blob: 29e4f59e695c3d7161753e2e8a90bc8a6d2f52ff [file] [log] [blame]
Ben Menchaca84f36632014-02-28 20:57:38 +00001/*
2 **************************************************************************
Murat Sezgin3aea6c92015-11-13 13:14:12 -08003 * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
Ben Menchaca84f36632014-02-28 20:57:38 +00004 * 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
Murat Sezginb3731e82014-11-26 12:20:59 -080017#include <linux/version.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000018#include <linux/types.h>
19#include <linux/ip.h>
20#include <linux/tcp.h>
21#include <linux/module.h>
22#include <linux/skbuff.h>
23#include <linux/icmp.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000024#include <linux/kthread.h>
Murat Sezgin908ecb32015-05-10 20:54:36 -070025#include <linux/debugfs.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000026#include <linux/pkt_sched.h>
27#include <linux/string.h>
Gareth Williams54d15d92015-04-24 19:28:27 +010028#include <linux/random.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000029#include <net/route.h>
30#include <net/ip.h>
31#include <net/tcp.h>
32#include <asm/unaligned.h>
33#include <asm/uaccess.h> /* for put_user */
34#include <net/ipv6.h>
Murat Sezgin1134fb82015-10-06 14:03:49 -070035#include <net/ip6_route.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000036#include <linux/inet.h>
37#include <linux/in.h>
38#include <linux/udp.h>
39#include <linux/tcp.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000040#include <linux/netfilter_ipv4.h>
41#include <linux/netfilter_bridge.h>
42#include <net/netfilter/nf_conntrack.h>
43#include <net/netfilter/nf_conntrack_helper.h>
44#include <net/netfilter/nf_conntrack_l4proto.h>
45#include <net/netfilter/nf_conntrack_l3proto.h>
46#include <net/netfilter/nf_conntrack_core.h>
47#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
48#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
49
50/*
51 * Debug output levels
52 * 0 = OFF
53 * 1 = ASSERTS / ERRORS
54 * 2 = 1 + WARN
55 * 3 = 2 + INFO
56 * 4 = 3 + TRACE
57 */
58#define DEBUG_LEVEL ECM_DB_DEBUG_LEVEL
59
Ben Menchaca84f36632014-02-28 20:57:38 +000060#include "ecm_types.h"
61#include "ecm_db_types.h"
Gareth Williamsd5618a82015-05-20 11:13:32 +010062#include "ecm_state.h"
Ben Menchaca84f36632014-02-28 20:57:38 +000063#include "ecm_tracker.h"
64#include "ecm_classifier.h"
65#include "ecm_front_end_types.h"
66#include "ecm_classifier_default.h"
67#include "ecm_db.h"
68
69/*
70 * Magic numbers
71 */
72#define ECM_DB_CONNECTION_INSTANCE_MAGIC 0xff23
73#define ECM_DB_HOST_INSTANCE_MAGIC 0x2873
74#define ECM_DB_MAPPING_INSTANCE_MAGIC 0x8765
75#define ECM_DB_LISTENER_INSTANCE_MAGIC 0x9876
76#define ECM_DB_NODE_INSTANCE_MAGIC 0x3312
77#define ECM_DB_IFACE_INSTANCE_MAGIC 0xAEF1
Gareth Williamsb39e7c22015-03-25 10:15:33 +000078#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +010079#define ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC 0xAEF4
Gareth Williamsb39e7c22015-03-25 10:15:33 +000080#endif
Shyam Sunder1f037262015-05-18 20:04:13 +053081#ifdef ECM_MULTICAST_ENABLE
82#define ECM_DB_MULTICAST_INSTANCE_MAGIC 0xc34a
83#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000084
85/*
86 * Global lists.
87 * All instances are inserted into global list - this allows easy iteration of all instances of a particular type.
88 * The list is doubly linked for fast removal. The list is in no particular order.
89 */
90struct ecm_db_connection_instance *ecm_db_connections = NULL;
91struct ecm_db_mapping_instance *ecm_db_mappings = NULL;
92struct ecm_db_host_instance *ecm_db_hosts = NULL;
93struct ecm_db_node_instance *ecm_db_nodes = NULL;
94struct ecm_db_iface_instance *ecm_db_interfaces = NULL;
95
96/*
97 * Connection hash table
98 */
99#define ECM_DB_CONNECTION_HASH_SLOTS 32768
Murat Sezgina89f7c02016-10-19 11:06:56 -0700100static struct ecm_db_connection_instance **ecm_db_connection_table;
Ben Menchaca84f36632014-02-28 20:57:38 +0000101 /* Slots of the connection hash table */
Murat Sezgina89f7c02016-10-19 11:06:56 -0700102static int *ecm_db_connection_table_lengths;
Ben Menchaca84f36632014-02-28 20:57:38 +0000103 /* Tracks how long each chain is */
104static int ecm_db_connection_count = 0; /* Number of connections allocated */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100105static int ecm_db_connection_serial = 0; /* Serial number - ensures each connection has a unique serial number.
Ben Menchaca84f36632014-02-28 20:57:38 +0000106 * Serial numbers are used mainly by classifiers that keep their own state
107 * and can 'link' their state to the right connection using a serial number.
Ben Menchaca84f36632014-02-28 20:57:38 +0000108 * The serial number is also used as a soft linkage to other subsystems such as NA.
109 */
110typedef uint32_t ecm_db_connection_hash_t;
111
112/*
113 * Connection serial number hash table
114 */
115#define ECM_DB_CONNECTION_SERIAL_HASH_SLOTS 32768
Murat Sezgina89f7c02016-10-19 11:06:56 -0700116static struct ecm_db_connection_instance **ecm_db_connection_serial_table;
Ben Menchaca84f36632014-02-28 20:57:38 +0000117 /* Slots of the connection serial hash table */
Murat Sezgina89f7c02016-10-19 11:06:56 -0700118static int *ecm_db_connection_serial_table_lengths;
Ben Menchaca84f36632014-02-28 20:57:38 +0000119 /* Tracks how long each chain is */
120typedef uint32_t ecm_db_connection_serial_hash_t;
121
122/*
123 * Mapping hash table
124 */
125#define ECM_DB_MAPPING_HASH_SLOTS 32768
Murat Sezgina89f7c02016-10-19 11:06:56 -0700126static struct ecm_db_mapping_instance **ecm_db_mapping_table;
Ben Menchaca84f36632014-02-28 20:57:38 +0000127 /* Slots of the mapping hash table */
Murat Sezgina89f7c02016-10-19 11:06:56 -0700128static int *ecm_db_mapping_table_lengths;
Ben Menchaca84f36632014-02-28 20:57:38 +0000129 /* Tracks how long each chain is */
130static int ecm_db_mapping_count = 0; /* Number of mappings allocated */
131typedef uint32_t ecm_db_mapping_hash_t;
132
133/*
134 * Host hash table
135 */
136#define ECM_DB_HOST_HASH_SLOTS 32768
Murat Sezgina89f7c02016-10-19 11:06:56 -0700137static struct ecm_db_host_instance **ecm_db_host_table;
Ben Menchaca84f36632014-02-28 20:57:38 +0000138 /* Slots of the host hash table */
Murat Sezgina89f7c02016-10-19 11:06:56 -0700139static int *ecm_db_host_table_lengths;
Ben Menchaca84f36632014-02-28 20:57:38 +0000140 /* Tracks how long each chain is */
141static int ecm_db_host_count = 0; /* Number of hosts allocated */
142typedef uint32_t ecm_db_host_hash_t;
143
144/*
145 * Node hash table
146 */
147#define ECM_DB_NODE_HASH_SLOTS 32768
Murat Sezgina89f7c02016-10-19 11:06:56 -0700148static struct ecm_db_node_instance **ecm_db_node_table;
Ben Menchaca84f36632014-02-28 20:57:38 +0000149 /* Slots of the node hash table */
Murat Sezgina89f7c02016-10-19 11:06:56 -0700150static int *ecm_db_node_table_lengths;
Ben Menchaca84f36632014-02-28 20:57:38 +0000151 /* Tracks how long each chain is */
152static int ecm_db_node_count = 0; /* Number of nodes allocated */
153typedef uint32_t ecm_db_node_hash_t;
154
155/*
156 * Interface hash table
157 */
158#define ECM_DB_IFACE_HASH_SLOTS 8
159static struct ecm_db_iface_instance *ecm_db_iface_table[ECM_DB_IFACE_HASH_SLOTS];
160 /* Slots of the interface hash table */
161static int ecm_db_iface_table_lengths[ECM_DB_IFACE_HASH_SLOTS];
162 /* Tracks how long each chain is */
163static int ecm_db_iface_count = 0; /* Number of interfaces allocated */
164typedef uint32_t ecm_db_iface_hash_t;
165
Murat Sezgin91c5d712015-06-12 15:16:22 -0700166#define ECM_DB_IFACE_ID_HASH_SLOTS 8
167static struct ecm_db_iface_instance *ecm_db_iface_id_table[ECM_DB_IFACE_ID_HASH_SLOTS];
168 /* Slots of the interface id hash table */
169static int ecm_db_iface_id_table_lengths[ECM_DB_IFACE_ID_HASH_SLOTS];
170 /* Tracks how long each chain is */
171typedef uint32_t ecm_db_iface_id_hash_t;
172
Ben Menchaca84f36632014-02-28 20:57:38 +0000173/*
174 * Listeners
175 */
176static int ecm_db_listeners_count = 0; /* Number of listeners allocated */
177static struct ecm_db_listener_instance *ecm_db_listeners = NULL;
178 /* Event listeners */
179
Gareth Williamsf98d4192015-03-11 16:55:41 +0000180#ifdef ECM_STATE_OUTPUT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000181/*
Gareth Williamsd5618a82015-05-20 11:13:32 +0100182 * ecm_db_iface_state_get_method_t
183 * Used to obtain interface state
Ben Menchaca84f36632014-02-28 20:57:38 +0000184 */
Gareth Williamsd5618a82015-05-20 11:13:32 +0100185typedef int (*ecm_db_iface_state_get_method_t)(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +0000186#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000187
188/*
189 * struct ecm_db_iface_instance
190 */
191struct ecm_db_iface_instance {
192 struct ecm_db_iface_instance *next; /* Next instance in global list */
193 struct ecm_db_iface_instance *prev; /* Previous instance in global list */
194 struct ecm_db_iface_instance *hash_next; /* Next Interface in the chain of Interfaces */
195 struct ecm_db_iface_instance *hash_prev; /* previous Interface in the chain of Interfaces */
196 ecm_db_iface_type_t type; /* RO: Type of interface */
Ben Menchaca84f36632014-02-28 20:57:38 +0000197 uint32_t time_added; /* RO: DB time stamp when the Interface was added into the database */
198
199 int32_t interface_identifier; /* RO: The operating system dependent identifier of this interface */
Murat Sezgin91c5d712015-06-12 15:16:22 -0700200 int32_t ae_interface_identifier; /* RO: The accel engine identifier of this interface */
Ben Menchaca84f36632014-02-28 20:57:38 +0000201 char name[IFNAMSIZ]; /* Name of interface */
202 int32_t mtu; /* Interface MTU */
203
Murat Sezgin91c5d712015-06-12 15:16:22 -0700204 struct ecm_db_iface_instance *iface_id_hash_next; /* Next interface in the chain of interface id table */
205 struct ecm_db_iface_instance *iface_id_hash_prev; /* Previous interface in the chain of interface id table */
206 ecm_db_iface_id_hash_t iface_id_hash_index; /* Hash index value of chains */
207
Gareth Williams85331c92015-03-11 20:39:18 +0000208#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000209 uint64_t from_data_total; /* Total of data sent by this Interface */
210 uint64_t to_data_total; /* Total of data sent to this Interface */
211 uint64_t from_packet_total; /* Total of packets sent by this Interface */
212 uint64_t to_packet_total; /* Total of packets sent to this Interface */
213 uint64_t from_data_total_dropped;
214 uint64_t to_data_total_dropped;
215 uint64_t from_packet_total_dropped;
216 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000217#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000218
Gareth Williamsb5903892015-03-20 15:13:07 +0000219#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000220 /*
221 * For convenience interfaces keep lists of connections that have been established
222 * from them and to them.
223 * In fact the same connection could be listed as from & to on the same interface (think: WLAN<>WLAN AP function)
224 * Interfaces keep this information for rapid iteration of connections e.g. when an interface 'goes down' we
Murat Sezgin91c5d712015-06-12 15:16:22 -0700225 * can defunct all associated connections or destroy any accel engine rules.
Ben Menchaca84f36632014-02-28 20:57:38 +0000226 */
227 struct ecm_db_connection_instance *from_connections; /* list of connections made from this interface */
228 struct ecm_db_connection_instance *to_connections; /* list of connections made to this interface */
229
230 struct ecm_db_connection_instance *from_nat_connections; /* list of NAT connections made from this interface */
231 struct ecm_db_connection_instance *to_nat_connections; /* list of NAT connections made to this interface */
232
233 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000234 * Normally only the node refers to the interfaces which it is reachable upon.
235 * The interface also keeps a list of all nodes that can be reached.
236 */
237 struct ecm_db_node_instance *nodes; /* Nodes associated with this Interface */
238 int node_count; /* Number of Nodes in the nodes list */
239#endif
240
241 /*
Ben Menchaca84f36632014-02-28 20:57:38 +0000242 * Interface specific information.
243 * type identifies which information is applicable.
244 */
245 union {
246 struct ecm_db_interface_info_ethernet ethernet; /* type == ECM_DB_IFACE_TYPE_ETHERNET */
Murat Sezgin37fb3952015-03-10 16:45:13 -0700247#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000248 struct ecm_db_interface_info_vlan vlan; /* type == ECM_DB_IFACE_TYPE_VLAN */
Murat Sezgin37fb3952015-03-10 16:45:13 -0700249#endif
Murat Sezgin910c9662015-03-11 16:15:06 -0700250#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000251 struct ecm_db_interface_info_lag lag; /* type == ECM_DB_IFACE_TYPE_LAG */
Murat Sezgin910c9662015-03-11 16:15:06 -0700252#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000253 struct ecm_db_interface_info_bridge bridge; /* type == ECM_DB_IFACE_TYPE_BRIDGE */
ratheesh kannotha32fdd12015-09-09 08:02:58 +0530254#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000255 struct ecm_db_interface_info_pppoe pppoe; /* type == ECM_DB_IFACE_TYPE_PPPOE */
Murat Sezginaad635c2015-03-06 16:11:41 -0800256#endif
ratheesh kannotha32fdd12015-09-09 08:02:58 +0530257#ifdef ECM_INTERFACE_L2TPV2_ENABLE
258 struct ecm_db_interface_info_pppol2tpv2 pppol2tpv2; /* type == ECM_DB_IFACE_TYPE_PPPOL2TPV2 */
259#endif
Shyam Sunder23f2e542015-09-28 14:56:49 +0530260#ifdef ECM_INTERFACE_PPTP_ENABLE
261 struct ecm_db_interface_info_pptp pptp; /* type == ECM_DB_IFACE_TYPE_PPTP */
262#endif
ratheesh kannothcfdcb332015-12-24 07:19:18 +0530263#ifdef ECM_INTERFACE_MAP_T_ENABLE
264 struct ecm_db_interface_info_map_t map_t; /* type == ECM_DB_IFACE_TYPE_MAP_T */
265#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000266 struct ecm_db_interface_info_unknown unknown; /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
267 struct ecm_db_interface_info_loopback loopback; /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
Murat Sezgin69a27532015-03-12 14:09:40 -0700268#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000269 struct ecm_db_interface_info_ipsec_tunnel ipsec_tunnel; /* type == ECM_DB_IFACE_TYPE_IPSEC_TUNNEL */
Murat Sezgin69a27532015-03-12 14:09:40 -0700270#endif
Murat Sezginbde55f92015-03-11 16:44:11 -0700271#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000272 struct ecm_db_interface_info_sit sit; /* type == ECM_DB_IFACE_TYPE_SIT (6-in-4) */
Murat Sezginbde55f92015-03-11 16:44:11 -0700273#endif
Murat Sezginc1402562015-03-12 12:32:20 -0700274#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +0000275#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000276 struct ecm_db_interface_info_tunipip6 tunipip6; /* type == ECM_DB_IFACE_TYPE_TUNIPIP6 (IPIP v6 Tunnel i.e. TUNNEL6) */
Murat Sezginc1402562015-03-12 12:32:20 -0700277#endif
Gareth Williams8ac34292015-03-17 14:06:58 +0000278#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000279 } type_info;
280
Gareth Williamsf98d4192015-03-11 16:55:41 +0000281#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +0100282 ecm_db_iface_state_get_method_t state_get; /* Type specific method to return state */
Gareth Williamsf98d4192015-03-11 16:55:41 +0000283#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000284
285 ecm_db_iface_final_callback_t final; /* Callback to owner when object is destroyed */
286 void *arg; /* Argument returned to owner in callbacks */
287 uint32_t flags;
288 int refs; /* Integer to trap we never go negative */
289 ecm_db_iface_hash_t hash_index;
290#if (DEBUG_LEVEL > 0)
291 uint16_t magic;
292#endif
293};
294
295/*
296 * Interface flags
297 */
298#define ECM_DB_IFACE_FLAGS_INSERTED 1 /* Interface is inserted into connection database tables */
299
300/*
301 * struct ecm_db_node_instance
302 */
303struct ecm_db_node_instance {
304 struct ecm_db_node_instance *next; /* Next instance in global list */
305 struct ecm_db_node_instance *prev; /* Previous instance in global list */
Gareth Williams90f2a282014-08-27 15:56:25 +0100306 struct ecm_db_node_instance *hash_next; /* Next node in the chain of nodes */
307 struct ecm_db_node_instance *hash_prev; /* previous node in the chain of nodes */
Ben Menchaca84f36632014-02-28 20:57:38 +0000308 uint8_t address[ETH_ALEN]; /* RO: MAC Address of this node */
Gareth Williams90f2a282014-08-27 15:56:25 +0100309
Gareth Williamsb5903892015-03-20 15:13:07 +0000310#ifdef ECM_DB_XREF_ENABLE
Gareth Williams90f2a282014-08-27 15:56:25 +0100311 /*
312 * For convenience nodes keep lists of connections that have been established from them and to them.
313 * In fact the same connection could be listed as from & to on the same interface (think: WLAN<>WLAN AP function)
314 * Nodes keep this information for rapid iteration of connections e.g. when a node 'goes down' we
Murat Sezgin91c5d712015-06-12 15:16:22 -0700315 * can defunct all associated connections or destroy any accel engine rules.
Gareth Williams90f2a282014-08-27 15:56:25 +0100316 */
317 struct ecm_db_connection_instance *from_connections; /* list of connections made from this node */
318 struct ecm_db_connection_instance *to_connections; /* list of connections made to this node */
319 int from_connections_count; /* Number of connections in the from_connections list */
320 int to_connections_count; /* Number of connections in the to_connections list */
321
322 struct ecm_db_connection_instance *from_nat_connections; /* list of NAT connections made from this node */
323 struct ecm_db_connection_instance *to_nat_connections; /* list of NAT connections made to this node */
324 int from_nat_connections_count; /* Number of connections in the from_nat_connections list */
325 int to_nat_connections_count; /* Number of connections in the to_nat_connections list */
326
Gareth Williamsb5903892015-03-20 15:13:07 +0000327 /*
328 * Nodes reachable from an interface are stored in a linked list maintained by that interface.
329 * This is so, given an interface, you can examine all nodes reachable from it.
330 */
331 struct ecm_db_node_instance *node_next; /* The next node within the same iface nodes list */
332 struct ecm_db_node_instance *node_prev; /* The previous node within the same iface nodes list */
333#endif
334
Ben Menchaca84f36632014-02-28 20:57:38 +0000335 uint32_t time_added; /* RO: DB time stamp when the node was added into the database */
336
Gareth Williams85331c92015-03-11 20:39:18 +0000337#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000338 uint64_t from_data_total; /* Total of data sent by this node */
339 uint64_t to_data_total; /* Total of data sent to this node */
340 uint64_t from_packet_total; /* Total of packets sent by this node */
341 uint64_t to_packet_total; /* Total of packets sent to this node */
342 uint64_t from_data_total_dropped;
343 uint64_t to_data_total_dropped;
344 uint64_t from_packet_total_dropped;
345 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000346#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000347
348 struct ecm_db_iface_instance *iface; /* The interface to which this node relates */
Ben Menchaca84f36632014-02-28 20:57:38 +0000349
350 ecm_db_node_final_callback_t final; /* Callback to owner when object is destroyed */
351 void *arg; /* Argument returned to owner in callbacks */
352 uint8_t flags;
353 int refs; /* Integer to trap we never go negative */
354 ecm_db_node_hash_t hash_index;
355#if (DEBUG_LEVEL > 0)
356 uint16_t magic;
357#endif
358};
359
360/*
361 * Node flags
362 */
363#define ECM_DB_NODE_FLAGS_INSERTED 1 /* Node is inserted into connection database tables */
364
365/*
366 * struct ecm_db_host_instance
367 */
368struct ecm_db_host_instance {
369 struct ecm_db_host_instance *next; /* Next instance in global list */
370 struct ecm_db_host_instance *prev; /* Previous instance in global list */
371 struct ecm_db_host_instance *hash_next; /* Next host in the chain of hosts */
372 struct ecm_db_host_instance *hash_prev; /* previous host in the chain of hosts */
373 ip_addr_t address; /* RO: IPv4/v6 Address of this host */
374 bool on_link; /* RO: false when this host is reached via a gateway */
Gareth Williamsb5903892015-03-20 15:13:07 +0000375 uint32_t time_added; /* RO: DB time stamp when the host was added into the database */
376
377#ifdef ECM_DB_XREF_ENABLE
378 /*
379 * Normally the mapping refers to the host it requires.
380 * However the host also keeps a list of all mappings that are associated with it.
381 */
Ben Menchaca84f36632014-02-28 20:57:38 +0000382 struct ecm_db_mapping_instance *mappings; /* Mappings made on this host */
383 int mapping_count; /* Number of mappings in the mapping list */
Gareth Williamsb5903892015-03-20 15:13:07 +0000384#endif
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530385
Gareth Williams85331c92015-03-11 20:39:18 +0000386#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000387 uint64_t from_data_total; /* Total of data sent by this host */
388 uint64_t to_data_total; /* Total of data sent to this host */
389 uint64_t from_packet_total; /* Total of packets sent by this host */
390 uint64_t to_packet_total; /* Total of packets sent to this host */
391 uint64_t from_data_total_dropped;
392 uint64_t to_data_total_dropped;
393 uint64_t from_packet_total_dropped;
394 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000395#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000396
397 ecm_db_host_final_callback_t final; /* Callback to owner when object is destroyed */
398 void *arg; /* Argument returned to owner in callbacks */
399 uint32_t flags;
400 int refs; /* Integer to trap we never go negative */
401 ecm_db_host_hash_t hash_index;
402#if (DEBUG_LEVEL > 0)
403 uint16_t magic;
404#endif
405};
406
407/*
408 * Host flags
409 */
410#define ECM_DB_HOST_FLAGS_INSERTED 1 /* Host is inserted into connection database tables */
411
412/*
413 * struct ecm_db_mapping_instance
414 */
415struct ecm_db_mapping_instance {
416 struct ecm_db_mapping_instance *next; /* Next instance in global list */
417 struct ecm_db_mapping_instance *prev; /* Previous instance in global list */
418
419 struct ecm_db_mapping_instance *hash_next; /* Next mapping in the chain of mappings */
420 struct ecm_db_mapping_instance *hash_prev; /* previous mapping in the chain of mappings */
421
422 uint32_t time_added; /* RO: DB time stamp when the connection was added into the database */
423 struct ecm_db_host_instance *host; /* The host to which this mapping relates */
424 int port; /* RO: The port number on the host - only applicable for mapping protocols that are port based */
Ben Menchaca84f36632014-02-28 20:57:38 +0000425
Gareth Williamsb5903892015-03-20 15:13:07 +0000426#ifdef ECM_DB_XREF_ENABLE
427 /*
428 * For convenience mappings keep lists of connections that have been established from them and to them.
429 * In fact the same connection could be listed as from & to on the same interface (think: WLAN<>WLAN AP function)
430 * Mappings keep this information for rapid iteration of connections e.g. given a mapping we
Murat Sezgin91c5d712015-06-12 15:16:22 -0700431 * can defunct all associated connections or destroy any accel engine rules.
Gareth Williamsb5903892015-03-20 15:13:07 +0000432 */
Ben Menchaca84f36632014-02-28 20:57:38 +0000433 struct ecm_db_connection_instance *from_connections; /* list of connections made from this host mapping */
434 struct ecm_db_connection_instance *to_connections; /* list of connections made to this host mapping */
435
436 struct ecm_db_connection_instance *from_nat_connections; /* list of NAT connections made from this host mapping */
437 struct ecm_db_connection_instance *to_nat_connections; /* list of NAT connections made to this host mapping */
438
439 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000440 * While a mapping refers to the host it requires.
441 * The host also keeps a list of all mappings that are associated with it, this is that list linkage.
442 */
443 struct ecm_db_mapping_instance *mapping_next; /* Next mapping in the list of mappings for the host */
444 struct ecm_db_mapping_instance *mapping_prev; /* previous mapping in the list of mappings for the host */
445#endif
446
447 /*
Ben Menchaca84f36632014-02-28 20:57:38 +0000448 * Connection counts
449 */
450 int tcp_from;
451 int tcp_to;
452 int udp_from;
453 int udp_to;
454 int tcp_nat_from;
455 int tcp_nat_to;
456 int udp_nat_from;
457 int udp_nat_to;
458
459 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000460 * Connection counts
Ben Menchaca84f36632014-02-28 20:57:38 +0000461 */
Gareth Williamsb5903892015-03-20 15:13:07 +0000462 int from; /* Number of connections made from */
463 int to; /* Number of connections made to */
464 int nat_from; /* Number of connections made from (nat) */
465 int nat_to; /* Number of connections made to (nat) */
Ben Menchaca84f36632014-02-28 20:57:38 +0000466
Gareth Williams85331c92015-03-11 20:39:18 +0000467#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000468 /*
469 * Data totals
470 */
471 uint64_t from_data_total; /* Total of data sent by this mapping */
472 uint64_t to_data_total; /* Total of data sent to this mapping */
473 uint64_t from_packet_total; /* Total of packets sent by this mapping */
474 uint64_t to_packet_total; /* Total of packets sent to this mapping */
475 uint64_t from_data_total_dropped;
476 uint64_t to_data_total_dropped;
477 uint64_t from_packet_total_dropped;
478 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000479#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000480
481 ecm_db_mapping_final_callback_t final; /* Callback to owner when object is destroyed */
482 void *arg; /* Argument returned to owner in callbacks */
483 uint32_t flags;
484 int refs; /* Integer to trap we never go negative */
485 ecm_db_mapping_hash_t hash_index;
486#if (DEBUG_LEVEL > 0)
487 uint16_t magic;
488#endif
489};
490
491/*
492 * Mapping flags
493 */
494#define ECM_DB_MAPPING_FLAGS_INSERTED 1 /* Mapping is inserted into connection database tables */
495
496/*
497 * struct ecm_db_timer_group
498 * A timer group - all group members within the same group have the same TTL reset value.
499 *
500 * Expiry of entries occurs from tail to head.
501 */
502struct ecm_db_timer_group {
503 struct ecm_db_timer_group_entry *head; /* Most recently used entry in this timer group */
504 struct ecm_db_timer_group_entry *tail; /* Least recently used entry in this timer group. */
505 uint32_t time; /* Time in seconds a group entry will be given to live when 'touched' */
506 ecm_db_timer_group_t tg; /* RO: The group id */
507#if (DEBUG_LEVEL > 0)
508 uint16_t magic;
509#endif
510};
511
512/*
513 * Timers and cleanup
514 */
515static uint32_t ecm_db_time = 0; /* Time in seconds since start */
516static struct ecm_db_timer_group ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_MAX];
517 /* Timer groups */
518static struct timer_list ecm_db_timer; /* Timer to drive timer groups */
519
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000520#ifdef ECM_DB_CTA_TRACK_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000521/*
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000522 * Classifier TYPE assignment lists.
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100523 *
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000524 * For each type of classifier a list is kept of all connections assigned a classifier of that type.
525 * This permits a classifier type to rapidly retrieve all connections with classifiers assigned to it of that type.
526 *
527 * NOTE: This is in addition to the basic functionality whereby a connection keeps a list of classifier instances
528 * that are assigned to it in descending order of priority.
529 */
530
531/*
532 * struct ecm_db_connection_classifier_type_assignment
533 * List linkage
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100534 */
535struct ecm_db_connection_classifier_type_assignment {
536 struct ecm_db_connection_instance *next; /* Next connection assigned to a classifier of this type */
537 struct ecm_db_connection_instance *prev; /* Previous connection assigned to a classifier of this type */
538 int iteration_count; /* >0 if something is examining this list entry and it may not be unlinked. The connection will persist. */
539 bool pending_unassign; /* True when the connection has been unassigned from the type, when iteration_count drops to 0 it may be removed from the list */
540#if (DEBUG_LEVEL > 0)
541 uint16_t magic;
542#endif
543};
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000544
545/*
546 * struct ecm_db_connection_classifier_type_assignment_list
547 * A list, one for each classifier type.
548 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100549struct ecm_db_connection_classifier_type_assignment_list {
550 struct ecm_db_connection_instance *type_assignments_list;
551 /* Lists of connections assigned to this type of classifier */
552 int32_t type_assignment_count; /* Number of connections in the list */
553} ecm_db_connection_classifier_type_assignments[ECM_CLASSIFIER_TYPES];
554 /* Each classifier type has a list of connections that are assigned to classifier instances of that type */
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000555#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100556
557/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000558 * struct ecm_db_connection_instance
559 */
560struct ecm_db_connection_instance {
561 struct ecm_db_connection_instance *next; /* Next instance in global list */
562 struct ecm_db_connection_instance *prev; /* Previous instance in global list */
563
564 struct ecm_db_connection_instance *hash_next; /* Next connection in chain */
565 struct ecm_db_connection_instance *hash_prev; /* Previous connection in chain */
566 ecm_db_connection_hash_t hash_index; /* The hash table slot whose chain of connections this is inserted into */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530567
Ben Menchaca84f36632014-02-28 20:57:38 +0000568 struct ecm_db_connection_instance *serial_hash_next; /* Next connection in serial hash chain */
569 struct ecm_db_connection_instance *serial_hash_prev; /* Previous connection in serial hash chain */
570 ecm_db_connection_hash_t serial_hash_index; /* The hash table slot whose chain of connections this is inserted into */
571
572 uint32_t time_added; /* RO: DB time stamp when the connection was added into the database */
573
Gareth Williams3e5b37f2015-05-13 10:04:12 +0100574 int ip_version; /* RO: The version of IP protocol this connection was established for */
Ben Menchaca84f36632014-02-28 20:57:38 +0000575 int protocol; /* RO: Protocol of the connection */
576 ecm_db_direction_t direction; /* RO: 'Direction' of connection establishment. */
577 bool is_routed; /* RO: True when connection is routed, false when not */
578
579 /*
580 * Connection endpoint mapping
581 */
582 struct ecm_db_mapping_instance *mapping_from; /* The connection was established from this mapping */
583 struct ecm_db_mapping_instance *mapping_to; /* The connection was established to this mapping */
Ben Menchaca84f36632014-02-28 20:57:38 +0000584
585 /*
586 * Connection endpoint mapping for NAT purposes
587 * NOTE: For non-NAT connections these would be identical to the endpoint mappings.
588 */
589 struct ecm_db_mapping_instance *mapping_nat_from; /* The connection was established from this mapping */
590 struct ecm_db_mapping_instance *mapping_nat_to; /* The connection was established to this mapping */
Gareth Williamsb5903892015-03-20 15:13:07 +0000591
592 /*
593 * From / To Node (NAT and non-NAT).
594 * Connections keep references to the nodes upon which they operate.
595 * Gut feeling would tell us this is unusual since it should be the case that
596 * the HOST refer to the node, e.g. IP address to a MAC address.
597 * However there are some 'interesting' usage models where the same IP address may appear
598 * from different nodes / MAC addresses because of this the unique element here is the connection
599 * and so we record the node information directly here.
600 */
601 struct ecm_db_node_instance *from_node; /* Node from which this connection was established */
602 struct ecm_db_node_instance *to_node; /* Node to which this connection was established */
603 struct ecm_db_node_instance *from_nat_node; /* Node from which this connection was established */
604 struct ecm_db_node_instance *to_nat_node; /* Node to which this connection was established */
605
606#ifdef ECM_DB_XREF_ENABLE
607 /*
608 * The connection has references to the mappings (both nat and non-nat) as required above.
609 * Also mappings keep lists of connections made to/from them so that they may be iterated
610 * to determine associated connections in each direction/situation (e.g. "defuncting all connections made to/from a mapping").
611 */
612 struct ecm_db_connection_instance *from_next; /* Next connection made from the same mapping */
613 struct ecm_db_connection_instance *from_prev; /* Previous connection made from the same mapping */
614 struct ecm_db_connection_instance *to_next; /* Next connection made to the same mapping */
615 struct ecm_db_connection_instance *to_prev; /* Previous connection made to the same mapping */
616
Ben Menchaca84f36632014-02-28 20:57:38 +0000617 struct ecm_db_connection_instance *from_nat_next; /* Next connection made from the same mapping */
618 struct ecm_db_connection_instance *from_nat_prev; /* Previous connection made from the same mapping */
619 struct ecm_db_connection_instance *to_nat_next; /* Next connection made to the same mapping */
620 struct ecm_db_connection_instance *to_nat_prev; /* Previous connection made to the same mapping */
621
622 /*
623 * Connection endpoint interface
Gareth Williamsb5903892015-03-20 15:13:07 +0000624 * GGG TODO Deprecated - use interface lists instead.
625 * To be removed when interface heirarchies are implemented to provide the same functionality.
Ben Menchaca84f36632014-02-28 20:57:38 +0000626 */
627 struct ecm_db_connection_instance *iface_from_next; /* Next connection made from the same interface */
628 struct ecm_db_connection_instance *iface_from_prev; /* Previous connection made from the same interface */
629 struct ecm_db_connection_instance *iface_to_next; /* Next connection made to the same interface */
630 struct ecm_db_connection_instance *iface_to_prev; /* Previous connection made to the same interface */
631
632 /*
633 * Connection endpoint interface for NAT purposes
634 * NOTE: For non-NAT connections these would be identical to the endpoint interface.
Gareth Williamsb5903892015-03-20 15:13:07 +0000635 * GGG TODO Deprecated - use interface lists instead.
636 * To be removed when interface heirarchies are implemented to provide the same functionality.
Ben Menchaca84f36632014-02-28 20:57:38 +0000637 */
638 struct ecm_db_connection_instance *iface_from_nat_next; /* Next connection made from the same interface */
639 struct ecm_db_connection_instance *iface_from_nat_prev; /* Previous connection made from the same interface */
640 struct ecm_db_connection_instance *iface_to_nat_next; /* Next connection made to the same interface */
641 struct ecm_db_connection_instance *iface_to_nat_prev; /* Previous connection made to the same interface */
642
643 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000644 * As well as keeping a reference to the node which this connection uses the nodes
645 * also keep lists of connections made from/to them.
646 */
647 struct ecm_db_connection_instance *node_from_next; /* Next connection in the nodes from_connections list */
648 struct ecm_db_connection_instance *node_from_prev; /* Prev connection in the nodes from_connections list */
649 struct ecm_db_connection_instance *node_to_next; /* Next connection in the nodes to_connections list */
650 struct ecm_db_connection_instance *node_to_prev; /* Prev connection in the nodes to_connections list */
651
652 struct ecm_db_connection_instance *node_from_nat_next; /* Next connection in the nodes from_nat_connections list */
653 struct ecm_db_connection_instance *node_from_nat_prev; /* Prev connection in the nodes from_nat_connections list */
654 struct ecm_db_connection_instance *node_to_nat_next; /* Next connection in the nodes to_nat_connections list */
655 struct ecm_db_connection_instance *node_to_nat_prev; /* Prev connection in the nodes to_nat_connections list */
656#endif
657
658 /*
Ben Menchaca84f36632014-02-28 20:57:38 +0000659 * From / To interfaces list
660 */
661 struct ecm_db_iface_instance *from_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
662 /* The outermost to innnermost interface this connection is using in the from path.
663 * Relationships are recorded from [ECM_DB_IFACE_HEIRARCHY_MAX - 1] to [0]
664 */
665 int32_t from_interface_first; /* The index of the first interface in the list */
666 bool from_interface_set; /* True when a list has been set - even if there is NO list, it's still deliberately set that way. */
667 struct ecm_db_iface_instance *to_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
668 /* The outermost to innnermost interface this connection is using in the to path */
669 int32_t to_interface_first; /* The index of the first interface in the list */
670 bool to_interface_set; /* True when a list has been set - even if there is NO list, it's still deliberately set that way. */
671
672 /*
673 * From / To NAT interfaces list
Gareth Williams90f2a282014-08-27 15:56:25 +0100674 * GGG TODO Not sure if NAT interface lists are necessary or appropriate or practical.
675 * Needs to be assessed if it gives any clear benefit and possibly remove these if not.
Ben Menchaca84f36632014-02-28 20:57:38 +0000676 */
677 struct ecm_db_iface_instance *from_nat_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
678 /* The outermost to innnermost interface this connection is using in the from path.
679 * Relationships are recorded from [ECM_DB_IFACE_HEIRARCHY_MAX - 1] to [0]
680 */
681 int32_t from_nat_interface_first; /* The index of the first interface in the list */
682 bool from_nat_interface_set; /* True when a list has been set - even if there is NO list, it's still deliberately set that way. */
683 struct ecm_db_iface_instance *to_nat_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
684 /* The outermost to innnermost interface this connection is using in the to path */
685 int32_t to_nat_interface_first; /* The index of the first interface in the list */
686 bool to_nat_interface_set; /* True when a list has been set - even if there is NO list, it's still deliberately set that way. */
687
Shyam Sunder1f037262015-05-18 20:04:13 +0530688#ifdef ECM_MULTICAST_ENABLE
689 /*
690 * Destination Multicast interfaces list
691 */
Shyam Sunderbf40d0e2015-06-23 15:56:37 +0530692 struct ecm_db_iface_instance *to_mcast_interfaces;
693 /* The outermost to innnermost interfaces this connection is using in multicast path.
694 * The size of the buffer allocated for the to_mcast_interfaces heirarchies is as large as
695 * sizeof(struct ecm_db_iface_instance *) * ECM_DB_MULTICAST_IF_MAX * ECM_DB_IFACE_HEIRARCHY_MAX. */
Shyam Sunder1f037262015-05-18 20:04:13 +0530696 int32_t to_mcast_interface_first[ECM_DB_MULTICAST_IF_MAX];
697 /* The indexes of the first interfaces in the destinaiton interface list */
698 struct ecm_db_multicast_tuple_instance *ti; /* Multicast Connection instance */
699 bool to_mcast_interfaces_set; /* Flag to indicate if the destination interface list is currently empty or not */
700#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000701 /*
702 * Time values in seconds
703 */
704 struct ecm_db_timer_group_entry defunct_timer; /* Used to defunct the connection on inactivity */
705
706 /*
707 * Byte and packet counts
708 */
709 uint64_t from_data_total; /* Totals of data as sent by the 'from' side of this connection */
710 uint64_t to_data_total; /* Totals of data as sent by the 'to' side of this connection */
711 uint64_t from_packet_total; /* Totals of packets as sent by the 'from' side of this connection */
712 uint64_t to_packet_total; /* Totals of packets as sent by the 'to' side of this connection */
713 uint64_t from_data_total_dropped; /* Total data sent by the 'from' side that we purposely dropped - the 'to' side has not seen this data */
714 uint64_t to_data_total_dropped; /* Total data sent by the 'to' side that we purposely dropped - the 'from' side has not seen this data */
715 uint64_t from_packet_total_dropped; /* Total packets sent by the 'from' side that we purposely dropped - the 'to' side has not seen this data */
716 uint64_t to_packet_total_dropped; /* Total packets sent by the 'to' side that we purposely dropped - the 'from' side has not seen this data */
717
718 /*
719 * Classifiers attached to this connection
720 */
Ben Menchaca84f36632014-02-28 20:57:38 +0000721 struct ecm_classifier_instance *assignments; /* A list of all classifiers that are still assigned to this connection.
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000722 * When a connection is created, one instance of every type of classifier is assigned to the connection.
Ben Menchaca84f36632014-02-28 20:57:38 +0000723 * Classifiers are added in ascending order of priority - so the most important processes a packet last.
724 * Classifiers may drop out of this list (become unassigned) at any time.
725 */
726 struct ecm_classifier_instance *assignments_by_type[ECM_CLASSIFIER_TYPES];
727 /* All assignments are also recorded in this array, since there can be only one of each type, this array allows
728 * rapid retrieval of a classifier type, saving having to iterate the assignments list.
729 */
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000730
731#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100732 struct ecm_db_connection_classifier_type_assignment type_assignment[ECM_CLASSIFIER_TYPES];
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000733 /*
734 * Each classifier TYPE has a list of connections that are assigned to it.
735 * This permits a classifier TYPE to rapidly retrieve all connections associated with it.
736 */
737#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100738
Tushar Mathurd38cacd2015-07-28 12:19:10 +0530739 /*
740 * Re-generation.
741 * When system or classifier state changes, affected connections may need to have their state re-generated.
742 * This ensures that a connection does not continue to operate on stale state which could affect the sanity of acceleration rules.
743 * A connection needs to be re-generated when its regen_required is > 0.
744 * When a re-generation is completed successfully the counter is decremented.
745 * The counter ensures that any further changes of state while re-generation is under way is not missed.
746 * While a connection needs re-generation (regen_required > 0), acceleration should not be permitted.
747 * It may not always be practical to flag individual connections for re-generation (time consuming with large numbers of connections).
748 * The "generation" is a numerical counter comparison against the global "ecm_db_connection_generation".
749 * This ecm_db_connection_generation can be incremented causing a numerical difference between the connections counter and this global.
750 * This is enough to flag that a re-generation is needed.
751 * Further, it is possible that re-generation may be required DURING a rule construction. Since constructing a rule
752 * can require lengthy non-atomic processes there needs to be a way to ensure that changes during construction of a rule are caught.
753 * The regen_occurances is a counter that is incremented whenever regen_required is also incremented.
754 * However it is never decremented. This permits the caller to obtain this count before a non-atomic procedure and then afterwards.
755 * If there is any change in the counter value there is a change of generation! And the operation should be aborted.
756 */
757 bool regen_in_progress; /* The connection is under regeneration right now and is used to provide atomic re-generation in SMP */
758 uint16_t regen_required; /* The connection needs to be re-generated when > 0 */
759 uint16_t regen_occurances; /* Total number of regens required */
760 uint16_t generation; /* Used to detect when a re-evaluation of this connection is necessary by comparing with ecm_db_connection_generation */
761 uint32_t regen_success; /* Tracks how many times re-generation was successfully completed */
762 uint32_t regen_fail; /* Tracks how many times re-generation failed */
763
Ben Menchaca84f36632014-02-28 20:57:38 +0000764 struct ecm_front_end_connection_instance *feci; /* Front end instance specific to this connection */
765
Murat Sezgin7f6cdf62014-09-11 13:41:06 -0700766 ecm_db_connection_defunct_callback_t defunct; /* Callback to be called when connection has become defunct */
Ben Menchaca84f36632014-02-28 20:57:38 +0000767 ecm_db_connection_final_callback_t final; /* Callback to owner when object is destroyed */
768 void *arg; /* Argument returned to owner in callbacks */
769
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100770 uint32_t serial; /* RO: Serial number for the connection - unique for run lifetime */
Ben Menchaca84f36632014-02-28 20:57:38 +0000771 uint32_t flags;
772 int refs; /* Integer to trap we never go negative */
773#if (DEBUG_LEVEL > 0)
774 uint16_t magic;
775#endif
776};
777
778/*
779 * Connection flags
780 */
781#define ECM_DB_CONNECTION_FLAGS_INSERTED 1 /* Connection is inserted into connection database tables */
782
783/*
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530784 * struct ecm_db_listener_instance
Ben Menchaca84f36632014-02-28 20:57:38 +0000785 * listener instances
786 */
787struct ecm_db_listener_instance {
788 struct ecm_db_listener_instance *next;
789 struct ecm_db_listener_instance *event_next;
790 uint32_t flags;
791 void *arg;
792 int refs; /* Integer to trap we never go negative */
793 ecm_db_mapping_final_callback_t final; /* Final callback for this instance */
794
795 ecm_db_iface_listener_added_callback_t iface_added;
796 ecm_db_iface_listener_removed_callback_t iface_removed;
797 ecm_db_node_listener_added_callback_t node_added;
798 ecm_db_node_listener_removed_callback_t node_removed;
799 ecm_db_host_listener_added_callback_t host_added;
800 ecm_db_host_listener_removed_callback_t host_removed;
801 ecm_db_mapping_listener_added_callback_t mapping_added;
802 ecm_db_mapping_listener_removed_callback_t mapping_removed;
803 ecm_db_connection_listener_added_callback_t connection_added;
804 ecm_db_connection_listener_removed_callback_t connection_removed;
805#if (DEBUG_LEVEL > 0)
806 uint16_t magic;
807#endif
808};
809
810/*
811 * Listener flags
812 */
Gareth Williamsb5903892015-03-20 15:13:07 +0000813#define ECM_DB_LISTENER_FLAGS_INSERTED 1 /* Is inserted into database */
Ben Menchaca84f36632014-02-28 20:57:38 +0000814
Shyam Sunder1f037262015-05-18 20:04:13 +0530815#ifdef ECM_MULTICAST_ENABLE
816/*
817 * struct ecm_db_multicast_tuple_instance
818 * Tuple information for an accelerated multicast connection.
819 * This tuple information is further used to find an attached
820 * connection for the multicast flow.
821 */
822struct ecm_db_multicast_tuple_instance {
823 struct ecm_db_multicast_tuple_instance *next; /* Next instance in global list */
824 struct ecm_db_multicast_tuple_instance *prev; /* Previous instance in global list */
Shyam Sunder3af86a52015-08-28 18:04:10 +0530825 struct ecm_db_connection_instance *ci; /* Pointer to the DB Connection Instance */
Shyam Sunder1f037262015-05-18 20:04:13 +0530826 uint16_t src_port; /* RO: IPv4/v6 Source Port */
827 uint16_t dst_port; /* RO: IPv4/v6 Destination Port */
828 ip_addr_t src_ip; /* RO: IPv4/v6 Source Address */
829 ip_addr_t grp_ip; /* RO: IPv4/v6 Multicast Group Address */
830 uint32_t flags; /* Flags for this instance node */
831 uint32_t hash_index; /* Hash index of this node */
832 int proto; /* RO: Protocol */
833 int refs; /* Integer to trap we never go negative */
834#if (DEBUG_LEVEL > 0)
835 uint16_t magic; /* Magic value for debug */
836#endif
837};
838
839#define ECM_DB_MULTICAST_TUPLE_INSTANCE_HASH_SLOTS 16
840typedef uint32_t ecm_db_multicast_tuple_instance_hash_t;
841
842/*
843 * Multicast connection tuple table
844 * This table is used to lookup a complete tuple for multicast connections
845 * using the multicast group address
846 */
847static struct ecm_db_multicast_tuple_instance *ecm_db_multicast_tuple_instance_table[ECM_DB_MULTICAST_TUPLE_INSTANCE_HASH_SLOTS];
848#endif
849
Ben Menchaca84f36632014-02-28 20:57:38 +0000850/*
851 * Simple stats
852 */
Gareth Williamsf98d4192015-03-11 16:55:41 +0000853#define ECM_DB_PROTOCOL_COUNT 256
854static int ecm_db_connection_count_by_protocol[ECM_DB_PROTOCOL_COUNT]; /* Each IP protocol has its own count */
Ben Menchaca84f36632014-02-28 20:57:38 +0000855
856/*
857 * Locking of the database - concurrency control
858 */
Murat Sezgin908ecb32015-05-10 20:54:36 -0700859static DEFINE_SPINLOCK(ecm_db_lock); /* Protect the table from SMP access. */
Ben Menchaca84f36632014-02-28 20:57:38 +0000860
861/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +0530862 * Connection state validity
863 * This counter is incremented whenever a general change is detected which requires re-generation of state for ALL connections.
Ben Menchaca84f36632014-02-28 20:57:38 +0000864 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +0530865static uint16_t ecm_db_connection_generation = 0; /* Generation counter to detect when all connection state is considered stale and all must be re-generated */
Ben Menchaca84f36632014-02-28 20:57:38 +0000866
867/*
Murat Sezgin908ecb32015-05-10 20:54:36 -0700868 * Debugfs dentry object.
Ben Menchaca84f36632014-02-28 20:57:38 +0000869 */
Murat Sezgin908ecb32015-05-10 20:54:36 -0700870static struct dentry *ecm_db_dentry;
Ben Menchaca84f36632014-02-28 20:57:38 +0000871
872/*
873 * Management thread control
874 */
875static bool ecm_db_terminate_pending = false; /* When true the user has requested termination */
Ben Menchaca84f36632014-02-28 20:57:38 +0000876
877/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000878 * ecm_db_interface_type_names[]
879 * Array that maps the interface type to a string
880 */
881static char *ecm_db_interface_type_names[ECM_DB_IFACE_TYPE_COUNT] = {
882 "ETHERNET",
883 "PPPoE",
884 "LINK-AGGREGATION",
885 "VLAN",
886 "BRIDGE",
887 "LOOPBACK",
888 "IPSEC_TUNNEL",
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530889 "UNKNOWN",
Murat Sezginb3cc8792014-06-06 19:16:51 -0700890 "SIT",
891 "TUNIPIP6",
Shyam Sunder23f2e542015-09-28 14:56:49 +0530892 "PPPoL2TPV2",
893 "PPTP"
Ben Menchaca84f36632014-02-28 20:57:38 +0000894};
895
896/*
Gareth Williams54d15d92015-04-24 19:28:27 +0100897 * Random seed used during hash calculations
898 */
899static uint32_t ecm_db_jhash_rnd __read_mostly;
900
901/*
Gareth Williamsf28ba5f2015-02-13 11:07:28 +0000902 * ecm_db_connection_count_get()
903 * Return the connection count
904 */
905int ecm_db_connection_count_get(void)
906{
907 int count;
908
909 spin_lock_bh(&ecm_db_lock);
910 count = ecm_db_connection_count;
911 spin_unlock_bh(&ecm_db_lock);
912 return count;
913}
914EXPORT_SYMBOL(ecm_db_connection_count_get);
915
916/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000917 * ecm_db_interface_type_to_string()
918 * Return a string buffer containing the type name of the interface
919 */
920char *ecm_db_interface_type_to_string(ecm_db_iface_type_t type)
921{
922 DEBUG_ASSERT((type >= 0) && (type < ECM_DB_IFACE_TYPE_COUNT), "Invalid type: %d\n", type);
923 return ecm_db_interface_type_names[(int)type];
924}
925EXPORT_SYMBOL(ecm_db_interface_type_to_string);
926
927/*
Gareth Williamsf98d4192015-03-11 16:55:41 +0000928 * ecm_db_connection_count_by_protocol_get()
929 * Return # connections for the given protocol
930 */
931int ecm_db_connection_count_by_protocol_get(int protocol)
932{
933 int count;
934
935 DEBUG_ASSERT((protocol >= 0) && (protocol < ECM_DB_PROTOCOL_COUNT), "Bad protocol: %d\n", protocol);
936 spin_lock_bh(&ecm_db_lock);
937 count = ecm_db_connection_count_by_protocol[protocol];
938 spin_unlock_bh(&ecm_db_lock);
939 return count;
940}
941EXPORT_SYMBOL(ecm_db_connection_count_by_protocol_get);
942
943/*
Murat Sezgin91c5d712015-06-12 15:16:22 -0700944 * ecm_db_iface_ae_interface_identifier_get()
945 * Return the accel engine interface number of this ecm interface
Ben Menchaca84f36632014-02-28 20:57:38 +0000946 */
Murat Sezgin91c5d712015-06-12 15:16:22 -0700947int32_t ecm_db_iface_ae_interface_identifier_get(struct ecm_db_iface_instance *ii)
Ben Menchaca84f36632014-02-28 20:57:38 +0000948{
949 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
Murat Sezgin91c5d712015-06-12 15:16:22 -0700950 return ii->ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +0000951}
Murat Sezgin91c5d712015-06-12 15:16:22 -0700952EXPORT_SYMBOL(ecm_db_iface_ae_interface_identifier_get);
Ben Menchaca84f36632014-02-28 20:57:38 +0000953
954/*
Murat Sezgin5f2947a2016-06-28 12:09:33 -0700955 * ecm_db_iface_ae_interface_identifier_set()
956 * Sets accel engine interface number of this ecm interface
957 */
958void ecm_db_iface_ae_interface_identifier_set(struct ecm_db_iface_instance *ii, uint32_t num)
959{
960 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
961 ii->ae_interface_identifier = num;
962}
963EXPORT_SYMBOL(ecm_db_iface_ae_interface_identifier_set);
964
965/*
Kiran Kumar C. S. K451b62e2014-05-19 20:34:06 +0530966 * ecm_db_iface_interface_identifier_get()
967 * Return the interface number of this ecm interface
968 */
969int32_t ecm_db_iface_interface_identifier_get(struct ecm_db_iface_instance *ii)
970{
971 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
972 return ii->interface_identifier;
973}
974EXPORT_SYMBOL(ecm_db_iface_interface_identifier_get);
975
976/*
Murat Sezgin3aea6c92015-11-13 13:14:12 -0800977 * ecm_db_iface_interface_name_get()
978 * Return the interface name of this ecm interface
979 *
980 * name_buffer should be at least of size IFNAMSIZ
981 */
982void ecm_db_iface_interface_name_get(struct ecm_db_iface_instance *ii, char *name_buffer)
983{
984 DEBUG_CHECK_MAGIC(ii,
985 ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
986 strlcpy(name_buffer, ii->name, IFNAMSIZ);
987}
988EXPORT_SYMBOL(ecm_db_iface_interface_name_get);
989
990/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000991 * ecm_db_iface_mtu_reset()
992 * Reset the mtu
993 */
994int32_t ecm_db_iface_mtu_reset(struct ecm_db_iface_instance *ii, int32_t mtu)
995{
996 int32_t mtu_old;
997 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
998 spin_lock_bh(&ecm_db_lock);
999 mtu_old = ii->mtu;
1000 ii->mtu = mtu;
1001 spin_unlock_bh(&ecm_db_lock);
1002 DEBUG_INFO("%p: Mtu change from %d to %d\n", ii, mtu_old, mtu);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301003
Ben Menchaca84f36632014-02-28 20:57:38 +00001004 return mtu_old;
1005}
1006EXPORT_SYMBOL(ecm_db_iface_mtu_reset);
1007
1008/*
1009 * ecm_db_connection_front_end_get_and_ref()
1010 * Return ref to the front end instance of the connection
1011 */
1012struct ecm_front_end_connection_instance *ecm_db_connection_front_end_get_and_ref(struct ecm_db_connection_instance *ci)
1013{
1014 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1015 ci->feci->ref(ci->feci);
1016 return ci->feci;
1017}
1018EXPORT_SYMBOL(ecm_db_connection_front_end_get_and_ref);
1019
1020/*
1021 * ecm_db_connection_defunct_callback()
1022 * Invoked by the expiration of the defunct_timer contained in a connection instance
1023 */
1024static void ecm_db_connection_defunct_callback(void *arg)
1025{
1026 struct ecm_db_connection_instance *ci = (struct ecm_db_connection_instance *)arg;
1027 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1028
1029 DEBUG_INFO("%p: defunct timer expired\n", ci);
Gareth Williams2bfb0b82015-01-15 16:31:15 +00001030
1031 if (ci->defunct) {
1032 ci->defunct(ci->feci);
1033 }
1034
Ben Menchaca84f36632014-02-28 20:57:38 +00001035 ecm_db_connection_deref(ci);
1036}
1037
1038/*
1039 * ecm_db_connection_defunct_timer_reset()
1040 * Set/change the timer group associated with a connection. Returns false if the connection has become defunct and the new group cannot be set for that reason.
1041 */
1042bool ecm_db_connection_defunct_timer_reset(struct ecm_db_connection_instance *ci, ecm_db_timer_group_t tg)
1043{
1044 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1045 return ecm_db_timer_group_entry_reset(&ci->defunct_timer, tg);
1046}
1047EXPORT_SYMBOL(ecm_db_connection_defunct_timer_reset);
1048
1049/*
1050 * ecm_db_connection_defunct_timer_touch()
1051 * Update the connections defunct timer to stop it timing out. Returns false if the connection defunct timer has expired.
1052 */
1053bool ecm_db_connection_defunct_timer_touch(struct ecm_db_connection_instance *ci)
1054{
1055 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1056 return ecm_db_timer_group_entry_touch(&ci->defunct_timer);
1057}
1058EXPORT_SYMBOL(ecm_db_connection_defunct_timer_touch);
1059
1060/*
1061 * ecm_db_connection_timer_group_get()
1062 * Return the timer group id
1063 */
1064ecm_db_timer_group_t ecm_db_connection_timer_group_get(struct ecm_db_connection_instance *ci)
1065{
1066 ecm_db_timer_group_t tg;
1067 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1068
1069 spin_lock_bh(&ecm_db_lock);
1070 tg = ci->defunct_timer.group;
1071 spin_unlock_bh(&ecm_db_lock);
1072 return tg;
1073}
1074EXPORT_SYMBOL(ecm_db_connection_timer_group_get);
1075
1076/*
1077 * ecm_db_connection_make_defunct()
1078 * Make connection defunct.
1079 */
1080void ecm_db_connection_make_defunct(struct ecm_db_connection_instance *ci)
1081{
1082 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07001083
1084 if (ci->defunct) {
1085 ci->defunct(ci->feci);
1086 }
1087
Ben Menchaca84f36632014-02-28 20:57:38 +00001088 if (ecm_db_timer_group_entry_remove(&ci->defunct_timer)) {
1089 ecm_db_connection_deref(ci);
1090 }
1091}
1092EXPORT_SYMBOL(ecm_db_connection_make_defunct);
1093
1094/*
1095 * ecm_db_connection_data_totals_update()
1096 * Update the total data (and packets) sent/received by the given host
1097 */
1098void ecm_db_connection_data_totals_update(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
1099{
Murat Sezginf6814bc2015-08-20 11:31:41 -07001100 int32_t i;
1101
Ben Menchaca84f36632014-02-28 20:57:38 +00001102 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
1103
1104 spin_lock_bh(&ecm_db_lock);
1105
1106 if (is_from) {
1107 /*
1108 * Update totals sent by the FROM side of connection
1109 */
1110 ci->from_data_total += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001111 ci->from_packet_total += packets;
1112#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001113 ci->mapping_from->from_data_total += size;
1114 ci->mapping_from->host->from_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001115 ci->from_node->from_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001116 ci->mapping_from->from_packet_total += packets;
1117 ci->mapping_from->host->from_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001118 ci->from_node->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001119
1120 /*
1121 * Data from the host is essentially TO the interface on which the host is reachable
1122 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001123 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1124 ci->from_interfaces[i]->to_data_total += size;
1125 ci->from_interfaces[i]->to_packet_total += packets;
1126 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001127
1128 /*
1129 * Update totals sent TO the other side of the connection
1130 */
1131 ci->mapping_to->to_data_total += size;
1132 ci->mapping_to->host->to_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001133 ci->to_node->to_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001134 ci->mapping_to->to_packet_total += packets;
1135 ci->mapping_to->host->to_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001136 ci->to_node->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001137
1138 /*
1139 * Sending to the other side means FROM the interface we reach that host
1140 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001141 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1142 ci->to_interfaces[i]->from_data_total += size;
1143 ci->to_interfaces[i]->from_packet_total += packets;
1144 }
Gareth Williams85331c92015-03-11 20:39:18 +00001145#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001146 spin_unlock_bh(&ecm_db_lock);
1147 return;
1148 }
1149
1150 /*
1151 * Update totals sent by the TO side of this connection
1152 */
1153 ci->to_data_total += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001154 ci->to_packet_total += packets;
1155#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001156 ci->mapping_to->from_data_total += size;
1157 ci->mapping_to->host->from_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001158 ci->to_node->from_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001159 ci->mapping_to->from_packet_total += packets;
1160 ci->mapping_to->host->from_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001161 ci->to_node->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001162
1163 /*
1164 * Data from the host is essentially TO the interface on which the host is reachable
1165 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001166 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1167 ci->to_interfaces[i]->to_data_total += size;
1168 ci->to_interfaces[i]->to_packet_total += packets;
1169 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001170
1171 /*
1172 * Update totals sent TO the other side of the connection
1173 */
1174 ci->mapping_from->to_data_total += size;
1175 ci->mapping_from->host->to_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001176 ci->from_node->to_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001177 ci->mapping_from->to_packet_total += packets;
1178 ci->mapping_from->host->to_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001179 ci->from_node->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001180
1181 /*
1182 * Sending to the other side means FROM the interface we reach that host
1183 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001184 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1185 ci->from_interfaces[i]->from_data_total += size;
1186 ci->from_interfaces[i]->from_packet_total += packets;
1187 }
Gareth Williams85331c92015-03-11 20:39:18 +00001188#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001189 spin_unlock_bh(&ecm_db_lock);
1190}
1191EXPORT_SYMBOL(ecm_db_connection_data_totals_update);
1192
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301193#ifdef ECM_MULTICAST_ENABLE
1194/*
1195 * ecm_db_multicast_connection_data_totals_update()
1196 * Update the total bytes and packets sent/received by the multicast connection
1197 * TODO: This function is almost similar to unicast connection_data_totals_update() except few
1198 * lines of code. The next merge should have a common logic for both unicast and multicast.
1199 */
1200void ecm_db_multicast_connection_data_totals_update(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
1201{
Murat Sezginf6814bc2015-08-20 11:31:41 -07001202 int32_t i;
1203
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301204 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
1205
1206 spin_lock_bh(&ecm_db_lock);
1207
1208 if (is_from) {
1209 /*
1210 * Update totals sent by the FROM side of connection
1211 */
1212 ci->from_data_total += size;
1213 ci->from_packet_total += packets;
1214#ifdef ECM_DB_ADVANCED_STATS_ENABLE
1215 ci->mapping_from->from_data_total += size;
1216 ci->mapping_from->host->from_data_total += size;
1217 ci->from_node->from_data_total += size;
1218 ci->mapping_from->from_packet_total += packets;
1219 ci->mapping_from->host->from_packet_total += packets;
1220 ci->from_node->from_packet_total += packets;
1221
1222 /*
1223 * Data from the host is essentially TO the interface on which the host is reachable
1224 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001225 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1226 ci->from_interfaces[i]->to_data_total += size;
1227 ci->from_interfaces[i]->to_packet_total += packets;
1228 }
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301229
1230 /*
1231 * Update totals sent TO the other side of the connection
1232 */
1233 ci->mapping_to->to_data_total += size;
1234 ci->mapping_to->host->to_data_total += size;
1235 ci->to_node->to_data_total += size;
1236 ci->mapping_to->to_packet_total += packets;
1237 ci->mapping_to->host->to_packet_total += packets;
1238 ci->to_node->to_packet_total += packets;
1239#endif
1240 spin_unlock_bh(&ecm_db_lock);
1241 return;
1242 }
1243
1244 /*
1245 * Update totals sent by the TO side of this connection
1246 */
1247 ci->to_data_total += size;
1248 ci->to_packet_total += packets;
1249#ifdef ECM_DB_ADVANCED_STATS_ENABLE
1250 ci->mapping_to->from_data_total += size;
1251 ci->mapping_to->host->from_data_total += size;
1252 ci->to_node->from_data_total += size;
1253 ci->mapping_to->from_packet_total += packets;
1254 ci->mapping_to->host->from_packet_total += packets;
1255 ci->to_node->from_packet_total += packets;
1256
1257 /*
1258 * Update totals sent TO the other side of the connection
1259 */
1260 ci->mapping_from->to_data_total += size;
1261 ci->mapping_from->host->to_data_total += size;
1262 ci->from_node->to_data_total += size;
1263 ci->mapping_from->to_packet_total += packets;
1264 ci->mapping_from->host->to_packet_total += packets;
1265 ci->from_node->to_packet_total += packets;
1266
1267 /*
1268 * Sending to the other side means FROM the interface we reach that host
1269 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001270 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1271 ci->from_interfaces[i]->from_data_total += size;
1272 ci->from_interfaces[i]->from_packet_total += packets;
1273 }
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301274#endif
1275 spin_unlock_bh(&ecm_db_lock);
1276}
1277EXPORT_SYMBOL(ecm_db_multicast_connection_data_totals_update);
1278
1279/*
1280 * ecm_db_multicast_connection_interface_heirarchy_stats_update()
1281 * Traverse through the multicast destination interface heirarchy and update the stats (data and packets).
1282 */
1283void ecm_db_multicast_connection_interface_heirarchy_stats_update(struct ecm_db_connection_instance *ci, uint64_t size, uint64_t packets)
1284{
1285 struct ecm_db_iface_instance *to_mc_ifaces;
1286 struct ecm_db_iface_instance *ii;
1287 struct ecm_db_iface_instance **ifaces;
1288 struct ecm_db_iface_instance *ii_temp;
1289 int32_t *to_mc_ifaces_first;
1290 int heirarchy_index;
1291 int ret;
1292
1293 ret = ecm_db_multicast_connection_to_interfaces_get_and_ref_all(ci, &to_mc_ifaces, &to_mc_ifaces_first);
1294 if (ret == 0) {
1295 DEBUG_WARN("%p: no interfaces in to_multicast_interfaces list!\n", ci);
1296 return;
1297 }
1298
1299 spin_lock_bh(&ecm_db_lock);
1300 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
1301
1302 if (to_mc_ifaces_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
1303 ii_temp = ecm_db_multicast_if_heirarchy_get(to_mc_ifaces, heirarchy_index);
1304 ii_temp = ecm_db_multicast_if_instance_get_at_index(ii_temp, ECM_DB_IFACE_HEIRARCHY_MAX - 1);
1305 ifaces = (struct ecm_db_iface_instance **)ii_temp;
1306 ii = *ifaces;
1307 ii->to_data_total += size;
1308 ii->to_packet_total += packets;
1309 }
1310 }
1311 spin_unlock_bh(&ecm_db_lock);
1312
1313 ecm_db_multicast_connection_to_interfaces_deref_all(to_mc_ifaces, to_mc_ifaces_first);
1314}
1315EXPORT_SYMBOL(ecm_db_multicast_connection_interface_heirarchy_stats_update);
1316#endif
1317
Ben Menchaca84f36632014-02-28 20:57:38 +00001318/*
1319 * ecm_db_connection_data_totals_update_dropped()
1320 * Update the total data (and packets) sent by the given host but which we dropped
1321 */
1322void ecm_db_connection_data_totals_update_dropped(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
1323{
Murat Sezginf6814bc2015-08-20 11:31:41 -07001324 int32_t i;
1325
Ben Menchaca84f36632014-02-28 20:57:38 +00001326 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
1327
1328 if (is_from) {
1329 /*
1330 * Update dropped totals sent by the FROM side
1331 */
1332 spin_lock_bh(&ecm_db_lock);
1333 ci->from_data_total_dropped += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001334 ci->from_packet_total_dropped += packets;
1335#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001336 ci->mapping_from->from_data_total_dropped += size;
1337 ci->mapping_from->host->from_data_total_dropped += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001338 ci->from_node->from_data_total_dropped += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001339 ci->mapping_from->from_packet_total_dropped += packets;
1340 ci->mapping_from->host->from_packet_total_dropped += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001341 ci->from_node->from_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001342
1343 /*
1344 * Data from the host is essentially TO the interface on which the host is reachable
1345 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001346 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1347 ci->from_interfaces[i]->to_data_total_dropped += size;
1348 ci->from_interfaces[i]->to_packet_total_dropped += packets;
1349 }
Gareth Williams85331c92015-03-11 20:39:18 +00001350#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001351 spin_unlock_bh(&ecm_db_lock);
1352 return;
1353 }
1354
1355 /*
1356 * Update dropped totals sent by the TO side of this connection
1357 */
1358 spin_lock_bh(&ecm_db_lock);
1359 ci->to_data_total_dropped += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001360 ci->to_packet_total_dropped += packets;
1361#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001362 ci->mapping_to->from_data_total_dropped += size;
1363 ci->mapping_to->host->from_data_total_dropped += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001364 ci->to_node->from_data_total_dropped += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001365 ci->mapping_to->from_packet_total_dropped += packets;
1366 ci->mapping_to->host->from_packet_total_dropped += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001367 ci->to_node->from_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001368
1369 /*
1370 * Data from the host is essentially TO the interface on which the host is reachable
1371 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001372 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1373 ci->to_interfaces[i]->to_data_total_dropped += size;
1374 ci->to_interfaces[i]->to_packet_total_dropped += packets;
1375 }
Gareth Williams85331c92015-03-11 20:39:18 +00001376#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001377 spin_unlock_bh(&ecm_db_lock);
1378}
1379EXPORT_SYMBOL(ecm_db_connection_data_totals_update_dropped);
1380
1381/*
1382 * ecm_db_connection_data_stats_get()
1383 * Return data stats for the instance
1384 */
1385void ecm_db_connection_data_stats_get(struct ecm_db_connection_instance *ci, uint64_t *from_data_total, uint64_t *to_data_total,
1386 uint64_t *from_packet_total, uint64_t *to_packet_total,
1387 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1388 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1389{
1390 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1391
1392 spin_lock_bh(&ecm_db_lock);
1393 if (from_data_total) {
1394 *from_data_total = ci->from_data_total;
1395 }
1396 if (to_data_total) {
1397 *to_data_total = ci->to_data_total;
1398 }
1399 if (from_packet_total) {
1400 *from_packet_total = ci->from_packet_total;
1401 }
1402 if (to_packet_total) {
1403 *to_packet_total = ci->to_packet_total;
1404 }
1405 if (from_data_total_dropped) {
1406 *from_data_total_dropped = ci->from_data_total_dropped;
1407 }
1408 if (to_data_total_dropped) {
1409 *to_data_total_dropped = ci->to_data_total_dropped;
1410 }
1411 if (from_packet_total_dropped) {
1412 *from_packet_total_dropped = ci->from_packet_total_dropped;
1413 }
1414 if (to_packet_total_dropped) {
1415 *to_packet_total_dropped = ci->to_packet_total_dropped;
1416 }
1417 spin_unlock_bh(&ecm_db_lock);
1418}
1419EXPORT_SYMBOL(ecm_db_connection_data_stats_get);
1420
Gareth Williams85331c92015-03-11 20:39:18 +00001421#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001422/*
1423 * ecm_db_mapping_data_stats_get()
1424 * Return data stats for the instance
1425 */
1426void ecm_db_mapping_data_stats_get(struct ecm_db_mapping_instance *mi, uint64_t *from_data_total, uint64_t *to_data_total,
1427 uint64_t *from_packet_total, uint64_t *to_packet_total,
1428 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1429 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1430{
1431 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
1432 spin_lock_bh(&ecm_db_lock);
1433 if (from_data_total) {
1434 *from_data_total = mi->from_data_total;
1435 }
1436 if (to_data_total) {
1437 *to_data_total = mi->to_data_total;
1438 }
1439 if (from_packet_total) {
1440 *from_packet_total = mi->from_packet_total;
1441 }
1442 if (to_packet_total) {
1443 *to_packet_total = mi->to_packet_total;
1444 }
1445 if (from_data_total_dropped) {
1446 *from_data_total_dropped = mi->from_data_total_dropped;
1447 }
1448 if (to_data_total_dropped) {
1449 *to_data_total_dropped = mi->to_data_total_dropped;
1450 }
1451 if (from_packet_total_dropped) {
1452 *from_packet_total_dropped = mi->from_packet_total_dropped;
1453 }
1454 if (to_packet_total_dropped) {
1455 *to_packet_total_dropped = mi->to_packet_total_dropped;
1456 }
1457 spin_unlock_bh(&ecm_db_lock);
1458}
1459EXPORT_SYMBOL(ecm_db_mapping_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001460#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001461
Gareth Williams85331c92015-03-11 20:39:18 +00001462#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001463/*
1464 * ecm_db_host_data_stats_get()
1465 * Return data stats for the instance
1466 */
1467void ecm_db_host_data_stats_get(struct ecm_db_host_instance *hi, uint64_t *from_data_total, uint64_t *to_data_total,
1468 uint64_t *from_packet_total, uint64_t *to_packet_total,
1469 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1470 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1471{
1472 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
1473 spin_lock_bh(&ecm_db_lock);
1474 if (from_data_total) {
1475 *from_data_total = hi->from_data_total;
1476 }
1477 if (to_data_total) {
1478 *to_data_total = hi->to_data_total;
1479 }
1480 if (from_packet_total) {
1481 *from_packet_total = hi->from_packet_total;
1482 }
1483 if (to_packet_total) {
1484 *to_packet_total = hi->to_packet_total;
1485 }
1486 if (from_data_total_dropped) {
1487 *from_data_total_dropped = hi->from_data_total_dropped;
1488 }
1489 if (to_data_total_dropped) {
1490 *to_data_total_dropped = hi->to_data_total_dropped;
1491 }
1492 if (from_packet_total_dropped) {
1493 *from_packet_total_dropped = hi->from_packet_total_dropped;
1494 }
1495 if (to_packet_total_dropped) {
1496 *to_packet_total_dropped = hi->to_packet_total_dropped;
1497 }
1498 spin_unlock_bh(&ecm_db_lock);
1499}
1500EXPORT_SYMBOL(ecm_db_host_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001501#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001502
Gareth Williams85331c92015-03-11 20:39:18 +00001503#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001504/*
1505 * ecm_db_node_data_stats_get()
1506 * Return data stats for the instance
1507 */
1508void ecm_db_node_data_stats_get(struct ecm_db_node_instance *ni, uint64_t *from_data_total, uint64_t *to_data_total,
1509 uint64_t *from_packet_total, uint64_t *to_packet_total,
1510 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1511 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1512{
1513 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
1514 spin_lock_bh(&ecm_db_lock);
1515 if (from_data_total) {
1516 *from_data_total = ni->from_data_total;
1517 }
1518 if (to_data_total) {
1519 *to_data_total = ni->to_data_total;
1520 }
1521 if (from_packet_total) {
1522 *from_packet_total = ni->from_packet_total;
1523 }
1524 if (to_packet_total) {
1525 *to_packet_total = ni->to_packet_total;
1526 }
1527 if (from_data_total_dropped) {
1528 *from_data_total_dropped = ni->from_data_total_dropped;
1529 }
1530 if (to_data_total_dropped) {
1531 *to_data_total_dropped = ni->to_data_total_dropped;
1532 }
1533 if (from_packet_total_dropped) {
1534 *from_packet_total_dropped = ni->from_packet_total_dropped;
1535 }
1536 if (to_packet_total_dropped) {
1537 *to_packet_total_dropped = ni->to_packet_total_dropped;
1538 }
1539 spin_unlock_bh(&ecm_db_lock);
1540}
1541EXPORT_SYMBOL(ecm_db_node_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001542#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001543
Gareth Williams85331c92015-03-11 20:39:18 +00001544#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001545/*
1546 * ecm_db_iface_data_stats_get()
1547 * Return data stats for the instance
1548 */
1549void ecm_db_iface_data_stats_get(struct ecm_db_iface_instance *ii, uint64_t *from_data_total, uint64_t *to_data_total,
1550 uint64_t *from_packet_total, uint64_t *to_packet_total,
1551 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1552 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1553{
1554 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
1555 spin_lock_bh(&ecm_db_lock);
1556 if (from_data_total) {
1557 *from_data_total = ii->from_data_total;
1558 }
1559 if (to_data_total) {
1560 *to_data_total = ii->to_data_total;
1561 }
1562 if (from_packet_total) {
1563 *from_packet_total = ii->from_packet_total;
1564 }
1565 if (to_packet_total) {
1566 *to_packet_total = ii->to_packet_total;
1567 }
1568 if (from_data_total_dropped) {
1569 *from_data_total_dropped = ii->from_data_total_dropped;
1570 }
1571 if (to_data_total_dropped) {
1572 *to_data_total_dropped = ii->to_data_total_dropped;
1573 }
1574 if (from_packet_total_dropped) {
1575 *from_packet_total_dropped = ii->from_packet_total_dropped;
1576 }
1577 if (to_packet_total_dropped) {
1578 *to_packet_total_dropped = ii->to_packet_total_dropped;
1579 }
1580 spin_unlock_bh(&ecm_db_lock);
1581}
1582EXPORT_SYMBOL(ecm_db_iface_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001583#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001584
1585/*
1586 * ecm_db_connection_serial_get()
1587 * Return serial
1588 */
1589uint32_t ecm_db_connection_serial_get(struct ecm_db_connection_instance *ci)
1590{
1591 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1592 return ci->serial;
1593}
1594EXPORT_SYMBOL(ecm_db_connection_serial_get);
1595
1596/*
1597 * ecm_db_connection_from_address_get()
1598 * Return ip address address
1599 */
1600void ecm_db_connection_from_address_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1601{
1602 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1603 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1604 DEBUG_CHECK_MAGIC(ci->mapping_from->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from->host);
1605 ECM_IP_ADDR_COPY(addr, ci->mapping_from->host->address);
1606}
1607EXPORT_SYMBOL(ecm_db_connection_from_address_get);
1608
1609/*
1610 * ecm_db_connection_from_address_nat_get()
1611 * Return NAT ip address address
1612 */
1613void ecm_db_connection_from_address_nat_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1614{
1615 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1616 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1617 DEBUG_CHECK_MAGIC(ci->mapping_from->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from->host);
1618 ECM_IP_ADDR_COPY(addr, ci->mapping_nat_from->host->address);
1619}
1620EXPORT_SYMBOL(ecm_db_connection_from_address_nat_get);
1621
1622/*
1623 * ecm_db_connection_to_address_get()
1624 * Return ip address address
1625 */
1626void ecm_db_connection_to_address_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1627{
1628 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1629 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1630 DEBUG_CHECK_MAGIC(ci->mapping_to->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to->host);
1631 ECM_IP_ADDR_COPY(addr, ci->mapping_to->host->address);
1632}
1633EXPORT_SYMBOL(ecm_db_connection_to_address_get);
1634
1635/*
1636 * ecm_db_connection_to_address_nat_get()
1637 * Return NAT ip address address
1638 */
1639void ecm_db_connection_to_address_nat_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1640{
1641 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1642 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1643 DEBUG_CHECK_MAGIC(ci->mapping_to->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to->host);
1644 ECM_IP_ADDR_COPY(addr, ci->mapping_nat_to->host->address);
1645}
1646EXPORT_SYMBOL(ecm_db_connection_to_address_nat_get);
1647
1648/*
1649 * ecm_db_connection_to_port_get()
1650 * Return port
1651 */
1652int ecm_db_connection_to_port_get(struct ecm_db_connection_instance *ci)
1653{
1654 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1655 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1656 return ci->mapping_to->port;
1657}
1658EXPORT_SYMBOL(ecm_db_connection_to_port_get);
1659
1660/*
1661 * ecm_db_connection_to_port_nat_get()
1662 * Return port
1663 */
1664int ecm_db_connection_to_port_nat_get(struct ecm_db_connection_instance *ci)
1665{
1666 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1667 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1668 return ci->mapping_nat_to->port;
1669}
1670EXPORT_SYMBOL(ecm_db_connection_to_port_nat_get);
1671
1672/*
1673 * ecm_db_connection_from_port_get()
1674 * Return port
1675 */
1676int ecm_db_connection_from_port_get(struct ecm_db_connection_instance *ci)
1677{
1678 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1679 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1680 return ci->mapping_from->port;
1681}
1682EXPORT_SYMBOL(ecm_db_connection_from_port_get);
1683
1684/*
1685 * ecm_db_connection_from_port_nat_get()
1686 * Return port
1687 */
1688int ecm_db_connection_from_port_nat_get(struct ecm_db_connection_instance *ci)
1689{
1690 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1691 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1692 return ci->mapping_nat_from->port;
1693}
1694EXPORT_SYMBOL(ecm_db_connection_from_port_nat_get);
1695
1696/*
1697 * ecm_db_connection_to_node_address_get()
1698 * Return address of the node used when sending packets to the 'to' side.
1699 */
1700void ecm_db_connection_to_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1701{
1702 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001703 memcpy(address_buffer, ci->to_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001704}
1705EXPORT_SYMBOL(ecm_db_connection_to_node_address_get);
1706
1707/*
1708 * ecm_db_connection_from_node_address_get()
1709 * Return address of the node used when sending packets to the 'from' side.
1710 */
1711void ecm_db_connection_from_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1712{
1713 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001714 memcpy(address_buffer, ci->from_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001715}
1716EXPORT_SYMBOL(ecm_db_connection_from_node_address_get);
1717
1718/*
1719 * ecm_db_connection_to_nat_node_address_get()
1720 * Return address of the node used when sending packets to the 'to' NAT side.
1721 */
1722void ecm_db_connection_to_nat_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1723{
1724 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001725 memcpy(address_buffer, ci->to_nat_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001726}
1727EXPORT_SYMBOL(ecm_db_connection_to_nat_node_address_get);
1728
1729/*
1730 * ecm_db_connection_from_nat_node_address_get()
1731 * Return address of the node used when sending packets to the 'from' NAT side.
1732 */
1733void ecm_db_connection_from_nat_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1734{
1735 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001736 memcpy(address_buffer, ci->from_nat_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001737}
1738EXPORT_SYMBOL(ecm_db_connection_from_nat_node_address_get);
1739
1740/*
1741 * ecm_db_connection_to_iface_name_get()
1742 * Return name of interface on which the 'to' side may be reached
1743 */
1744void ecm_db_connection_to_iface_name_get(struct ecm_db_connection_instance *ci, char *name_buffer)
1745{
1746 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001747 strcpy(name_buffer, ci->to_node->iface->name);
Ben Menchaca84f36632014-02-28 20:57:38 +00001748}
1749EXPORT_SYMBOL(ecm_db_connection_to_iface_name_get);
1750
1751/*
1752 * ecm_db_connection_from_iface_name_get()
1753 * Return name of interface on which the 'from' side may be reached
1754 */
1755void ecm_db_connection_from_iface_name_get(struct ecm_db_connection_instance *ci, char *name_buffer)
1756{
1757 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001758 strcpy(name_buffer, ci->from_node->iface->name);
Ben Menchaca84f36632014-02-28 20:57:38 +00001759}
1760EXPORT_SYMBOL(ecm_db_connection_from_iface_name_get);
1761
1762/*
1763 * ecm_db_connection_to_iface_mtu_get()
1764 * Return MTU of interface on which the 'to' side may be reached
1765 */
1766int ecm_db_connection_to_iface_mtu_get(struct ecm_db_connection_instance *ci)
1767{
1768 int mtu;
1769 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1770 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001771 mtu = ci->to_node->iface->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00001772 spin_unlock_bh(&ecm_db_lock);
1773 return mtu;
1774}
1775EXPORT_SYMBOL(ecm_db_connection_to_iface_mtu_get);
1776
1777/*
1778 * ecm_db_connection_to_iface_type_get()
1779 * Return type of interface on which the 'to' side may be reached
1780 */
1781ecm_db_iface_type_t ecm_db_connection_to_iface_type_get(struct ecm_db_connection_instance *ci)
1782{
1783 ecm_db_iface_type_t type;
1784
1785 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1786 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001787 type = ci->to_node->iface->type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001788 spin_unlock_bh(&ecm_db_lock);
1789 return type;
1790}
1791EXPORT_SYMBOL(ecm_db_connection_to_iface_type_get);
1792
1793/*
1794 * ecm_db_connection_from_iface_mtu_get()
1795 * Return MTU of interface on which the 'from' side may be reached
1796 */
1797int ecm_db_connection_from_iface_mtu_get(struct ecm_db_connection_instance *ci)
1798{
1799 int mtu;
1800 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1801 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001802 mtu = ci->from_node->iface->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00001803 spin_unlock_bh(&ecm_db_lock);
1804 return mtu;
1805}
1806EXPORT_SYMBOL(ecm_db_connection_from_iface_mtu_get);
1807
1808/*
1809 * ecm_db_connection_from_iface_type_get()
1810 * Return type of interface on which the 'from' side may be reached
1811 */
1812ecm_db_iface_type_t ecm_db_connection_from_iface_type_get(struct ecm_db_connection_instance *ci)
1813{
1814 ecm_db_iface_type_t type;
1815
1816 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1817 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001818 type = ci->from_node->iface->type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001819 spin_unlock_bh(&ecm_db_lock);
1820 return type;
1821}
1822EXPORT_SYMBOL(ecm_db_connection_from_iface_type_get);
1823
1824/*
1825 * ecm_db_connection_iface_type_get()
1826 * Return type of interface
1827 */
1828ecm_db_iface_type_t ecm_db_connection_iface_type_get(struct ecm_db_iface_instance *ii)
1829{
1830 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
1831 return ii->type;
1832}
1833EXPORT_SYMBOL(ecm_db_connection_iface_type_get);
1834
1835/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301836 * ecm_db_connection_regeneration_occurrances_get()
1837 * Get the number of regeneration occurrances that have occurred since the connection was created.
Ben Menchaca84f36632014-02-28 20:57:38 +00001838 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301839uint16_t ecm_db_connection_regeneration_occurrances_get(struct ecm_db_connection_instance *ci)
1840{
1841 uint16_t occurances;
1842 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1843
1844 spin_lock_bh(&ecm_db_lock);
1845 occurances = ci->regen_occurances;
1846 spin_unlock_bh(&ecm_db_lock);
1847 return occurances;
1848}
1849EXPORT_SYMBOL(ecm_db_connection_regeneration_occurrances_get);
1850
1851/*
1852 * ecm_db_conection_regeneration_completed()
1853 * Re-generation was completed successfully
1854 */
1855void ecm_db_conection_regeneration_completed(struct ecm_db_connection_instance *ci)
Ben Menchaca84f36632014-02-28 20:57:38 +00001856{
1857 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1858
1859 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301860
1861 DEBUG_ASSERT(ci->regen_in_progress, "%p: Bad call", ci);
1862 DEBUG_ASSERT(ci->regen_required > 0, "%p: Bad call", ci);
1863
1864 /*
1865 * Decrement the required counter by 1.
1866 * This may mean that regeneration is still required due to another change occuring _during_ re-generation.
1867 */
1868 ci->regen_required--;
1869 ci->regen_in_progress = false;
1870 ci->regen_success++;
1871 spin_unlock_bh(&ecm_db_lock);
1872}
1873EXPORT_SYMBOL(ecm_db_conection_regeneration_completed);
1874
1875/*
1876 * ecm_db_conection_regeneration_failed()
1877 * Re-generation failed
1878 */
1879void ecm_db_conection_regeneration_failed(struct ecm_db_connection_instance *ci)
1880{
1881 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1882
1883 spin_lock_bh(&ecm_db_lock);
1884
1885 DEBUG_ASSERT(ci->regen_in_progress, "%p: Bad call", ci);
1886 DEBUG_ASSERT(ci->regen_required > 0, "%p: Bad call", ci);
1887
1888 /*
1889 * Re-generation is no longer in progress BUT we leave the regen
1890 * counter as it is so as to indicate re-generation is still needed
1891 */
1892 ci->regen_in_progress = false;
1893 ci->regen_fail++;
1894 spin_unlock_bh(&ecm_db_lock);
1895}
1896EXPORT_SYMBOL(ecm_db_conection_regeneration_failed);
1897
1898/*
1899 * ecm_db_connection_regeneration_required_check()
1900 * Returns true if the connection needs to be re-generated.
1901 *
1902 * If re-generation is needed this will mark the connection to indicate that re-generation is needed AND in progress.
1903 * If the return code is TRUE the caller MUST handle the re-generation.
1904 * Upon re-generation completion you must call ecm_db_conection_regeneration_completed() or ecm_db_conection_regeneration_failed().
1905 */
1906bool ecm_db_connection_regeneration_required_check(struct ecm_db_connection_instance *ci)
1907{
1908 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1909
1910 /*
1911 * Check the global generation counter for changes
1912 */
1913 spin_lock_bh(&ecm_db_lock);
1914 if (ci->generation != ecm_db_connection_generation) {
1915 /*
1916 * Re-generation is needed
1917 */
1918 ci->regen_occurances++;
1919 ci->regen_required++;
1920
1921 /*
1922 * Record that we have seen this change
1923 */
1924 ci->generation = ecm_db_connection_generation;
1925 }
1926
1927 /*
1928 * If re-generation is in progress then something is handling re-generation already
1929 * so we tell the caller that it cannot handle re-generation.
1930 */
1931 if (ci->regen_in_progress) {
Ben Menchaca84f36632014-02-28 20:57:38 +00001932 spin_unlock_bh(&ecm_db_lock);
1933 return false;
1934 }
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301935
1936 /*
1937 * Is re-generation required?
1938 */
1939 if (ci->regen_required == 0) {
1940 spin_unlock_bh(&ecm_db_lock);
1941 return false;
1942 }
1943
1944 /*
1945 * Flag that re-generation is in progress and tell the caller to handle re-generation
1946 */
1947 ci->regen_in_progress = true;
Ben Menchaca84f36632014-02-28 20:57:38 +00001948 spin_unlock_bh(&ecm_db_lock);
1949 return true;
1950}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301951EXPORT_SYMBOL(ecm_db_connection_regeneration_required_check);
Ben Menchaca84f36632014-02-28 20:57:38 +00001952
1953/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301954 * ecm_db_connection_regeneration_required_peek()
1955 * Returns true if the connection needs to be regenerated.
Ben Menchaca84f36632014-02-28 20:57:38 +00001956 *
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301957 * NOTE: The caller MUST NOT handle re-generation, the caller may use this indication
1958 * to determine the sanity of the connection state and whether acceleration is permitted.
Ben Menchaca84f36632014-02-28 20:57:38 +00001959 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301960bool ecm_db_connection_regeneration_required_peek(struct ecm_db_connection_instance *ci)
Ben Menchaca84f36632014-02-28 20:57:38 +00001961{
1962 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1963
1964 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301965
1966 /*
1967 * Check the global generation counter for changes (record any change now)
1968 */
1969 if (ci->generation != ecm_db_connection_generation) {
1970 /*
1971 * Re-generation is needed, flag the connection as needing re-generation now.
1972 */
1973 ci->regen_occurances++;
1974 ci->regen_required++;
1975
1976 /*
1977 * Record that we have seen this change
1978 */
1979 ci->generation = ecm_db_connection_generation;
1980 }
1981 if (ci->regen_required == 0) {
Ben Menchaca84f36632014-02-28 20:57:38 +00001982 spin_unlock_bh(&ecm_db_lock);
1983 return false;
1984 }
1985 spin_unlock_bh(&ecm_db_lock);
1986 return true;
1987}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301988EXPORT_SYMBOL(ecm_db_connection_regeneration_required_peek);
Ben Menchaca84f36632014-02-28 20:57:38 +00001989
1990/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301991 * ecm_db_connection_regeneration_needed()
1992 * Cause a specific connection to require re-generation
1993 *
1994 * NOTE: This only flags that re-generation is needed.
1995 * The connection will typically be re-generated when ecm_db_connection_regeneration_required_check() is invoked.
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01001996 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301997void ecm_db_connection_regeneration_needed(struct ecm_db_connection_instance *ci)
Ben Menchaca84f36632014-02-28 20:57:38 +00001998{
1999 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2000
2001 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302002 ci->regen_occurances++;
2003 ci->regen_required++;
Ben Menchaca84f36632014-02-28 20:57:38 +00002004 spin_unlock_bh(&ecm_db_lock);
2005}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302006EXPORT_SYMBOL(ecm_db_connection_regeneration_needed);
Ben Menchaca84f36632014-02-28 20:57:38 +00002007
2008/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302009 * ecm_db_regeneration_needed()
2010 * Bump the global generation index to cause a re-generation of all connections state.
Ben Menchaca84f36632014-02-28 20:57:38 +00002011 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302012void ecm_db_regeneration_needed(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002013{
2014 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302015 ecm_db_connection_generation++;
Ben Menchaca84f36632014-02-28 20:57:38 +00002016 spin_unlock_bh(&ecm_db_lock);
2017}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302018EXPORT_SYMBOL(ecm_db_regeneration_needed);
Ben Menchaca84f36632014-02-28 20:57:38 +00002019
2020/*
Xiaoping Faned6d37e2015-09-17 14:13:47 -07002021 * ecm_db_connection_regenerate()
2022 * Re-generate a specific connection
2023 */
2024void ecm_db_connection_regenerate(struct ecm_db_connection_instance *ci)
2025{
2026 struct ecm_front_end_connection_instance *feci;
2027
2028 DEBUG_TRACE("Regenerate connection: %p\n", ci);
2029
2030 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2031
2032 /*
2033 * Notify front end to regenerate a connection.
2034 */
2035 feci = ecm_db_connection_front_end_get_and_ref(ci);
2036 feci->regenerate(feci, ci);
2037 feci->deref(feci);
2038}
2039EXPORT_SYMBOL(ecm_db_connection_regenerate);
2040
2041/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002042 * ecm_db_connection_direction_get()
2043 * Return direction of the connection.
2044 *
2045 * NOTE: an EGRESS connection means that packets being sent to mapping_to should have qos applied.
2046 * INGRESS means that packets being sent to mapping_from should have qos applied.
2047 */
2048ecm_db_direction_t ecm_db_connection_direction_get(struct ecm_db_connection_instance *ci)
2049{
2050 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2051 return ci->direction;
2052}
2053EXPORT_SYMBOL(ecm_db_connection_direction_get);
2054
2055/*
2056 * ecm_db_mapping_port_count_get()
2057 * Return port count stats for a mapping.
2058 */
2059void ecm_db_mapping_port_count_get(struct ecm_db_mapping_instance *mi,
2060 int *tcp_from, int *tcp_to, int *udp_from, int *udp_to, int *from, int *to,
2061 int *tcp_nat_from, int *tcp_nat_to, int *udp_nat_from, int *udp_nat_to, int *nat_from, int *nat_to)
2062{
2063 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2064
2065 spin_lock_bh(&ecm_db_lock);
2066
2067 *tcp_from = mi->tcp_from;
2068 *tcp_to = mi->tcp_to;
2069 *udp_from = mi->udp_from;
2070 *udp_to = mi->udp_to;
2071 *from = mi->from;
2072 *to = mi->to;
2073
2074 *tcp_nat_from = mi->tcp_nat_from;
2075 *tcp_nat_to = mi->tcp_nat_to;
2076 *udp_nat_from = mi->udp_nat_from;
2077 *udp_nat_to = mi->udp_nat_to;
2078 *nat_from = mi->nat_from;
2079 *nat_to = mi->nat_to;
2080
2081 spin_unlock_bh(&ecm_db_lock);
2082}
2083EXPORT_SYMBOL(ecm_db_mapping_port_count_get);
2084
2085/*
2086 * ecm_db_connection_is_routed_get()
2087 * Return whether connection is a routed path or not
2088 */
2089bool ecm_db_connection_is_routed_get(struct ecm_db_connection_instance *ci)
2090{
2091 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2092 return ci->is_routed;
2093}
2094EXPORT_SYMBOL(ecm_db_connection_is_routed_get);
2095
2096/*
2097 * ecm_db_connection_protocol_get()
2098 * Return protocol of connection
2099 */
2100int ecm_db_connection_protocol_get(struct ecm_db_connection_instance *ci)
2101{
2102 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2103 return ci->protocol;
2104}
2105EXPORT_SYMBOL(ecm_db_connection_protocol_get);
2106
2107/*
Gareth Williams3e5b37f2015-05-13 10:04:12 +01002108 * ecm_db_connection_ip_version_get()
2109 * Return IP version of connection
2110 */
2111int ecm_db_connection_ip_version_get(struct ecm_db_connection_instance *ci)
2112{
2113 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2114 return ci->ip_version;
2115}
2116EXPORT_SYMBOL(ecm_db_connection_ip_version_get);
2117
2118/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002119 * ecm_db_host_address_get()
2120 * Return address of host
2121 */
2122void ecm_db_host_address_get(struct ecm_db_host_instance *hi, ip_addr_t addr)
2123{
2124 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
2125 ECM_IP_ADDR_COPY(addr, hi->address);
2126}
2127EXPORT_SYMBOL(ecm_db_host_address_get);
2128
2129/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002130 * ecm_db_host_on_link_get()
2131 * Return on link status of host
2132 */
2133bool ecm_db_host_on_link_get(struct ecm_db_host_instance *hi)
2134{
2135 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
2136 return hi->on_link;
2137}
2138EXPORT_SYMBOL(ecm_db_host_on_link_get);
2139
2140/*
2141 * ecm_db_mapping_adress_get()
2142 * Return address
2143 */
2144void ecm_db_mapping_adress_get(struct ecm_db_mapping_instance *mi, ip_addr_t addr)
2145{
2146 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2147 ECM_IP_ADDR_COPY(addr, mi->host->address);
2148}
2149EXPORT_SYMBOL(ecm_db_mapping_adress_get);
2150
2151/*
2152 * ecm_db_mapping_port_get()
2153 * Return port
2154 */
2155int ecm_db_mapping_port_get(struct ecm_db_mapping_instance *mi)
2156{
2157 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2158 return mi->port;
2159}
2160EXPORT_SYMBOL(ecm_db_mapping_port_get);
2161
2162/*
2163 * ecm_db_node_adress_get()
2164 * Return address
2165 */
2166void ecm_db_node_adress_get(struct ecm_db_node_instance *ni, uint8_t *address_buffer)
2167{
2168 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
2169 memcpy(address_buffer, ni->address, ETH_ALEN);
2170}
2171EXPORT_SYMBOL(ecm_db_node_adress_get);
2172
2173/*
2174 * _ecm_db_timer_group_entry_remove()
2175 * Remove the entry from its timer group, returns false if the entry has already expired.
2176 */
2177static bool _ecm_db_timer_group_entry_remove(struct ecm_db_timer_group_entry *tge)
2178{
2179 struct ecm_db_timer_group *timer_group;
2180
2181 /*
2182 * If not in a timer group then it is already removed
2183 */
2184 if (tge->group == ECM_DB_TIMER_GROUPS_MAX) {
2185 return false;
2186 }
2187
2188 /*
2189 * Remove the connection from its current group
2190 */
2191 timer_group = &ecm_db_timer_groups[tge->group];
2192
2193 /*
2194 * Somewhere in the list?
2195 */
2196 if (tge->prev) {
2197 tge->prev->next = tge->next;
2198 } else {
2199 /*
2200 * First in the group
2201 */
2202 DEBUG_ASSERT(timer_group->head == tge, "%p: bad head, expecting %p, got %p\n", timer_group, tge, timer_group->head);
2203 timer_group->head = tge->next;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302204 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002205
2206 if (tge->next) {
2207 tge->next->prev = tge->prev;
2208 } else {
2209 /*
2210 * No next so this must be the last item - we need to adjust the tail pointer
2211 */
2212 DEBUG_ASSERT(timer_group->tail == tge, "%p: bad tail, expecting %p got %p\n", timer_group, tge, timer_group->tail);
2213 timer_group->tail = tge->prev;
2214 }
2215
2216 /*
2217 * No longer a part of a timer group
2218 */
2219 tge->group = ECM_DB_TIMER_GROUPS_MAX;
2220 return true;
2221}
2222
2223/*
2224 * ecm_db_timer_group_entry_remove()
2225 * Remove the connection from its timer group, returns false if the entry has already expired.
2226 */
2227bool ecm_db_timer_group_entry_remove(struct ecm_db_timer_group_entry *tge)
2228{
2229 bool res;
2230 spin_lock_bh(&ecm_db_lock);
2231 res = _ecm_db_timer_group_entry_remove(tge);
2232 spin_unlock_bh(&ecm_db_lock);
2233 return res;
2234}
2235EXPORT_SYMBOL(ecm_db_timer_group_entry_remove);
2236
2237/*
2238 * _ecm_db_timer_group_entry_set()
2239 * Set the timer group to which this entry will be a member
2240 */
2241void _ecm_db_timer_group_entry_set(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
2242{
2243 struct ecm_db_timer_group *timer_group;
2244
2245 DEBUG_ASSERT(tge->group == ECM_DB_TIMER_GROUPS_MAX, "%p: already set\n", tge);
2246
2247 /*
2248 * Set group
2249 */
2250 tge->group = tg;
2251 timer_group = &ecm_db_timer_groups[tge->group];
2252 tge->timeout = timer_group->time + ecm_db_time;
2253
2254 /*
2255 * Insert into a timer group at the head (as this is now touched)
2256 */
2257 tge->prev = NULL;
2258 tge->next = timer_group->head;
2259 if (!timer_group->head) {
2260 /*
2261 * As there is no head there is also no tail so we need to set that
2262 */
2263 timer_group->tail = tge;
2264 } else {
2265 /*
2266 * As there is a head already there must be a tail. Since we insert before
2267 * the current head we don't adjust the tail.
2268 */
2269 timer_group->head->prev = tge;
2270 }
2271 timer_group->head = tge;
2272}
2273
2274/*
2275 * ecm_db_timer_group_entry_reset()
2276 * Re-set the timer group to which this entry will be a member.
2277 *
2278 * Returns false if the timer cannot be reset because it has expired
2279 */
2280bool ecm_db_timer_group_entry_reset(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
2281{
2282 spin_lock_bh(&ecm_db_lock);
2283
2284 /*
2285 * Remove it from its current group, if any
2286 */
2287 if (!_ecm_db_timer_group_entry_remove(tge)) {
2288 spin_unlock_bh(&ecm_db_lock);
2289 return false;
2290 }
2291
2292 /*
2293 * Set new group
2294 */
2295 _ecm_db_timer_group_entry_set(tge, tg);
2296 spin_unlock_bh(&ecm_db_lock);
2297 return true;
2298}
2299EXPORT_SYMBOL(ecm_db_timer_group_entry_reset);
2300
2301/*
2302 * ecm_db_timer_group_entry_set()
2303 * Set the timer group to which this entry will be a member
2304 */
2305void ecm_db_timer_group_entry_set(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
2306{
2307 spin_lock_bh(&ecm_db_lock);
2308 _ecm_db_timer_group_entry_set(tge, tg);
2309 spin_unlock_bh(&ecm_db_lock);
2310}
2311EXPORT_SYMBOL(ecm_db_timer_group_entry_set);
2312
2313/*
2314 * ecm_db_timer_group_entry_init()
2315 * Initialise a timer entry ready for setting
2316 */
2317void ecm_db_timer_group_entry_init(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_entry_callback_t fn, void *arg)
2318{
2319 memset(tge, 0, sizeof(struct ecm_db_timer_group_entry));
2320 tge->group = ECM_DB_TIMER_GROUPS_MAX;
2321 tge->arg = arg;
2322 tge->fn = fn;
2323}
2324EXPORT_SYMBOL(ecm_db_timer_group_entry_init);
2325
2326/*
2327 * ecm_db_timer_group_entry_touch()
2328 * Update the timeout, if the timer is not running this has no effect.
2329 * It returns false if the timer is not running.
2330 */
2331bool ecm_db_timer_group_entry_touch(struct ecm_db_timer_group_entry *tge)
2332{
2333 struct ecm_db_timer_group *timer_group;
2334
2335 spin_lock_bh(&ecm_db_lock);
2336
2337 /*
2338 * If not in a timer group then do nothing
2339 */
2340 if (tge->group == ECM_DB_TIMER_GROUPS_MAX) {
2341 spin_unlock_bh(&ecm_db_lock);
2342 return false;
2343 }
2344
2345 /*
2346 * Update time to live
2347 */
2348 timer_group = &ecm_db_timer_groups[tge->group];
2349
2350 /*
2351 * Link out of its current position.
2352 */
2353 if (!tge->prev) {
2354 /*
2355 * Already at the head, just update the time
2356 */
2357 tge->timeout = timer_group->time + ecm_db_time;
2358 spin_unlock_bh(&ecm_db_lock);
2359 return true;
2360 }
2361
2362 /*
2363 * tge->prev is not null, so:
2364 * 1) it is in a timer list
2365 * 2) is not at the head of the list
2366 * 3) there is a head already (so more than one item on the list)
2367 * 4) there is a prev pointer.
2368 * Somewhere in the group list - unlink it.
2369 */
2370 tge->prev->next = tge->next;
2371
2372 if (tge->next) {
2373 tge->next->prev = tge->prev;
2374 } else {
2375 /*
2376 * Since there is no next this must be the tail
2377 */
2378 DEBUG_ASSERT(timer_group->tail == tge, "%p: bad tail, expecting %p got %p\n", timer_group, tge, timer_group->tail);
2379 timer_group->tail = tge->prev;
2380 }
2381
2382 /*
2383 * Link in to head.
2384 */
Sol Kavy213e45d2014-06-05 18:04:07 -07002385 tge->timeout = timer_group->time + ecm_db_time;
Ben Menchaca84f36632014-02-28 20:57:38 +00002386 tge->prev = NULL;
2387 tge->next = timer_group->head;
2388 timer_group->head->prev = tge;
2389 timer_group->head = tge;
2390 spin_unlock_bh(&ecm_db_lock);
2391 return true;
2392}
2393EXPORT_SYMBOL(ecm_db_timer_group_entry_touch);
2394
2395/*
2396 * _ecm_db_connection_ref()
2397 */
2398static void _ecm_db_connection_ref(struct ecm_db_connection_instance *ci)
2399{
2400 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2401 ci->refs++;
2402 DEBUG_TRACE("%p: connection ref %d\n", ci, ci->refs);
2403 DEBUG_ASSERT(ci->refs > 0, "%p: ref wrap\n", ci);
2404}
2405
2406/*
2407 * ecm_db_connection_ref()
2408 */
2409void ecm_db_connection_ref(struct ecm_db_connection_instance *ci)
2410{
2411 spin_lock_bh(&ecm_db_lock);
2412 _ecm_db_connection_ref(ci);
2413 spin_unlock_bh(&ecm_db_lock);
2414}
2415EXPORT_SYMBOL(ecm_db_connection_ref);
2416
2417/*
2418 * _ecm_db_mapping_ref()
2419 */
2420static void _ecm_db_mapping_ref(struct ecm_db_mapping_instance *mi)
2421{
2422 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
2423 mi->refs++;
2424 DEBUG_TRACE("%p: mapping ref %d\n", mi, mi->refs);
2425 DEBUG_ASSERT(mi->refs > 0, "%p: ref wrap\n", mi);
2426}
2427
2428/*
2429 * ecm_db_mapping_ref()
2430 */
2431void ecm_db_mapping_ref(struct ecm_db_mapping_instance *mi)
2432{
2433 spin_lock_bh(&ecm_db_lock);
2434 _ecm_db_mapping_ref(mi);
2435 spin_unlock_bh(&ecm_db_lock);
2436}
2437EXPORT_SYMBOL(ecm_db_mapping_ref);
2438
2439/*
2440 * _ecm_db_host_ref()
2441 */
2442static void _ecm_db_host_ref(struct ecm_db_host_instance *hi)
2443{
2444 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
2445 hi->refs++;
2446 DEBUG_TRACE("%p: host ref %d\n", hi, hi->refs);
2447 DEBUG_ASSERT(hi->refs > 0, "%p: ref wrap\n", hi);
2448}
2449
2450/*
2451 * ecm_db_host_ref()
2452 */
2453void ecm_db_host_ref(struct ecm_db_host_instance *hi)
2454{
2455 spin_lock_bh(&ecm_db_lock);
2456 _ecm_db_host_ref(hi);
2457 spin_unlock_bh(&ecm_db_lock);
2458}
2459EXPORT_SYMBOL(ecm_db_host_ref);
2460
2461/*
2462 * _ecm_db_node_ref()
2463 */
2464static void _ecm_db_node_ref(struct ecm_db_node_instance *ni)
2465{
2466 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
2467 ni->refs++;
2468 DEBUG_TRACE("%p: node ref %d\n", ni, ni->refs);
2469 DEBUG_ASSERT(ni->refs > 0, "%p: ref wrap\n", ni);
2470}
2471
2472/*
2473 * ecm_db_node_ref()
2474 */
2475void ecm_db_node_ref(struct ecm_db_node_instance *ni)
2476{
2477 spin_lock_bh(&ecm_db_lock);
2478 _ecm_db_node_ref(ni);
2479 spin_unlock_bh(&ecm_db_lock);
2480}
2481EXPORT_SYMBOL(ecm_db_node_ref);
2482
2483/*
2484 * _ecm_db_iface_ref()
2485 */
2486static void _ecm_db_iface_ref(struct ecm_db_iface_instance *ii)
2487{
2488 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
2489 ii->refs++;
2490 DEBUG_TRACE("%p: iface ref %d\n", ii, ii->refs);
2491 DEBUG_ASSERT(ii->refs > 0, "%p: ref wrap\n", ii);
2492}
2493
2494/*
2495 * ecm_db_iface_ref()
2496 */
2497void ecm_db_iface_ref(struct ecm_db_iface_instance *ii)
2498{
2499 spin_lock_bh(&ecm_db_lock);
2500 _ecm_db_iface_ref(ii);
2501 spin_unlock_bh(&ecm_db_lock);
2502}
2503EXPORT_SYMBOL(ecm_db_iface_ref);
2504
2505/*
2506 * _ecm_db_listener_ref()
2507 */
2508static void _ecm_db_listener_ref(struct ecm_db_listener_instance *li)
2509{
2510 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
2511 li->refs++;
2512 DEBUG_ASSERT(li->refs > 0, "%p: ref wrap\n", li);
2513}
2514
2515/*
2516 * ecm_db_listener_ref()
2517 */
2518void ecm_db_listener_ref(struct ecm_db_listener_instance *li)
2519{
2520 spin_lock_bh(&ecm_db_lock);
2521 _ecm_db_listener_ref(li);
2522 spin_unlock_bh(&ecm_db_lock);
2523}
2524EXPORT_SYMBOL(ecm_db_listener_ref);
2525
2526/*
2527 * ecm_db_connections_get_and_ref_first()
2528 * Obtain a ref to the first connection instance, if any
2529 */
Gareth Williamsf98d4192015-03-11 16:55:41 +00002530struct ecm_db_connection_instance *ecm_db_connections_get_and_ref_first(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002531{
2532 struct ecm_db_connection_instance *ci;
2533 spin_lock_bh(&ecm_db_lock);
2534 ci = ecm_db_connections;
2535 if (ci) {
2536 _ecm_db_connection_ref(ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302537 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002538 spin_unlock_bh(&ecm_db_lock);
2539 return ci;
2540}
2541EXPORT_SYMBOL(ecm_db_connections_get_and_ref_first);
2542
2543/*
2544 * ecm_db_connection_get_and_ref_next()
2545 * Return the next connection in the list given a connection
2546 */
2547struct ecm_db_connection_instance *ecm_db_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
2548{
2549 struct ecm_db_connection_instance *cin;
2550 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2551 spin_lock_bh(&ecm_db_lock);
2552 cin = ci->next;
2553 if (cin) {
2554 _ecm_db_connection_ref(cin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302555 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002556 spin_unlock_bh(&ecm_db_lock);
2557 return cin;
2558}
2559EXPORT_SYMBOL(ecm_db_connection_get_and_ref_next);
2560
2561/*
2562 * ecm_db_mappings_get_and_ref_first()
2563 * Obtain a ref to the first mapping instance, if any
2564 */
2565struct ecm_db_mapping_instance *ecm_db_mappings_get_and_ref_first(void)
2566{
2567 struct ecm_db_mapping_instance *mi;
2568 spin_lock_bh(&ecm_db_lock);
2569 mi = ecm_db_mappings;
2570 if (mi) {
2571 _ecm_db_mapping_ref(mi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302572 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002573 spin_unlock_bh(&ecm_db_lock);
2574 return mi;
2575}
2576EXPORT_SYMBOL(ecm_db_mappings_get_and_ref_first);
2577
2578/*
2579 * ecm_db_mapping_get_and_ref_next()
2580 * Return the next mapping in the list given a mapping
2581 */
2582struct ecm_db_mapping_instance *ecm_db_mapping_get_and_ref_next(struct ecm_db_mapping_instance *mi)
2583{
2584 struct ecm_db_mapping_instance *min;
2585 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2586 spin_lock_bh(&ecm_db_lock);
2587 min = mi->next;
2588 if (min) {
2589 _ecm_db_mapping_ref(min);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302590 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002591 spin_unlock_bh(&ecm_db_lock);
2592 return min;
2593}
2594EXPORT_SYMBOL(ecm_db_mapping_get_and_ref_next);
2595
2596/*
2597 * ecm_db_hosts_get_and_ref_first()
2598 * Obtain a ref to the first host instance, if any
2599 */
2600struct ecm_db_host_instance *ecm_db_hosts_get_and_ref_first(void)
2601{
2602 struct ecm_db_host_instance *hi;
2603 spin_lock_bh(&ecm_db_lock);
2604 hi = ecm_db_hosts;
2605 if (hi) {
2606 _ecm_db_host_ref(hi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302607 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002608 spin_unlock_bh(&ecm_db_lock);
2609 return hi;
2610}
2611EXPORT_SYMBOL(ecm_db_hosts_get_and_ref_first);
2612
2613/*
2614 * ecm_db_host_get_and_ref_next()
2615 * Return the next host in the list given a host
2616 */
2617struct ecm_db_host_instance *ecm_db_host_get_and_ref_next(struct ecm_db_host_instance *hi)
2618{
2619 struct ecm_db_host_instance *hin;
2620 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
2621 spin_lock_bh(&ecm_db_lock);
2622 hin = hi->next;
2623 if (hin) {
2624 _ecm_db_host_ref(hin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302625 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002626 spin_unlock_bh(&ecm_db_lock);
2627 return hin;
2628}
2629EXPORT_SYMBOL(ecm_db_host_get_and_ref_next);
2630
2631/*
2632 * ecm_db_listeners_get_and_ref_first()
2633 * Obtain a ref to the first listener instance, if any
2634 */
2635static struct ecm_db_listener_instance *ecm_db_listeners_get_and_ref_first(void)
2636{
2637 struct ecm_db_listener_instance *li;
2638 spin_lock_bh(&ecm_db_lock);
2639 li = ecm_db_listeners;
2640 if (li) {
2641 _ecm_db_listener_ref(li);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302642 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002643 spin_unlock_bh(&ecm_db_lock);
2644 return li;
2645}
2646
2647/*
2648 * ecm_db_listener_get_and_ref_next()
2649 * Return the next listener in the list given a listener
2650 */
2651static struct ecm_db_listener_instance *ecm_db_listener_get_and_ref_next(struct ecm_db_listener_instance *li)
2652{
2653 struct ecm_db_listener_instance *lin;
2654 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
2655 spin_lock_bh(&ecm_db_lock);
2656 lin = li->next;
2657 if (lin) {
2658 _ecm_db_listener_ref(lin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302659 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002660 spin_unlock_bh(&ecm_db_lock);
2661 return lin;
2662}
2663
2664/*
2665 * ecm_db_nodes_get_and_ref_first()
2666 * Obtain a ref to the first node instance, if any
2667 */
2668struct ecm_db_node_instance *ecm_db_nodes_get_and_ref_first(void)
2669{
2670 struct ecm_db_node_instance *ni;
2671 spin_lock_bh(&ecm_db_lock);
2672 ni = ecm_db_nodes;
2673 if (ni) {
2674 _ecm_db_node_ref(ni);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302675 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002676 spin_unlock_bh(&ecm_db_lock);
2677 return ni;
2678}
2679EXPORT_SYMBOL(ecm_db_nodes_get_and_ref_first);
2680
2681/*
2682 * ecm_db_node_get_and_ref_next()
2683 * Return the next node in the list given a node
2684 */
2685struct ecm_db_node_instance *ecm_db_node_get_and_ref_next(struct ecm_db_node_instance *ni)
2686{
2687 struct ecm_db_node_instance *nin;
2688 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
2689 spin_lock_bh(&ecm_db_lock);
2690 nin = ni->next;
2691 if (nin) {
2692 _ecm_db_node_ref(nin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302693 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002694 spin_unlock_bh(&ecm_db_lock);
2695 return nin;
2696}
2697EXPORT_SYMBOL(ecm_db_node_get_and_ref_next);
2698
2699/*
2700 * ecm_db_interfaces_get_and_ref_first()
2701 * Obtain a ref to the first iface instance, if any
2702 */
2703struct ecm_db_iface_instance *ecm_db_interfaces_get_and_ref_first(void)
2704{
2705 struct ecm_db_iface_instance *ii;
2706 spin_lock_bh(&ecm_db_lock);
2707 ii = ecm_db_interfaces;
2708 if (ii) {
2709 _ecm_db_iface_ref(ii);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302710 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002711 spin_unlock_bh(&ecm_db_lock);
2712 return ii;
2713}
2714EXPORT_SYMBOL(ecm_db_interfaces_get_and_ref_first);
2715
2716/*
2717 * ecm_db_interface_get_and_ref_next()
2718 * Return the next iface in the list given a iface
2719 */
2720struct ecm_db_iface_instance *ecm_db_interface_get_and_ref_next(struct ecm_db_iface_instance *ii)
2721{
2722 struct ecm_db_iface_instance *iin;
2723 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
2724 spin_lock_bh(&ecm_db_lock);
2725 iin = ii->next;
2726 if (iin) {
2727 _ecm_db_iface_ref(iin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302728 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002729 spin_unlock_bh(&ecm_db_lock);
2730 return iin;
2731}
2732EXPORT_SYMBOL(ecm_db_interface_get_and_ref_next);
2733
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002734#ifdef ECM_DB_CTA_TRACK_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002735/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01002736 * _ecm_db_classifier_type_assignment_remove()
2737 * Remove the connection from the classifier type assignment list (of the given type)
2738 */
2739static void _ecm_db_classifier_type_assignment_remove(struct ecm_db_connection_instance *ci, ecm_classifier_type_t ca_type)
2740{
2741 struct ecm_db_connection_classifier_type_assignment *ta;
2742 struct ecm_db_connection_classifier_type_assignment_list *tal;
2743
Murat Sezginc848bce2016-01-15 09:58:11 -08002744 DEBUG_ASSERT(spin_is_locked(&ecm_db_lock), "%p: lock is not held\n", ci);
2745
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01002746 DEBUG_TRACE("%p: Classifier type assignment remove: %d\n", ci, ca_type);
2747 ta = &ci->type_assignment[ca_type];
2748 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p\n", ta, ci);
2749 DEBUG_ASSERT(ta->iteration_count == 0, "%p: iteration count: %d, type: %d\n", ci, ta->iteration_count, ca_type);
2750
2751 if (ta->next) {
2752 struct ecm_db_connection_classifier_type_assignment *tan = &ta->next->type_assignment[ca_type];
2753 DEBUG_ASSERT(tan->prev == ci, "Bad list, expecting: %p, got: %p\n", ci, tan->prev);
2754 tan->prev = ta->prev;
2755 }
2756
2757 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
2758 if (ta->prev) {
2759 struct ecm_db_connection_classifier_type_assignment *tap = &ta->prev->type_assignment[ca_type];
2760 DEBUG_ASSERT(tap->next == ci, "Bad list, expecting: %p, got: %p\n", ci, tap->next);
2761 tap->next = ta->next;
2762 } else {
2763 /*
2764 * Set new head of list
2765 */
2766 DEBUG_ASSERT(tal->type_assignments_list == ci, "Bad head, expecting %p, got %p, type: %d\n", ci, tal->type_assignments_list, ca_type);
2767 tal->type_assignments_list = ta->next;
2768 }
2769 ta->next = NULL;
2770 ta->prev = NULL;
2771 ta->pending_unassign = false;
2772
2773 /*
2774 * Decrement assignment count
2775 */
2776 tal->type_assignment_count--;
2777 DEBUG_ASSERT(tal->type_assignment_count >= 0, "Bad type assignment count: %d, type: %d\n", tal->type_assignment_count, ca_type);
2778
2779 DEBUG_CLEAR_MAGIC(ta);
2780}
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002781#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01002782
2783/*
Shyam Sunder8793f612016-01-06 20:16:20 +05302784 * _ecm_db_connection_classifier_unassign()
2785 * Unassign a classifier and remove the classifier type
2786 *
2787 * The default classifier cannot be unassigned.
2788 */
2789static inline void _ecm_db_connection_classifier_unassign(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *cci, ecm_classifier_type_t ca_type)
2790{
2791#ifdef ECM_DB_CTA_TRACK_ENABLE
2792 struct ecm_db_connection_classifier_type_assignment *ta;
2793#endif
2794 DEBUG_ASSERT(spin_is_locked(&ecm_db_lock), "%p: lock is not held\n", ci);
2795
2796 /*
2797 * Clear the assignment.
2798 */
2799 ci->assignments_by_type[ca_type] = NULL;
2800
2801 /*
2802 * Link out of assignments list
2803 */
2804 if (cci->ca_prev) {
2805 cci->ca_prev->ca_next = cci->ca_next;
2806 } else {
2807 DEBUG_ASSERT(ci->assignments == cci, "%p: Bad assigmnment list, expecting: %p, got: %p", ci, cci, ci->assignments);
2808 ci->assignments = cci->ca_next;
2809 }
2810 if (cci->ca_next) {
2811 cci->ca_next->ca_prev = cci->ca_prev;
2812 }
2813
2814#ifdef ECM_DB_CTA_TRACK_ENABLE
2815 /*
2816 * Remove from the classifier type assignment list
2817 */
2818 ta = &ci->type_assignment[ca_type];
2819 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
2820 if (ta->iteration_count > 0) {
2821 /*
2822 * The list entry is being iterated outside of db lock being held.
2823 * We cannot remove this entry since it would mess up iteration.
2824 * Set the pending flag to be actioned another time
2825 */
2826 ta->pending_unassign = true;
2827 return;
2828 }
2829
2830 /*
2831 * Remove the list entry
2832 */
2833 DEBUG_INFO("%p: Remove type assignment: %d\n", ci, ca_type);
2834 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
2835#endif
2836 cci->deref(cci);
2837}
2838
Shyam Sunder317ca912016-01-22 16:51:28 +05302839#ifdef ECM_MULTICAST_ENABLE
2840/*
2841 * _ecm_db_multicast_tuple_instance_deref()
2842 * Deref the reference count or
2843 * Free the tuple_instance struct, when the multicast connection dies
2844 */
2845int _ecm_db_multicast_tuple_instance_deref(struct ecm_db_multicast_tuple_instance *ti)
2846{
2847 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
2848 ti->refs--;
2849 DEBUG_TRACE("%p: ti deref %d\n", ti, ti->refs);
2850 DEBUG_ASSERT(ti->refs >= 0, "%p: ref wrap\n", ti);
2851
2852 if (ti->refs > 0) {
2853 return ti->refs;
2854 }
2855
2856 if (ti->flags & ECM_DB_MULTICAST_TUPLE_INSTANCE_FLAGS_INSERTED) {
2857 if (!ti->prev) {
2858 DEBUG_ASSERT(ecm_db_multicast_tuple_instance_table[ti->hash_index] == ti, "%p: hash table bad\n", ti);
2859 ecm_db_multicast_tuple_instance_table[ti->hash_index] = ti->next;
2860 } else {
2861 ti->prev->next = ti->next;
2862 }
2863
2864 if (ti->next) {
2865 ti->next->prev = ti->prev;
2866 }
2867 }
2868
2869 DEBUG_CLEAR_MAGIC(ti);
2870 kfree(ti);
2871
2872 return 0;
2873}
2874#endif
2875
Shyam Sunder8793f612016-01-06 20:16:20 +05302876/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002877 * ecm_db_connection_deref()
2878 * Release reference to connection. Connection is removed from database on final deref and destroyed.
2879 */
2880int ecm_db_connection_deref(struct ecm_db_connection_instance *ci)
2881{
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002882#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002883 ecm_classifier_type_t ca_type;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002884#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002885 int32_t i;
2886
2887 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2888
2889 spin_lock_bh(&ecm_db_lock);
2890 ci->refs--;
2891 DEBUG_TRACE("%p: connection deref %d\n", ci, ci->refs);
2892 DEBUG_ASSERT(ci->refs >= 0, "%p: ref wrap\n", ci);
2893
2894 if (ci->refs > 0) {
2895 int refs = ci->refs;
2896 spin_unlock_bh(&ecm_db_lock);
2897 return refs;
2898 }
2899
Shyam Sunder317ca912016-01-22 16:51:28 +05302900#ifdef ECM_MULTICAST_ENABLE
2901 /*
2902 * For multicast connections, we need to deref the
2903 * associated tuple instance as well
2904 */
2905 if (ci->ti) {
2906 _ecm_db_multicast_tuple_instance_deref(ci->ti);
2907 }
2908#endif
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002909 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00002910 * Remove from database if inserted
2911 */
2912 if (!ci->flags & ECM_DB_CONNECTION_FLAGS_INSERTED) {
2913 spin_unlock_bh(&ecm_db_lock);
2914 } else {
2915 struct ecm_db_listener_instance *li;
Gareth Williamsb5903892015-03-20 15:13:07 +00002916#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002917 struct ecm_db_iface_instance *iface_from;
2918 struct ecm_db_iface_instance *iface_to;
2919 struct ecm_db_iface_instance *iface_nat_from;
2920 struct ecm_db_iface_instance *iface_nat_to;
Gareth Williamsb5903892015-03-20 15:13:07 +00002921#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002922
2923 /*
2924 * Remove it from the connection hash table
2925 */
2926 if (!ci->hash_prev) {
2927 DEBUG_ASSERT(ecm_db_connection_table[ci->hash_index] == ci, "%p: hash table bad\n", ci);
2928 ecm_db_connection_table[ci->hash_index] = ci->hash_next;
2929 } else {
2930 ci->hash_prev->hash_next = ci->hash_next;
2931 }
2932 if (ci->hash_next) {
2933 ci->hash_next->hash_prev = ci->hash_prev;
2934 }
2935 ecm_db_connection_table_lengths[ci->hash_index]--;
2936 DEBUG_ASSERT(ecm_db_connection_table_lengths[ci->hash_index] >= 0, "%p: invalid table len %d\n", ci, ecm_db_connection_table_lengths[ci->hash_index]);
2937
2938 /*
2939 * Remove it from the connection serial hash table
2940 */
2941 if (!ci->serial_hash_prev) {
2942 DEBUG_ASSERT(ecm_db_connection_serial_table[ci->serial_hash_index] == ci, "%p: hash table bad\n", ci);
2943 ecm_db_connection_serial_table[ci->serial_hash_index] = ci->serial_hash_next;
2944 } else {
2945 ci->serial_hash_prev->serial_hash_next = ci->serial_hash_next;
2946 }
2947 if (ci->serial_hash_next) {
2948 ci->serial_hash_next->serial_hash_prev = ci->serial_hash_prev;
2949 }
2950 ecm_db_connection_serial_table_lengths[ci->serial_hash_index]--;
2951 DEBUG_ASSERT(ecm_db_connection_serial_table_lengths[ci->serial_hash_index] >= 0, "%p: invalid table len %d\n", ci, ecm_db_connection_serial_table_lengths[ci->serial_hash_index]);
2952
2953 /*
2954 * Remove from the global list
2955 */
2956 if (!ci->prev) {
2957 DEBUG_ASSERT(ecm_db_connections == ci, "%p: conn table bad\n", ci);
2958 ecm_db_connections = ci->next;
2959 } else {
2960 ci->prev->next = ci->next;
2961 }
2962 if (ci->next) {
2963 ci->next->prev = ci->prev;
2964 }
2965
Gareth Williamsb5903892015-03-20 15:13:07 +00002966#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002967 /*
2968 * Remove connection from the "from" mapping connection list
2969 */
2970 if (!ci->from_prev) {
2971 DEBUG_ASSERT(ci->mapping_from->from_connections == ci, "%p: from conn table bad\n", ci);
2972 ci->mapping_from->from_connections = ci->from_next;
2973 } else {
2974 ci->from_prev->from_next = ci->from_next;
2975 }
2976 if (ci->from_next) {
2977 ci->from_next->from_prev = ci->from_prev;
2978 }
2979
2980 /*
2981 * Remove connection from the "to" mapping connection list
2982 */
2983 if (!ci->to_prev) {
2984 DEBUG_ASSERT(ci->mapping_to->to_connections == ci, "%p: to conn table bad\n", ci);
2985 ci->mapping_to->to_connections = ci->to_next;
2986 } else {
2987 ci->to_prev->to_next = ci->to_next;
2988 }
2989 if (ci->to_next) {
2990 ci->to_next->to_prev = ci->to_prev;
2991 }
2992
2993 /*
2994 * Remove connection from the "from" NAT mapping connection list
2995 */
2996 if (!ci->from_nat_prev) {
2997 DEBUG_ASSERT(ci->mapping_nat_from->from_nat_connections == ci, "%p: nat from conn table bad\n", ci);
2998 ci->mapping_nat_from->from_nat_connections = ci->from_nat_next;
2999 } else {
3000 ci->from_nat_prev->from_nat_next = ci->from_nat_next;
3001 }
3002 if (ci->from_nat_next) {
3003 ci->from_nat_next->from_nat_prev = ci->from_nat_prev;
3004 }
3005
3006 /*
3007 * Remove connection from the "to" NAT mapping connection list
3008 */
3009 if (!ci->to_nat_prev) {
3010 DEBUG_ASSERT(ci->mapping_nat_to->to_nat_connections == ci, "%p: nat to conn table bad\n", ci);
3011 ci->mapping_nat_to->to_nat_connections = ci->to_nat_next;
3012 } else {
3013 ci->to_nat_prev->to_nat_next = ci->to_nat_next;
3014 }
3015 if (ci->to_nat_next) {
3016 ci->to_nat_next->to_nat_prev = ci->to_nat_prev;
3017 }
3018
3019 /*
3020 * Remove connection from the "from" iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01003021 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00003022 */
Gareth Williams90f2a282014-08-27 15:56:25 +01003023 iface_from = ci->from_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00003024 if (!ci->iface_from_prev) {
3025 DEBUG_ASSERT(iface_from->from_connections == ci, "%p: iface from conn table bad\n", ci);
3026 iface_from->from_connections = ci->iface_from_next;
3027 } else {
3028 ci->iface_from_prev->iface_from_next = ci->iface_from_next;
3029 }
3030 if (ci->iface_from_next) {
3031 ci->iface_from_next->iface_from_prev = ci->iface_from_prev;
3032 }
3033
3034 /*
3035 * Remove connection from the "to" iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01003036 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00003037 */
Gareth Williams90f2a282014-08-27 15:56:25 +01003038 iface_to = ci->to_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00003039 if (!ci->iface_to_prev) {
3040 DEBUG_ASSERT(iface_to->to_connections == ci, "%p: to conn table bad\n", ci);
3041 iface_to->to_connections = ci->iface_to_next;
3042 } else {
3043 ci->iface_to_prev->iface_to_next = ci->iface_to_next;
3044 }
3045 if (ci->iface_to_next) {
3046 ci->iface_to_next->iface_to_prev = ci->iface_to_prev;
3047 }
3048
3049 /*
3050 * Remove connection from the "from" NAT iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01003051 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00003052 */
Gareth Williams90f2a282014-08-27 15:56:25 +01003053 iface_nat_from = ci->from_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00003054 if (!ci->iface_from_nat_prev) {
3055 DEBUG_ASSERT(iface_nat_from->from_nat_connections == ci, "%p: nat from conn table bad\n", ci);
3056 iface_nat_from->from_nat_connections = ci->iface_from_nat_next;
3057 } else {
3058 ci->iface_from_nat_prev->iface_from_nat_next = ci->iface_from_nat_next;
3059 }
3060 if (ci->iface_from_nat_next) {
3061 ci->iface_from_nat_next->iface_from_nat_prev = ci->iface_from_nat_prev;
3062 }
3063
3064 /*
3065 * Remove connection from the "to" NAT iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01003066 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00003067 */
Gareth Williams90f2a282014-08-27 15:56:25 +01003068 iface_nat_to = ci->to_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00003069 if (!ci->iface_to_nat_prev) {
3070 DEBUG_ASSERT(iface_nat_to->to_nat_connections == ci, "%p: nat to conn table bad\n", ci);
3071 iface_nat_to->to_nat_connections = ci->iface_to_nat_next;
3072 } else {
3073 ci->iface_to_nat_prev->iface_to_nat_next = ci->iface_to_nat_next;
3074 }
3075 if (ci->iface_to_nat_next) {
3076 ci->iface_to_nat_next->iface_to_nat_prev = ci->iface_to_nat_prev;
3077 }
3078
3079 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01003080 * Remove connection from its "from node" node connection list
3081 */
3082 if (!ci->node_from_prev) {
3083 DEBUG_ASSERT(ci->from_node->from_connections == ci, "%p: from node conn table bad, got: %p\n", ci, ci->from_node->from_connections);
3084 ci->from_node->from_connections = ci->node_from_next;
3085 } else {
3086 ci->node_from_prev->node_from_next = ci->node_from_next;
3087 }
3088 if (ci->node_from_next) {
3089 ci->node_from_next->node_from_prev = ci->node_from_prev;
3090 }
3091 ci->from_node->from_connections_count--;
3092 DEBUG_ASSERT(ci->from_node->from_connections_count >= 0, "%p: bad count\n", ci);
3093
3094 /*
3095 * Remove connection from its "to node" node connection list
3096 */
3097 if (!ci->node_to_prev) {
3098 DEBUG_ASSERT(ci->to_node->to_connections == ci, "%p: to node conn table bad, got: %p\n", ci, ci->to_node->to_connections);
3099 ci->to_node->to_connections = ci->node_to_next;
3100 } else {
3101 ci->node_to_prev->node_to_next = ci->node_to_next;
3102 }
3103 if (ci->node_to_next) {
3104 ci->node_to_next->node_to_prev = ci->node_to_prev;
3105 }
3106 ci->to_node->to_connections_count--;
3107 DEBUG_ASSERT(ci->to_node->to_connections_count >= 0, "%p: bad count\n", ci);
3108
3109 /*
3110 * Remove connection from its "from nat node" node connection list
3111 */
3112 if (!ci->node_from_nat_prev) {
3113 DEBUG_ASSERT(ci->from_nat_node->from_nat_connections == ci, "%p: from nat node conn table bad, got: %p\n", ci, ci->from_nat_node->from_nat_connections);
3114 ci->from_nat_node->from_nat_connections = ci->node_from_nat_next;
3115 } else {
3116 ci->node_from_nat_prev->node_from_nat_next = ci->node_from_nat_next;
3117 }
3118 if (ci->node_from_nat_next) {
3119 ci->node_from_nat_next->node_from_nat_prev = ci->node_from_nat_prev;
3120 }
3121 ci->from_nat_node->from_nat_connections_count--;
3122 DEBUG_ASSERT(ci->from_nat_node->from_nat_connections_count >= 0, "%p: bad count\n", ci);
3123
3124 /*
3125 * Remove connection from its "to nat node" node connection list
3126 */
3127 if (!ci->node_to_nat_prev) {
3128 DEBUG_ASSERT(ci->to_nat_node->to_nat_connections == ci, "%p: to nat node conn table bad, got: %p\n", ci, ci->to_nat_node->to_nat_connections);
3129 ci->to_nat_node->to_nat_connections = ci->node_to_nat_next;
3130 } else {
3131 ci->node_to_nat_prev->node_to_nat_next = ci->node_to_nat_next;
3132 }
3133 if (ci->node_to_nat_next) {
3134 ci->node_to_nat_next->node_to_nat_prev = ci->node_to_nat_prev;
3135 }
3136 ci->to_nat_node->to_nat_connections_count--;
3137 DEBUG_ASSERT(ci->to_nat_node->to_nat_connections_count >= 0, "%p: bad count\n", ci);
Gareth Williamsb5903892015-03-20 15:13:07 +00003138#endif
Gareth Williams90f2a282014-08-27 15:56:25 +01003139
3140 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00003141 * Update the counters in the mappings
3142 */
3143 if (ci->protocol == IPPROTO_UDP) {
3144 ci->mapping_from->udp_from--;
3145 ci->mapping_to->udp_to--;
3146 ci->mapping_nat_from->udp_nat_from--;
3147 ci->mapping_nat_to->udp_nat_to--;
3148 } else if (ci->protocol == IPPROTO_TCP) {
3149 ci->mapping_from->tcp_from--;
3150 ci->mapping_to->tcp_to--;
3151 ci->mapping_nat_from->tcp_nat_from--;
3152 ci->mapping_nat_to->tcp_nat_to--;
3153 }
3154
3155 ci->mapping_from->from--;
3156 ci->mapping_to->to--;
3157 ci->mapping_nat_from->nat_from--;
3158 ci->mapping_nat_to->nat_to--;
3159
3160 /*
3161 * Assert that the defunt timer has been detached
3162 */
3163 DEBUG_ASSERT(ci->defunct_timer.group == ECM_DB_TIMER_GROUPS_MAX, "%p: unexpected timer group %d\n", ci, ci->defunct_timer.group);
3164
3165 /*
3166 * Decrement protocol counter stats
3167 */
3168 ecm_db_connection_count_by_protocol[ci->protocol]--;
3169 DEBUG_ASSERT(ecm_db_connection_count_by_protocol[ci->protocol] >= 0, "%p: Invalid protocol count %d\n", ci, ecm_db_connection_count_by_protocol[ci->protocol]);
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01003170
Ben Menchaca84f36632014-02-28 20:57:38 +00003171 spin_unlock_bh(&ecm_db_lock);
3172
3173 /*
3174 * Throw removed event to listeners
3175 */
3176 DEBUG_TRACE("%p: Throw connection removed event\n", ci);
3177 li = ecm_db_listeners_get_and_ref_first();
3178 while (li) {
3179 struct ecm_db_listener_instance *lin;
3180 if (li->connection_removed) {
3181 li->connection_removed(li->arg, ci);
3182 }
3183
3184 /*
3185 * Get next listener
3186 */
3187 lin = ecm_db_listener_get_and_ref_next(li);
3188 ecm_db_listener_deref(li);
3189 li = lin;
3190 }
3191 }
3192
Shyam Sunder8793f612016-01-06 20:16:20 +05303193#ifdef ECM_DB_CTA_TRACK_ENABLE
3194 /*
3195 * Unlink from the "assignments by classifier type" lists.
3196 *
3197 * This is done whether the connection is inserted into the database or not - this is because
3198 * classifier assignments take place before adding into the db.
3199 *
3200 * NOTE: We know that the ci is not being iterated in any of these lists because otherwise
3201 * ci would be being held as part of iteration and so we would not be here!
3202 * Equally we know that if the assignments_by_type[] element is non-null then it must also be in the relevant list too.
3203 *
3204 * Default classifier is not in the classifier type assignement list, so we should start the loop index
3205 * with the first assigned classifier type.
3206 */
3207 spin_lock_bh(&ecm_db_lock);
3208 for (ca_type = ECM_CLASSIFIER_TYPE_DEFAULT + 1; ca_type < ECM_CLASSIFIER_TYPES; ++ca_type) {
3209 struct ecm_classifier_instance *cci = ci->assignments_by_type[ca_type];
3210 if (!cci) {
3211 /*
3212 * No assignment of this type, so would not be in the classifier type assignments list
3213 */
3214 continue;
3215 }
3216 _ecm_db_connection_classifier_unassign(ci, cci, ca_type);
3217 }
3218 spin_unlock_bh(&ecm_db_lock);
3219#endif
3220
Ben Menchaca84f36632014-02-28 20:57:38 +00003221 /*
3222 * Throw final event
3223 */
3224 if (ci->final) {
3225 ci->final(ci->arg);
3226 }
3227
Murat Sezgina4b4b1f2016-01-19 12:21:55 -08003228 /*
3229 * Release instances to the objects referenced by the connection
3230 */
3231 while (ci->assignments) {
3232 struct ecm_classifier_instance *classi = ci->assignments;
3233 ci->assignments = classi->ca_next;
3234 classi->deref(classi);
3235 }
3236
Ben Menchaca84f36632014-02-28 20:57:38 +00003237 if (ci->mapping_from) {
3238 ecm_db_mapping_deref(ci->mapping_from);
3239 }
3240 if (ci->mapping_to) {
3241 ecm_db_mapping_deref(ci->mapping_to);
3242 }
3243 if (ci->mapping_nat_from) {
3244 ecm_db_mapping_deref(ci->mapping_nat_from);
3245 }
3246 if (ci->mapping_nat_to) {
3247 ecm_db_mapping_deref(ci->mapping_nat_to);
3248 }
3249 if (ci->feci) {
3250 ci->feci->deref(ci->feci);
3251 }
Gareth Williams90f2a282014-08-27 15:56:25 +01003252 if (ci->from_node) {
3253 ecm_db_node_deref(ci->from_node);
3254 }
3255 if (ci->to_node) {
3256 ecm_db_node_deref(ci->to_node);
3257 }
3258 if (ci->from_nat_node) {
3259 ecm_db_node_deref(ci->from_nat_node);
3260 }
3261 if (ci->to_nat_node) {
3262 ecm_db_node_deref(ci->to_nat_node);
3263 }
Shyam Sunder317ca912016-01-22 16:51:28 +05303264
Ben Menchaca84f36632014-02-28 20:57:38 +00003265 /*
3266 * Remove references to the interfaces in our heirarchy lists
3267 */
3268 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3269 DEBUG_TRACE("%p: from interface %d remove: %p\n", ci, i, ci->from_interfaces[i]);
3270 ecm_db_iface_deref(ci->from_interfaces[i]);
3271 }
3272 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3273 DEBUG_TRACE("%p: to interface %d remove: %p\n", ci, i, ci->to_interfaces[i]);
3274 ecm_db_iface_deref(ci->to_interfaces[i]);
3275 }
3276 for (i = ci->from_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3277 DEBUG_TRACE("%p: from nat interface %d remove: %p\n", ci, i, ci->from_nat_interfaces[i]);
3278 ecm_db_iface_deref(ci->from_nat_interfaces[i]);
3279 }
3280 for (i = ci->to_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3281 DEBUG_TRACE("%p: to nat interface %d remove: %p\n", ci, i, ci->to_nat_interfaces[i]);
3282 ecm_db_iface_deref(ci->to_nat_interfaces[i]);
3283 }
3284
3285 /*
3286 * We can now destroy the instance
3287 */
3288 DEBUG_CLEAR_MAGIC(ci);
3289 kfree(ci);
3290
3291 /*
3292 * Decrease global connection count
3293 */
3294 spin_lock_bh(&ecm_db_lock);
3295 ecm_db_connection_count--;
3296 DEBUG_ASSERT(ecm_db_connection_count >= 0, "%p: connection count wrap\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00003297 spin_unlock_bh(&ecm_db_lock);
3298
Ben Menchaca84f36632014-02-28 20:57:38 +00003299 return 0;
3300}
3301EXPORT_SYMBOL(ecm_db_connection_deref);
3302
3303/*
3304 * ecm_db_mapping_deref()
3305 * Release ref to mapping, possibly removing it from the database and destroying it.
3306 */
3307int ecm_db_mapping_deref(struct ecm_db_mapping_instance *mi)
3308{
3309 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
3310
3311 spin_lock_bh(&ecm_db_lock);
3312 mi->refs--;
3313 DEBUG_TRACE("%p: mapping deref %d\n", mi, mi->refs);
3314 DEBUG_ASSERT(mi->refs >= 0, "%p: ref wrap\n", mi);
3315
3316 if (mi->refs > 0) {
3317 int refs = mi->refs;
3318 spin_unlock_bh(&ecm_db_lock);
3319 return refs;
3320 }
3321
Gareth Williamsb5903892015-03-20 15:13:07 +00003322 DEBUG_ASSERT(!mi->tcp_from && !mi->udp_from && !mi->from, "%p: from not zero: %d, %d, %d\n",
3323 mi, mi->tcp_from, mi->udp_from, mi->from);
3324 DEBUG_ASSERT(!mi->tcp_to && !mi->udp_to && !mi->to, "%p: to not zero: %d, %d, %d\n",
3325 mi, mi->tcp_to, mi->udp_to, mi->to);
3326 DEBUG_ASSERT(!mi->tcp_nat_from && !mi->udp_nat_from && !mi->nat_from, "%p: nat_from not zero: %d, %d, %d\n",
3327 mi, mi->tcp_nat_from, mi->udp_nat_from, mi->nat_from);
3328 DEBUG_ASSERT(!mi->tcp_nat_to && !mi->udp_nat_to && !mi->nat_to, "%p: nat_to not zero: %d, %d, %d\n",
3329 mi, mi->tcp_nat_to, mi->udp_nat_to, mi->nat_to);
3330
3331#ifdef ECM_DB_XREF_ENABLE
3332 DEBUG_ASSERT(!mi->from_connections, "%p: from not null: %p\n", mi, mi->from_connections);
3333 DEBUG_ASSERT(!mi->to_connections, "%p: to not null: %p\n", mi, mi->to_connections);
3334 DEBUG_ASSERT(!mi->from_nat_connections, "%p: nat_from not null: %p\n", mi, mi->from_nat_connections);
3335 DEBUG_ASSERT(!mi->to_nat_connections, "%p: nat_to not null: %p\n", mi, mi->to_nat_connections);
3336#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003337
3338 /*
3339 * Remove from database if inserted
3340 */
3341 if (!mi->flags & ECM_DB_MAPPING_FLAGS_INSERTED) {
3342 spin_unlock_bh(&ecm_db_lock);
3343 } else {
3344 struct ecm_db_listener_instance *li;
3345
3346 /*
3347 * Remove from the global list
3348 */
3349 if (!mi->prev) {
3350 DEBUG_ASSERT(ecm_db_mappings == mi, "%p: mapping table bad\n", mi);
3351 ecm_db_mappings = mi->next;
3352 } else {
3353 mi->prev->next = mi->next;
3354 }
3355 if (mi->next) {
3356 mi->next->prev = mi->prev;
3357 }
3358
3359 /*
3360 * Unlink it from the mapping hash table
3361 */
3362 if (!mi->hash_prev) {
3363 DEBUG_ASSERT(ecm_db_mapping_table[mi->hash_index] == mi, "%p: hash table bad\n", mi);
3364 ecm_db_mapping_table[mi->hash_index] = mi->hash_next;
3365 } else {
3366 mi->hash_prev->hash_next = mi->hash_next;
3367 }
3368 if (mi->hash_next) {
3369 mi->hash_next->hash_prev = mi->hash_prev;
3370 }
3371 mi->hash_next = NULL;
3372 mi->hash_prev = NULL;
3373 ecm_db_mapping_table_lengths[mi->hash_index]--;
3374 DEBUG_ASSERT(ecm_db_mapping_table_lengths[mi->hash_index] >= 0, "%p: invalid table len %d\n", mi, ecm_db_mapping_table_lengths[mi->hash_index]);
3375
Gareth Williamsb5903892015-03-20 15:13:07 +00003376#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003377 /*
3378 * Unlink it from the host mapping list
3379 */
3380 if (!mi->mapping_prev) {
3381 DEBUG_ASSERT(mi->host->mappings == mi, "%p: mapping table bad\n", mi);
3382 mi->host->mappings = mi->mapping_next;
3383 } else {
3384 mi->mapping_prev->mapping_next = mi->mapping_next;
3385 }
3386 if (mi->mapping_next) {
3387 mi->mapping_next->mapping_prev = mi->mapping_prev;
3388 }
3389 mi->mapping_next = NULL;
3390 mi->mapping_prev = NULL;
3391
3392 mi->host->mapping_count--;
Gareth Williamsb5903892015-03-20 15:13:07 +00003393#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003394 spin_unlock_bh(&ecm_db_lock);
3395
3396 /*
3397 * Throw removed event to listeners
3398 */
3399 DEBUG_TRACE("%p: Throw mapping removed event\n", mi);
3400 li = ecm_db_listeners_get_and_ref_first();
3401 while (li) {
3402 struct ecm_db_listener_instance *lin;
3403 if (li->mapping_removed) {
3404 li->mapping_removed(li->arg, mi);
3405 }
3406
3407 /*
3408 * Get next listener
3409 */
3410 lin = ecm_db_listener_get_and_ref_next(li);
3411 ecm_db_listener_deref(li);
3412 li = lin;
3413 }
3414 }
3415
3416 /*
3417 * Throw final event
3418 */
3419 if (mi->final) {
3420 mi->final(mi->arg);
3421 }
3422
3423 /*
3424 * Now release the host instance if the mapping had one
3425 */
3426 if (mi->host) {
3427 ecm_db_host_deref(mi->host);
3428 }
3429
3430 /*
3431 * We can now destroy the instance
3432 */
3433 DEBUG_CLEAR_MAGIC(mi);
3434 kfree(mi);
3435
3436 /*
3437 * Decrease global mapping count
3438 */
3439 spin_lock_bh(&ecm_db_lock);
3440 ecm_db_mapping_count--;
3441 DEBUG_ASSERT(ecm_db_mapping_count >= 0, "%p: mapping count wrap\n", mi);
Ben Menchaca84f36632014-02-28 20:57:38 +00003442 spin_unlock_bh(&ecm_db_lock);
3443
Ben Menchaca84f36632014-02-28 20:57:38 +00003444 return 0;
3445}
3446EXPORT_SYMBOL(ecm_db_mapping_deref);
3447
3448/*
3449 * ecm_db_host_deref()
3450 * Release a ref to a host instance, possibly causing removal from the database and destruction of the instance
3451 */
3452int ecm_db_host_deref(struct ecm_db_host_instance *hi)
3453{
3454 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
3455
3456 spin_lock_bh(&ecm_db_lock);
3457 hi->refs--;
3458 DEBUG_TRACE("%p: host deref %d\n", hi, hi->refs);
3459 DEBUG_ASSERT(hi->refs >= 0, "%p: ref wrap\n", hi);
3460
3461 if (hi->refs > 0) {
3462 int refs = hi->refs;
3463 spin_unlock_bh(&ecm_db_lock);
3464 return refs;
3465 }
3466
Gareth Williamsb5903892015-03-20 15:13:07 +00003467#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003468 DEBUG_ASSERT((hi->mappings == NULL) && (hi->mapping_count == 0), "%p: mappings not null\n", hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00003469#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003470
3471 /*
3472 * Remove from database if inserted
3473 */
3474 if (!hi->flags & ECM_DB_HOST_FLAGS_INSERTED) {
3475 spin_unlock_bh(&ecm_db_lock);
3476 } else {
3477 struct ecm_db_listener_instance *li;
3478
3479 /*
3480 * Remove from the global list
3481 */
3482 if (!hi->prev) {
3483 DEBUG_ASSERT(ecm_db_hosts == hi, "%p: host table bad\n", hi);
3484 ecm_db_hosts = hi->next;
3485 } else {
3486 hi->prev->next = hi->next;
3487 }
3488 if (hi->next) {
3489 hi->next->prev = hi->prev;
3490 }
3491
3492 /*
3493 * Unlink it from the host hash table
3494 */
3495 if (!hi->hash_prev) {
3496 DEBUG_ASSERT(ecm_db_host_table[hi->hash_index] == hi, "%p: hash table bad\n", hi);
3497 ecm_db_host_table[hi->hash_index] = hi->hash_next;
3498 } else {
3499 hi->hash_prev->hash_next = hi->hash_next;
3500 }
3501 if (hi->hash_next) {
3502 hi->hash_next->hash_prev = hi->hash_prev;
3503 }
3504 hi->hash_next = NULL;
3505 hi->hash_prev = NULL;
3506 ecm_db_host_table_lengths[hi->hash_index]--;
3507 DEBUG_ASSERT(ecm_db_host_table_lengths[hi->hash_index] >= 0, "%p: invalid table len %d\n", hi, ecm_db_host_table_lengths[hi->hash_index]);
3508
Ben Menchaca84f36632014-02-28 20:57:38 +00003509 spin_unlock_bh(&ecm_db_lock);
3510
3511 /*
3512 * Throw removed event to listeners
3513 */
3514 DEBUG_TRACE("%p: Throw host removed event\n", hi);
3515 li = ecm_db_listeners_get_and_ref_first();
3516 while (li) {
3517 struct ecm_db_listener_instance *lin;
3518 if (li->host_removed) {
3519 li->host_removed(li->arg, hi);
3520 }
3521
3522 /*
3523 * Get next listener
3524 */
3525 lin = ecm_db_listener_get_and_ref_next(li);
3526 ecm_db_listener_deref(li);
3527 li = lin;
3528 }
3529 }
3530
3531 /*
3532 * Throw final event
3533 */
3534 if (hi->final) {
3535 hi->final(hi->arg);
3536 }
3537
3538 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00003539 * We can now destroy the instance
3540 */
3541 DEBUG_CLEAR_MAGIC(hi);
3542 kfree(hi);
3543
3544 /*
3545 * Decrease global host count
3546 */
3547 spin_lock_bh(&ecm_db_lock);
3548 ecm_db_host_count--;
3549 DEBUG_ASSERT(ecm_db_host_count >= 0, "%p: host count wrap\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00003550 spin_unlock_bh(&ecm_db_lock);
3551
Ben Menchaca84f36632014-02-28 20:57:38 +00003552 return 0;
3553}
3554EXPORT_SYMBOL(ecm_db_host_deref);
3555
3556/*
3557 * ecm_db_node_deref()
3558 * Deref a node. Removing it on the last ref and destroying it.
3559 */
3560int ecm_db_node_deref(struct ecm_db_node_instance *ni)
3561{
3562 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
3563
3564 spin_lock_bh(&ecm_db_lock);
3565 ni->refs--;
3566 DEBUG_TRACE("%p: node deref %d\n", ni, ni->refs);
3567 DEBUG_ASSERT(ni->refs >= 0, "%p: ref wrap\n", ni);
3568
3569 if (ni->refs > 0) {
3570 int refs = ni->refs;
3571 spin_unlock_bh(&ecm_db_lock);
3572 return refs;
3573 }
3574
Gareth Williamsb5903892015-03-20 15:13:07 +00003575#ifdef ECM_DB_XREF_ENABLE
Gareth Williams90f2a282014-08-27 15:56:25 +01003576 DEBUG_ASSERT((ni->from_connections == NULL) && (ni->from_connections_count == 0), "%p: from_connections not null\n", ni);
3577 DEBUG_ASSERT((ni->to_connections == NULL) && (ni->to_connections_count == 0), "%p: to_connections not null\n", ni);
3578 DEBUG_ASSERT((ni->from_nat_connections == NULL) && (ni->from_nat_connections_count == 0), "%p: from_nat_connections not null\n", ni);
3579 DEBUG_ASSERT((ni->to_nat_connections == NULL) && (ni->to_nat_connections_count == 0), "%p: to_nat_connections not null\n", ni);
Gareth Williamsb5903892015-03-20 15:13:07 +00003580#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003581
3582 /*
3583 * Remove from database if inserted
3584 */
3585 if (!ni->flags & ECM_DB_NODE_FLAGS_INSERTED) {
3586 spin_unlock_bh(&ecm_db_lock);
3587 } else {
3588 struct ecm_db_listener_instance *li;
3589
3590 /*
3591 * Remove from the global list
3592 */
3593 if (!ni->prev) {
3594 DEBUG_ASSERT(ecm_db_nodes == ni, "%p: node table bad\n", ni);
3595 ecm_db_nodes = ni->next;
3596 } else {
3597 ni->prev->next = ni->next;
3598 }
3599 if (ni->next) {
3600 ni->next->prev = ni->prev;
3601 }
3602
3603 /*
3604 * Link out of hash table
3605 */
3606 if (!ni->hash_prev) {
3607 DEBUG_ASSERT(ecm_db_node_table[ni->hash_index] == ni, "%p: hash table bad\n", ni);
3608 ecm_db_node_table[ni->hash_index] = ni->hash_next;
3609 } else {
3610 ni->hash_prev->hash_next = ni->hash_next;
3611 }
3612 if (ni->hash_next) {
3613 ni->hash_next->hash_prev = ni->hash_prev;
3614 }
3615 ni->hash_next = NULL;
3616 ni->hash_prev = NULL;
3617 ecm_db_node_table_lengths[ni->hash_index]--;
3618 DEBUG_ASSERT(ecm_db_node_table_lengths[ni->hash_index] >= 0, "%p: invalid table len %d\n", ni, ecm_db_node_table_lengths[ni->hash_index]);
3619
Gareth Williamsb5903892015-03-20 15:13:07 +00003620#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003621 /*
3622 * Unlink it from the iface node list
3623 */
3624 if (!ni->node_prev) {
3625 DEBUG_ASSERT(ni->iface->nodes == ni, "%p: nodes table bad\n", ni);
3626 ni->iface->nodes = ni->node_next;
3627 } else {
3628 ni->node_prev->node_next = ni->node_next;
3629 }
3630 if (ni->node_next) {
3631 ni->node_next->node_prev = ni->node_prev;
3632 }
3633 ni->node_next = NULL;
3634 ni->node_prev = NULL;
3635 ni->iface->node_count--;
Gareth Williamsb5903892015-03-20 15:13:07 +00003636#endif
3637
Ben Menchaca84f36632014-02-28 20:57:38 +00003638 spin_unlock_bh(&ecm_db_lock);
3639
3640 /*
3641 * Throw removed event to listeners
3642 */
3643 DEBUG_TRACE("%p: Throw node removed event\n", ni);
3644 li = ecm_db_listeners_get_and_ref_first();
3645 while (li) {
3646 struct ecm_db_listener_instance *lin;
3647 if (li->node_removed) {
3648 li->node_removed(li->arg, ni);
3649 }
3650
3651 /*
3652 * Get next listener
3653 */
3654 lin = ecm_db_listener_get_and_ref_next(li);
3655 ecm_db_listener_deref(li);
3656 li = lin;
3657 }
3658 }
3659
3660 /*
3661 * Throw final event
3662 */
3663 if (ni->final) {
3664 ni->final(ni->arg);
3665 }
3666
3667 /*
3668 * Now release the iface instance if the node had one
3669 */
3670 if (ni->iface) {
3671 ecm_db_iface_deref(ni->iface);
3672 }
3673
3674 /*
3675 * We can now destroy the instance
3676 */
3677 DEBUG_CLEAR_MAGIC(ni);
3678 kfree(ni);
3679
3680 /*
3681 * Decrease global node count
3682 */
3683 spin_lock_bh(&ecm_db_lock);
3684 ecm_db_node_count--;
3685 DEBUG_ASSERT(ecm_db_node_count >= 0, "%p: node count wrap\n", ni);
Ben Menchaca84f36632014-02-28 20:57:38 +00003686 spin_unlock_bh(&ecm_db_lock);
3687
Ben Menchaca84f36632014-02-28 20:57:38 +00003688 return 0;
3689}
3690EXPORT_SYMBOL(ecm_db_node_deref);
3691
3692/*
3693 * ecm_db_iface_deref()
3694 * Deref a interface instance, removing it from the database on the last ref release
3695 */
3696int ecm_db_iface_deref(struct ecm_db_iface_instance *ii)
3697{
3698 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
3699
3700 /*
3701 * Decrement reference count
3702 */
3703 spin_lock_bh(&ecm_db_lock);
3704 ii->refs--;
3705 DEBUG_TRACE("%p: iface deref %d\n", ii, ii->refs);
3706 DEBUG_ASSERT(ii->refs >= 0, "%p: ref wrap\n", ii);
3707
3708 if (ii->refs > 0) {
3709 int refs = ii->refs;
3710 spin_unlock_bh(&ecm_db_lock);
3711 return refs;
3712 }
3713
Gareth Williamsb5903892015-03-20 15:13:07 +00003714#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003715 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00003716#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003717
3718 /*
3719 * Remove from database if inserted
3720 */
3721 if (!ii->flags & ECM_DB_IFACE_FLAGS_INSERTED) {
3722 spin_unlock_bh(&ecm_db_lock);
3723 } else {
3724 struct ecm_db_listener_instance *li;
3725
3726 /*
3727 * Remove from the global list
3728 */
3729 if (!ii->prev) {
3730 DEBUG_ASSERT(ecm_db_interfaces == ii, "%p: interface table bad\n", ii);
3731 ecm_db_interfaces = ii->next;
3732 } else {
3733 ii->prev->next = ii->next;
3734 }
3735 if (ii->next) {
3736 ii->next->prev = ii->prev;
3737 }
3738
3739 /*
3740 * Link out of hash table
3741 */
3742 if (!ii->hash_prev) {
3743 DEBUG_ASSERT(ecm_db_iface_table[ii->hash_index] == ii, "%p: hash table bad got %p for hash index %u\n", ii, ecm_db_iface_table[ii->hash_index], ii->hash_index);
3744 ecm_db_iface_table[ii->hash_index] = ii->hash_next;
3745 } else {
3746 ii->hash_prev->hash_next = ii->hash_next;
3747 }
3748 if (ii->hash_next) {
3749 ii->hash_next->hash_prev = ii->hash_prev;
3750 }
3751 ii->hash_next = NULL;
3752 ii->hash_prev = NULL;
3753 ecm_db_iface_table_lengths[ii->hash_index]--;
3754 DEBUG_ASSERT(ecm_db_iface_table_lengths[ii->hash_index] >= 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[ii->hash_index]);
Murat Sezgin91c5d712015-06-12 15:16:22 -07003755
3756 /*
3757 * Link out of interface identifier hash table
3758 */
3759 if (!ii->iface_id_hash_prev) {
3760 DEBUG_ASSERT(ecm_db_iface_id_table[ii->iface_id_hash_index] == ii, "%p: hash table bad got %p for hash index %u\n", ii, ecm_db_iface_id_table[ii->iface_id_hash_index], ii->iface_id_hash_index);
3761 ecm_db_iface_id_table[ii->iface_id_hash_index] = ii->iface_id_hash_next;
3762 } else {
3763 ii->iface_id_hash_prev->iface_id_hash_next = ii->iface_id_hash_next;
3764 }
3765 if (ii->iface_id_hash_next) {
3766 ii->iface_id_hash_next->iface_id_hash_prev = ii->iface_id_hash_prev;
3767 }
3768 ii->iface_id_hash_next = NULL;
3769 ii->iface_id_hash_prev = NULL;
3770 ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]--;
3771 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[ii->iface_id_hash_index] >= 0, "%p: invalid table len %d\n", ii, ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]);
Ben Menchaca84f36632014-02-28 20:57:38 +00003772 spin_unlock_bh(&ecm_db_lock);
3773
3774 /*
3775 * Throw removed event to listeners
3776 */
3777 DEBUG_TRACE("%p: Throw iface removed event\n", ii);
3778 li = ecm_db_listeners_get_and_ref_first();
3779 while (li) {
3780 struct ecm_db_listener_instance *lin;
3781 if (li->iface_removed) {
3782 li->iface_removed(li->arg, ii);
3783 }
3784
3785 /*
3786 * Get next listener
3787 */
3788 lin = ecm_db_listener_get_and_ref_next(li);
3789 ecm_db_listener_deref(li);
3790 li = lin;
3791 }
3792 }
3793
3794 /*
3795 * Throw final event
3796 */
3797 if (ii->final) {
3798 ii->final(ii->arg);
3799 }
3800
3801 /*
3802 * We can now destroy the instance
3803 */
3804 DEBUG_CLEAR_MAGIC(ii);
3805 kfree(ii);
3806
3807 /*
3808 * Decrease global interface count
3809 */
3810 spin_lock_bh(&ecm_db_lock);
3811 ecm_db_iface_count--;
3812 DEBUG_ASSERT(ecm_db_iface_count >= 0, "%p: iface count wrap\n", ii);
Ben Menchaca84f36632014-02-28 20:57:38 +00003813 spin_unlock_bh(&ecm_db_lock);
3814
Ben Menchaca84f36632014-02-28 20:57:38 +00003815 return 0;
3816}
3817EXPORT_SYMBOL(ecm_db_iface_deref);
3818
3819/*
3820 * ecm_db_listener_deref()
3821 * Release reference to listener.
3822 *
3823 * On final reference release listener shall be removed from the database.
3824 */
3825int ecm_db_listener_deref(struct ecm_db_listener_instance *li)
3826{
3827 struct ecm_db_listener_instance *cli;
3828 struct ecm_db_listener_instance **cli_prev;
3829
3830 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
3831
3832 spin_lock_bh(&ecm_db_lock);
3833 li->refs--;
3834 DEBUG_ASSERT(li->refs >= 0, "%p: ref wrap\n", li);
3835 if (li->refs > 0) {
3836 int refs;
3837 refs = li->refs;
3838 spin_unlock_bh(&ecm_db_lock);
3839 return refs;
3840 }
3841
3842 /*
3843 * Instance is to be removed and destroyed.
3844 * Link the listener out of the listener list.
3845 */
3846 cli = ecm_db_listeners;
3847 cli_prev = &ecm_db_listeners;
3848 while (cli) {
3849 if (cli == li) {
3850 *cli_prev = cli->next;
3851 break;
3852 }
3853 cli_prev = &cli->next;
3854 cli = cli->next;
3855 }
3856 DEBUG_ASSERT(cli, "%p: not found\n", li);
3857 spin_unlock_bh(&ecm_db_lock);
3858
3859 /*
3860 * Invoke final callback
3861 */
3862 if (li->final) {
3863 li->final(li->arg);
3864 }
3865 DEBUG_CLEAR_MAGIC(li);
3866 kfree(li);
3867
3868 /*
3869 * Decrease global listener count
3870 */
3871 spin_lock_bh(&ecm_db_lock);
3872 ecm_db_listeners_count--;
3873 DEBUG_ASSERT(ecm_db_listeners_count >= 0, "%p: listener count wrap\n", li);
Ben Menchaca84f36632014-02-28 20:57:38 +00003874 spin_unlock_bh(&ecm_db_lock);
3875
Ben Menchaca84f36632014-02-28 20:57:38 +00003876 return 0;
3877}
3878EXPORT_SYMBOL(ecm_db_listener_deref);
3879
3880/*
3881 * ecm_db_connection_defunct_all()
3882 * Make defunct ALL connections.
3883 *
3884 * This API is typically used in shutdown situations commanded by the user.
3885 * NOTE: Ensure all front ends are stopped to avoid further connections being created while this is running.
3886 */
3887void ecm_db_connection_defunct_all(void)
3888{
3889 struct ecm_db_connection_instance *ci;
3890
3891 DEBUG_INFO("Defuncting all\n");
3892
3893 /*
3894 * Iterate all connections
3895 */
3896 ci = ecm_db_connections_get_and_ref_first();
3897 while (ci) {
3898 struct ecm_db_connection_instance *cin;
3899
3900 DEBUG_TRACE("%p: defunct\n", ci);
3901 ecm_db_connection_make_defunct(ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05303902
Ben Menchaca84f36632014-02-28 20:57:38 +00003903 cin = ecm_db_connection_get_and_ref_next(ci);
3904 ecm_db_connection_deref(ci);
3905 ci = cin;
3906 }
3907 DEBUG_INFO("Defuncting complete\n");
3908}
3909EXPORT_SYMBOL(ecm_db_connection_defunct_all);
3910
3911/*
3912 * ecm_db_connection_generate_hash_index()
3913 * Calculate the hash index.
3914 *
3915 * Note: The hash we produce is symmetric - i.e. we can swap the "from" and "to"
3916 * details without generating a different hash index!
3917 */
3918static inline ecm_db_connection_hash_t ecm_db_connection_generate_hash_index(ip_addr_t host1_addr, uint32_t host1_port, ip_addr_t host2_addr, uint32_t host2_port, int protocol)
3919{
Gareth Williams54d15d92015-04-24 19:28:27 +01003920 uint32_t hah1;
3921 uint32_t hah2;
3922 uint32_t ht1;
Ben Menchaca84f36632014-02-28 20:57:38 +00003923 uint32_t hash_val;
3924
3925 /*
3926 * The hash function only uses both host 1 address/port, host 2 address/port
3927 * and protocol fields.
3928 */
Gareth Williams54d15d92015-04-24 19:28:27 +01003929 ECM_IP_ADDR_HASH(hah1, host1_addr);
3930 ECM_IP_ADDR_HASH(hah2, host2_addr);
3931 ht1 = (u32)hah1 + host1_port + hah2 + host2_port + (uint32_t)protocol;
3932 hash_val = (uint32_t)jhash_1word(ht1, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00003933 return (ecm_db_connection_hash_t)(hash_val & (ECM_DB_CONNECTION_HASH_SLOTS - 1));
3934}
3935
3936/*
3937 * ecm_db_connection_generate_serial_hash_index()
3938 * Calculate the serial hash index.
3939 */
3940static inline ecm_db_connection_serial_hash_t ecm_db_connection_generate_serial_hash_index(uint32_t serial)
3941{
Gareth Williams54d15d92015-04-24 19:28:27 +01003942 uint32_t hash_val;
3943 hash_val = (uint32_t)jhash_1word(serial, ecm_db_jhash_rnd);
3944
3945 return (ecm_db_connection_serial_hash_t)(hash_val & (ECM_DB_CONNECTION_SERIAL_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00003946}
3947
Shyam Sunder1f037262015-05-18 20:04:13 +05303948#ifdef ECM_MULTICAST_ENABLE
3949/*
3950 * ecm_db_multicast_generate_hash_index()
3951 * Calculate the hash index given a multicast group address.
3952 */
3953static inline ecm_db_multicast_tuple_instance_hash_t ecm_db_multicast_generate_hash_index(ip_addr_t address)
3954{
3955 uint32_t temp;
3956 uint32_t hash_val;
3957
3958 if (ECM_IP_ADDR_IS_V4(address)){
3959 temp = (uint32_t)address[0];
3960 } else {
3961 temp = (uint32_t)address[3];
3962 }
3963
3964 hash_val = (uint32_t)jhash_1word(temp, ecm_db_jhash_rnd);
3965
3966 return (ecm_db_multicast_tuple_instance_hash_t)(hash_val & (ECM_DB_MULTICAST_TUPLE_INSTANCE_HASH_SLOTS - 1));
3967}
3968#endif
3969
Ben Menchaca84f36632014-02-28 20:57:38 +00003970/*
3971 * ecm_db_mapping_generate_hash_index()
3972 * Calculate the hash index.
3973 */
3974static inline ecm_db_mapping_hash_t ecm_db_mapping_generate_hash_index(ip_addr_t address, uint32_t port)
3975{
Gareth Williams54d15d92015-04-24 19:28:27 +01003976 uint32_t tuple;
Ben Menchaca84f36632014-02-28 20:57:38 +00003977 uint32_t hash_val;
3978
Gareth Williams54d15d92015-04-24 19:28:27 +01003979 ECM_IP_ADDR_HASH(tuple, address);
3980 hash_val = (uint32_t)jhash_2words(tuple, port, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00003981 return (ecm_db_mapping_hash_t)(hash_val & (ECM_DB_MAPPING_HASH_SLOTS - 1));
3982}
3983
3984/*
3985 * ecm_db_host_generate_hash_index()
3986 * Calculate the hash index.
3987 */
3988static inline ecm_db_host_hash_t ecm_db_host_generate_hash_index(ip_addr_t address)
3989{
Gareth Williams54d15d92015-04-24 19:28:27 +01003990 uint32_t tuple;
Ben Menchaca84f36632014-02-28 20:57:38 +00003991 uint32_t hash_val;
3992
Gareth Williams54d15d92015-04-24 19:28:27 +01003993 ECM_IP_ADDR_HASH(tuple, address);
3994 hash_val = (uint32_t)jhash_1word(tuple, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00003995 return (ecm_db_host_hash_t)(hash_val & (ECM_DB_HOST_HASH_SLOTS - 1));
3996}
3997
3998/*
3999 * ecm_db_node_generate_hash_index()
4000 * Calculate the hash index.
4001 */
4002static inline ecm_db_node_hash_t ecm_db_node_generate_hash_index(uint8_t *address)
4003{
4004 uint32_t hash_val;
4005
Gareth Williams54d15d92015-04-24 19:28:27 +01004006 hash_val = (uint32_t)jhash(address, 6, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00004007 hash_val &= (ECM_DB_NODE_HASH_SLOTS - 1);
4008
4009 return (ecm_db_node_hash_t)hash_val;
4010}
4011
Murat Sezgin91c5d712015-06-12 15:16:22 -07004012/*
4013 * ecm_db_iface_id_generate_hash_index()
4014 * Calculate the hash index based on interface identifier.
4015 */
4016static inline ecm_db_iface_id_hash_t ecm_db_iface_id_generate_hash_index(int32_t interface_id)
4017{
4018 uint32_t hash_val;
4019
4020 hash_val = (uint32_t)jhash_1word((uint32_t)interface_id, ecm_db_jhash_rnd);
4021 return (ecm_db_iface_id_hash_t)(hash_val & (ECM_DB_IFACE_ID_HASH_SLOTS - 1));
4022}
4023
Murat Sezginbde55f92015-03-11 16:44:11 -07004024#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004025/*
4026 * ecm_db_iface_generate_hash_index_sit()
4027 * Calculate the hash index.
4028 */
4029static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_sit(ip_addr_t saddr, ip_addr_t daddr)
4030{
Gareth Williams54d15d92015-04-24 19:28:27 +01004031 uint32_t tuple1;
4032 uint32_t tuple2;
Ben Menchaca84f36632014-02-28 20:57:38 +00004033 uint32_t hash_val;
4034
Gareth Williams54d15d92015-04-24 19:28:27 +01004035 ECM_IP_ADDR_HASH(tuple1, saddr);
4036 ECM_IP_ADDR_HASH(tuple2, daddr);
4037 hash_val = (uint32_t)jhash_2words(tuple1, tuple2, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00004038 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
4039}
Murat Sezginbde55f92015-03-11 16:44:11 -07004040#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004041
Murat Sezginc1402562015-03-12 12:32:20 -07004042#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +00004043#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004044/*
4045 * ecm_db_iface_generate_hash_index_tunipip6()
4046 * Calculate the hash index.
4047 */
4048static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_tunipip6(ip_addr_t saddr, ip_addr_t daddr)
4049{
Gareth Williams54d15d92015-04-24 19:28:27 +01004050 uint32_t tuple1;
4051 uint32_t tuple2;
Ben Menchaca84f36632014-02-28 20:57:38 +00004052 uint32_t hash_val;
4053
Gareth Williams54d15d92015-04-24 19:28:27 +01004054 ECM_IP_ADDR_HASH(tuple1, saddr);
4055 ECM_IP_ADDR_HASH(tuple2, daddr);
4056 hash_val = (uint32_t)jhash_2words(tuple1, tuple2, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00004057 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
4058}
Murat Sezginc1402562015-03-12 12:32:20 -07004059#endif
Gareth Williams8ac34292015-03-17 14:06:58 +00004060#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004061
4062/*
4063 * ecm_db_iface_generate_hash_index_ethernet()
4064 * Calculate the hash index.
4065 */
4066static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_ethernet(uint8_t *address)
4067{
Gareth Williams54d15d92015-04-24 19:28:27 +01004068 uint32_t hash_val;
4069 hash_val = (uint32_t)jhash(address, 6, ecm_db_jhash_rnd);
4070 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00004071}
4072
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304073#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004074/*
4075 * ecm_db_iface_generate_hash_index_pppoe()
4076 * Calculate the hash index.
4077 */
4078static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pppoe(uint16_t pppoe_session_id)
4079{
Gareth Williams54d15d92015-04-24 19:28:27 +01004080 uint32_t hash_val;
4081 hash_val = (uint32_t)jhash_1word((uint32_t)pppoe_session_id, ecm_db_jhash_rnd);
4082 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00004083}
Murat Sezginaad635c2015-03-06 16:11:41 -08004084#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004085
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304086#ifdef ECM_INTERFACE_L2TPV2_ENABLE
4087/*
4088 * ecm_db_iface_generate_hash_index_pppol2tpv2()
4089 * Calculate the hash index.
4090 */
4091static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pppol2tpv2(uint32_t pppol2tpv2_tunnel_id, uint32_t pppol2tpv2_session_id)
4092{
4093 uint32_t hash_val;
4094 hash_val = (uint32_t)jhash_2words(pppol2tpv2_tunnel_id, pppol2tpv2_session_id, ecm_db_jhash_rnd);
4095 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
4096}
4097
4098#endif
4099
Shyam Sunder23f2e542015-09-28 14:56:49 +05304100#ifdef ECM_INTERFACE_PPTP_ENABLE
4101/*
4102 * ecm_db_iface_generate_hash_index_pptp()
4103 * Calculate the hash index.
4104 */
4105static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pptp(uint16_t pptp_src_call_id, uint16_t pptp_dst_call_id)
4106{
4107 uint32_t hash_val;
4108 hash_val = (uint32_t)jhash_2words(pptp_src_call_id, pptp_dst_call_id, ecm_db_jhash_rnd);
4109 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
4110}
4111#endif
ratheesh kannothcfdcb332015-12-24 07:19:18 +05304112
4113#ifdef ECM_INTERFACE_MAP_T_ENABLE
4114/*
4115 * ecm_db_iface_generate_hash_index_map_t()
4116 * Calculate the hash index.
4117 */
4118static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_map_t(int if_index)
4119{
4120 uint32_t hash_val;
4121 hash_val = (uint32_t)jhash_1word(if_index, ecm_db_jhash_rnd);
4122 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
4123}
4124#endif
4125
Ben Menchaca84f36632014-02-28 20:57:38 +00004126/*
4127 * ecm_db_iface_generate_hash_index_unknown()
4128 * Calculate the hash index.
4129 */
4130static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_unknown(uint32_t os_specific_ident)
4131{
Gareth Williams54d15d92015-04-24 19:28:27 +01004132 uint32_t hash_val;
4133 hash_val = (uint32_t)jhash_1word(os_specific_ident, ecm_db_jhash_rnd);
4134 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00004135}
4136
4137/*
4138 * ecm_db_iface_generate_hash_index_loopback()
4139 * Calculate the hash index.
4140 */
4141static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_loopback(uint32_t os_specific_ident)
4142{
Gareth Williams54d15d92015-04-24 19:28:27 +01004143 uint32_t hash_val;
4144 hash_val = (uint32_t)jhash_1word(os_specific_ident, ecm_db_jhash_rnd);
4145 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00004146}
4147
Murat Sezgin69a27532015-03-12 14:09:40 -07004148#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004149/*
4150 * ecm_db_iface_generate_hash_index_ipsec_tunnel()
4151 * Calculate the hash index.
4152 * GGG TODO Flesh this out using actual tunnel endpoint keys
4153 */
4154static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_ipsec_tunnel(uint32_t os_specific_ident)
4155{
Gareth Williams54d15d92015-04-24 19:28:27 +01004156 uint32_t hash_val;
4157 hash_val = (uint32_t)jhash_1word(os_specific_ident, ecm_db_jhash_rnd);
4158 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00004159}
Murat Sezgin69a27532015-03-12 14:09:40 -07004160#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004161
4162/*
4163 * ecm_db_host_find_and_ref()
4164 * Lookup and return a host reference if any
4165 */
4166struct ecm_db_host_instance *ecm_db_host_find_and_ref(ip_addr_t address)
4167{
4168 ecm_db_host_hash_t hash_index;
4169 struct ecm_db_host_instance *hi;
4170
4171 DEBUG_TRACE("Lookup host with addr " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(address));
4172
4173 /*
4174 * Compute the hash chain index and prepare to walk the chain
4175 */
4176 hash_index = ecm_db_host_generate_hash_index(address);
4177
4178 /*
4179 * Iterate the chain looking for a host with matching details
4180 */
4181 spin_lock_bh(&ecm_db_lock);
4182 hi = ecm_db_host_table[hash_index];
4183 while (hi) {
4184 if (!ECM_IP_ADDR_MATCH(hi->address, address)) {
4185 hi = hi->hash_next;
4186 continue;
4187 }
4188
4189 _ecm_db_host_ref(hi);
4190 spin_unlock_bh(&ecm_db_lock);
4191 DEBUG_TRACE("host found %p\n", hi);
4192 return hi;
4193 }
4194 spin_unlock_bh(&ecm_db_lock);
4195 DEBUG_TRACE("Host not found\n");
4196 return NULL;
4197}
4198EXPORT_SYMBOL(ecm_db_host_find_and_ref);
4199
4200/*
Murat Sezgina5f3de12016-08-02 17:29:30 -07004201 * ecm_db_node_is_mac_addr_equal()
4202 * Compares the node's mac address with the given mac address.
4203 */
4204bool ecm_db_node_is_mac_addr_equal(struct ecm_db_node_instance *ni, uint8_t *address)
4205{
4206 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
4207
4208 if (ecm_mac_addr_equal(ni->address, address)) {
4209 return false;
4210 }
4211
4212 return true;
4213}
4214EXPORT_SYMBOL(ecm_db_node_is_mac_addr_equal);
4215
4216/*
Ben Menchaca84f36632014-02-28 20:57:38 +00004217 * ecm_db_node_find_and_ref()
4218 * Lookup and return a node reference if any
4219 */
Murat Sezgina5f3de12016-08-02 17:29:30 -07004220struct ecm_db_node_instance *ecm_db_node_find_and_ref(uint8_t *address, struct ecm_db_iface_instance *ii)
Ben Menchaca84f36632014-02-28 20:57:38 +00004221{
4222 ecm_db_node_hash_t hash_index;
4223 struct ecm_db_node_instance *ni;
4224
Murat Sezgina5f3de12016-08-02 17:29:30 -07004225 DEBUG_TRACE("Lookup node with addr %pMi and iface %p\n", address, ii);
Ben Menchaca84f36632014-02-28 20:57:38 +00004226
4227 /*
4228 * Compute the hash chain index and prepare to walk the chain
4229 */
4230 hash_index = ecm_db_node_generate_hash_index(address);
4231
4232 /*
4233 * Iterate the chain looking for a host with matching details
4234 */
4235 spin_lock_bh(&ecm_db_lock);
4236 ni = ecm_db_node_table[hash_index];
4237 while (ni) {
4238 if (memcmp(ni->address, address, ETH_ALEN)) {
4239 ni = ni->hash_next;
4240 continue;
4241 }
4242
Murat Sezgina5f3de12016-08-02 17:29:30 -07004243 if (ni->iface != ii) {
4244 ni = ni->hash_next;
4245 continue;
4246 }
4247
Ben Menchaca84f36632014-02-28 20:57:38 +00004248 _ecm_db_node_ref(ni);
4249 spin_unlock_bh(&ecm_db_lock);
4250 DEBUG_TRACE("node found %p\n", ni);
4251 return ni;
4252 }
4253 spin_unlock_bh(&ecm_db_lock);
4254 DEBUG_TRACE("Node not found\n");
4255 return NULL;
4256}
4257EXPORT_SYMBOL(ecm_db_node_find_and_ref);
4258
4259/*
Murat Sezgina5f3de12016-08-02 17:29:30 -07004260 * ecm_db_node_chain_get_and_ref_first()
4261 * Gets and refs the first node in the chain of that mac address.
4262 */
4263struct ecm_db_node_instance *ecm_db_node_chain_get_and_ref_first(uint8_t *address)
4264{
4265 ecm_db_node_hash_t hash_index;
4266 struct ecm_db_node_instance *ni;
4267
4268 DEBUG_TRACE("Get the first node with addr %pMi in the chain\n", address);
4269
4270 /*
4271 * Compute the hash chain index.
4272 */
4273 hash_index = ecm_db_node_generate_hash_index(address);
4274
4275 spin_lock_bh(&ecm_db_lock);
4276 ni = ecm_db_node_table[hash_index];
4277 if (ni) {
4278 _ecm_db_node_ref(ni);
4279 }
4280 spin_unlock_bh(&ecm_db_lock);
4281
4282 return ni;
4283}
4284EXPORT_SYMBOL(ecm_db_node_chain_get_and_ref_first);
4285
4286/*
4287 * ecm_db_node_chain_get_and_ref_next()
4288 * Gets and refs the next node in the chain..
4289 */
4290struct ecm_db_node_instance *ecm_db_node_chain_get_and_ref_next(struct ecm_db_node_instance *ni)
4291{
4292 struct ecm_db_node_instance *nin;
4293 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
4294
4295 spin_lock_bh(&ecm_db_lock);
4296 nin = ni->hash_next;
4297 if (nin) {
4298 _ecm_db_node_ref(nin);
4299 }
4300 spin_unlock_bh(&ecm_db_lock);
4301 return nin;
4302}
4303EXPORT_SYMBOL(ecm_db_node_chain_get_and_ref_next);
4304
4305/*
Ben Menchaca84f36632014-02-28 20:57:38 +00004306 * ecm_db_iface_ethernet_address_get()
4307 * Obtain the ethernet address for an ethernet interface
4308 */
4309void ecm_db_iface_ethernet_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
4310{
4311 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4312 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_ETHERNET, "%p: Bad type, expected ethernet, actual: %d\n", ii, ii->type);
4313 spin_lock_bh(&ecm_db_lock);
4314 memcpy(address, ii->type_info.ethernet.address, sizeof(ii->type_info.ethernet.address));
4315 spin_unlock_bh(&ecm_db_lock);
4316}
4317EXPORT_SYMBOL(ecm_db_iface_ethernet_address_get);
4318
4319/*
Gareth Williams83125b12014-05-26 19:58:09 +01004320 * ecm_db_iface_bridge_address_get()
4321 * Obtain the ethernet address for a bridge interface
4322 */
4323void ecm_db_iface_bridge_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
4324{
4325 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4326 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_BRIDGE, "%p: Bad type, expected bridge, actual: %d\n", ii, ii->type);
4327 spin_lock_bh(&ecm_db_lock);
4328 memcpy(address, ii->type_info.bridge.address, sizeof(ii->type_info.bridge.address));
4329 spin_unlock_bh(&ecm_db_lock);
4330}
4331EXPORT_SYMBOL(ecm_db_iface_bridge_address_get);
4332
Gareth Williamsf98d4192015-03-11 16:55:41 +00004333/*
Shyam Sunder39e25672015-09-03 14:28:09 +05304334 * _ecm_db_iface_identifier_hash_table_insert_entry()
4335 * Calculate the hash index based on updated interface_identifier, and
4336 * re-insert into interface identifier chain.
4337 *
4338 * Note: Must take ecm_db_lock before calling this.
4339 */
4340static void _ecm_db_iface_identifier_hash_table_insert_entry(struct ecm_db_iface_instance *ii, int32_t interface_identifier)
4341{
4342 ecm_db_iface_id_hash_t iface_id_hash_index;
4343
4344 /*
4345 * Compute hash chain for insertion
4346 */
4347 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
4348 ii->iface_id_hash_index = iface_id_hash_index;
4349
4350 /*
4351 * Insert into interface identifier chain
4352 */
4353 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
4354 if (ecm_db_iface_id_table[iface_id_hash_index]) {
4355 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
4356 }
4357
4358 ecm_db_iface_id_table[iface_id_hash_index] = ii;
4359 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
4360 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
4361}
4362
4363/*
4364 * _ecm_db_iface_identifier_hash_table_remove_entry()
4365 * Remove an entry of a given interface instance from interface identifier chain.
4366 *
4367 * Note: Must take ecm_db_lock before calling this.
4368 */
4369static void _ecm_db_iface_identifier_hash_table_remove_entry(struct ecm_db_iface_instance *ii)
4370{
4371 /*
4372 * Remove from database if inserted
4373 */
4374 if (!ii->flags & ECM_DB_IFACE_FLAGS_INSERTED) {
4375 return;
4376 }
4377
4378 /*
4379 * Link out of interface identifier hash table
4380 */
4381 if (!ii->iface_id_hash_prev) {
4382 DEBUG_ASSERT(ecm_db_iface_id_table[ii->iface_id_hash_index] == ii, "%p: hash table bad got %p for hash index %u\n", ii, ecm_db_iface_id_table[ii->iface_id_hash_index], ii->iface_id_hash_index);
4383 ecm_db_iface_id_table[ii->iface_id_hash_index] = ii->iface_id_hash_next;
4384 } else {
4385 ii->iface_id_hash_prev->iface_id_hash_next = ii->iface_id_hash_next;
4386 }
4387
4388 if (ii->iface_id_hash_next) {
4389 ii->iface_id_hash_next->iface_id_hash_prev = ii->iface_id_hash_prev;
4390 }
4391
4392 ii->iface_id_hash_next = NULL;
4393 ii->iface_id_hash_prev = NULL;
4394 ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]--;
4395 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[ii->iface_id_hash_index] >= 0, "%p: invalid table len %d\n", ii, ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]);
4396}
4397
4398/*
4399 * ecm_db_iface_identifier_hash_table_entry_check_and_update()
4400 * Update the hash table entry of interface identifier hash table.
4401 * First remove the 'ii' from curent hash index position, re-calculate new hash and re-insert
4402 * the 'ii' at new hash index position into interface identifier hash table.
4403 */
4404void ecm_db_iface_identifier_hash_table_entry_check_and_update(struct ecm_db_iface_instance *ii, int32_t new_interface_identifier)
4405{
4406 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4407 spin_lock_bh(&ecm_db_lock);
4408 if (ii->interface_identifier == new_interface_identifier) {
4409 spin_unlock_bh(&ecm_db_lock);
4410 return;
4411 }
4412
4413 DEBUG_TRACE("%p: interface ifindex has changed Old %d, New %d \n", ii, ii->interface_identifier, new_interface_identifier);
4414 _ecm_db_iface_identifier_hash_table_remove_entry(ii);
4415 ii->interface_identifier = new_interface_identifier;
4416 _ecm_db_iface_identifier_hash_table_insert_entry(ii, new_interface_identifier);
4417 spin_unlock_bh(&ecm_db_lock);
4418}
4419EXPORT_SYMBOL(ecm_db_iface_identifier_hash_table_entry_check_and_update);
4420
4421/*
Murat Sezgin91c5d712015-06-12 15:16:22 -07004422 * ecm_db_iface_find_and_ref_by_interface_identifier()
4423 * Return an interface based on a hlos interface identifier
4424 */
4425struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_by_interface_identifier(int32_t interface_id)
4426{
4427 ecm_db_iface_id_hash_t hash_index;
4428 struct ecm_db_iface_instance *ii;
4429
4430 DEBUG_TRACE("Lookup database iface with interface_id %d\n", interface_id);
4431
4432 /*
4433 * Compute the hash chain index and prepare to walk the chain
4434 */
4435 hash_index = ecm_db_iface_id_generate_hash_index(interface_id);
4436
4437 /*
4438 * Iterate the chain looking for a host with matching details
4439 */
4440 spin_lock_bh(&ecm_db_lock);
4441 ii = ecm_db_iface_id_table[hash_index];
Murat Sezgin91c5d712015-06-12 15:16:22 -07004442 while (ii) {
Murat Sezgin91c5d712015-06-12 15:16:22 -07004443 if (ii->interface_identifier == interface_id) {
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004444 _ecm_db_iface_ref(ii);
4445 spin_unlock_bh(&ecm_db_lock);
Murat Sezgin91c5d712015-06-12 15:16:22 -07004446 DEBUG_TRACE("iface found %p\n", ii);
4447 return ii;
4448 }
4449
4450 /*
4451 * Try next
4452 */
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004453 ii = ii->iface_id_hash_next;
Murat Sezgin91c5d712015-06-12 15:16:22 -07004454 }
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004455 spin_unlock_bh(&ecm_db_lock);
Murat Sezgin91c5d712015-06-12 15:16:22 -07004456 DEBUG_TRACE("Iface not found\n");
4457 return NULL;
4458}
4459EXPORT_SYMBOL(ecm_db_iface_find_and_ref_by_interface_identifier);
4460
4461/*
Gareth Williamsf98d4192015-03-11 16:55:41 +00004462 * ecm_db_iface_ifidx_find_and_ref_ethernet()
4463 * Return an interface based on a MAC address and interface hlos interface identifier
4464 */
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304465struct ecm_db_iface_instance *ecm_db_iface_ifidx_find_and_ref_ethernet(uint8_t *address, int32_t ifidx)
Ben Menchaca84f36632014-02-28 20:57:38 +00004466{
4467 ecm_db_iface_hash_t hash_index;
4468 struct ecm_db_iface_instance *ii;
4469
4470 DEBUG_TRACE("Lookup ethernet iface with addr %pM\n", address);
4471
4472 /*
4473 * Compute the hash chain index and prepare to walk the chain
4474 */
4475 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
4476
4477 /*
4478 * Iterate the chain looking for a host with matching details
4479 */
4480 spin_lock_bh(&ecm_db_lock);
4481 ii = ecm_db_iface_table[hash_index];
4482 while (ii) {
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304483 if ((ii->type != ECM_DB_IFACE_TYPE_ETHERNET)
4484 || memcmp(ii->type_info.ethernet.address, address, ETH_ALEN)
4485 || ii->interface_identifier != ifidx) {
Ben Menchaca84f36632014-02-28 20:57:38 +00004486 ii = ii->hash_next;
4487 continue;
4488 }
4489
4490 _ecm_db_iface_ref(ii);
4491 spin_unlock_bh(&ecm_db_lock);
4492 DEBUG_TRACE("iface found %p\n", ii);
4493 return ii;
4494 }
4495 spin_unlock_bh(&ecm_db_lock);
4496 DEBUG_TRACE("Iface not found\n");
4497 return NULL;
4498}
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304499EXPORT_SYMBOL(ecm_db_iface_ifidx_find_and_ref_ethernet);
4500
Murat Sezgin37fb3952015-03-10 16:45:13 -07004501#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004502/*
4503 * ecm_db_iface_vlan_info_get()
4504 * Get vlan interface specific information
4505 */
4506void ecm_db_iface_vlan_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_vlan *vlan_info)
4507{
4508 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4509 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_VLAN, "%p: Bad type, expected vlan, actual: %d\n", ii, ii->type);
4510 spin_lock_bh(&ecm_db_lock);
4511 memcpy(vlan_info->address, ii->type_info.vlan.address, sizeof(ii->type_info.vlan.address));
4512 vlan_info->vlan_tag = ii->type_info.vlan.vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304513 vlan_info->vlan_tpid = ii->type_info.vlan.vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00004514 spin_unlock_bh(&ecm_db_lock);
4515}
4516EXPORT_SYMBOL(ecm_db_iface_vlan_info_get);
4517
4518/*
4519 * ecm_db_iface_find_and_ref_vlan()
4520 * Lookup and return a iface reference if any
4521 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304522struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_vlan(uint8_t *address, uint16_t vlan_tag, uint16_t vlan_tpid)
Ben Menchaca84f36632014-02-28 20:57:38 +00004523{
4524 ecm_db_iface_hash_t hash_index;
4525 struct ecm_db_iface_instance *ii;
4526
Sol Kavyd7583592014-06-05 18:51:46 -07004527 DEBUG_TRACE("Lookup vlan iface with addr %pM, vlan tag: %x vlan tpid: %x\n", address, vlan_tag, vlan_tpid);
Ben Menchaca84f36632014-02-28 20:57:38 +00004528
4529 /*
4530 * Compute the hash chain index and prepare to walk the chain
4531 */
4532 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
4533
4534 /*
4535 * Iterate the chain looking for a host with matching details
4536 */
4537 spin_lock_bh(&ecm_db_lock);
4538 ii = ecm_db_iface_table[hash_index];
4539 while (ii) {
4540 if ((ii->type != ECM_DB_IFACE_TYPE_VLAN) || (ii->type_info.vlan.vlan_tag != vlan_tag)
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304541 || (ii->type_info.vlan.vlan_tpid != vlan_tpid)
Ben Menchaca84f36632014-02-28 20:57:38 +00004542 || memcmp(ii->type_info.vlan.address, address, ETH_ALEN)) {
4543 ii = ii->hash_next;
4544 continue;
4545 }
4546
4547 _ecm_db_iface_ref(ii);
4548 spin_unlock_bh(&ecm_db_lock);
4549 DEBUG_TRACE("iface found %p\n", ii);
4550 return ii;
4551 }
4552 spin_unlock_bh(&ecm_db_lock);
4553 DEBUG_TRACE("Iface not found\n");
4554 return NULL;
4555}
4556EXPORT_SYMBOL(ecm_db_iface_find_and_ref_vlan);
Murat Sezgin37fb3952015-03-10 16:45:13 -07004557#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004558
4559/*
4560 * ecm_db_iface_find_and_ref_bridge()
4561 * Lookup and return a iface reference if any
4562 */
4563struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_bridge(uint8_t *address)
4564{
4565 ecm_db_iface_hash_t hash_index;
4566 struct ecm_db_iface_instance *ii;
4567
4568 DEBUG_TRACE("Lookup bridge iface with addr %pM\n", address);
4569
4570 /*
4571 * Compute the hash chain index and prepare to walk the chain
4572 */
4573 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
4574
4575 /*
4576 * Iterate the chain looking for a host with matching details
4577 */
4578 spin_lock_bh(&ecm_db_lock);
4579 ii = ecm_db_iface_table[hash_index];
4580 while (ii) {
4581 if ((ii->type != ECM_DB_IFACE_TYPE_BRIDGE) || memcmp(ii->type_info.bridge.address, address, ETH_ALEN)) {
4582 ii = ii->hash_next;
4583 continue;
4584 }
4585
4586 _ecm_db_iface_ref(ii);
4587 spin_unlock_bh(&ecm_db_lock);
4588 DEBUG_TRACE("iface found %p\n", ii);
4589 return ii;
4590 }
4591 spin_unlock_bh(&ecm_db_lock);
4592 DEBUG_TRACE("Iface not found\n");
4593 return NULL;
4594}
4595EXPORT_SYMBOL(ecm_db_iface_find_and_ref_bridge);
4596
Murat Sezgin910c9662015-03-11 16:15:06 -07004597#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004598/*
4599 * ecm_db_iface_find_and_ref_lag()
4600 * Lookup and return a iface reference if any
4601 */
4602struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_lag(uint8_t *address)
4603{
4604 ecm_db_iface_hash_t hash_index;
4605 struct ecm_db_iface_instance *ii;
4606
4607 DEBUG_TRACE("Lookup lag iface with addr %pM\n", address);
4608
4609 /*
4610 * Compute the hash chain index and prepare to walk the chain
4611 */
4612 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
4613
4614 /*
4615 * Iterate the chain looking for a host with matching details
4616 */
4617 spin_lock_bh(&ecm_db_lock);
4618 ii = ecm_db_iface_table[hash_index];
4619 while (ii) {
4620 if ((ii->type != ECM_DB_IFACE_TYPE_LAG) || memcmp(ii->type_info.lag.address, address, ETH_ALEN)) {
4621 ii = ii->hash_next;
4622 continue;
4623 }
4624
4625 _ecm_db_iface_ref(ii);
4626 spin_unlock_bh(&ecm_db_lock);
4627 DEBUG_TRACE("iface found %p\n", ii);
4628 return ii;
4629 }
4630 spin_unlock_bh(&ecm_db_lock);
4631 DEBUG_TRACE("Iface not found\n");
4632 return NULL;
4633}
4634EXPORT_SYMBOL(ecm_db_iface_find_and_ref_lag);
Murat Sezgin910c9662015-03-11 16:15:06 -07004635#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004636
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304637#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004638/*
4639 * ecm_db_iface_pppoe_session_info_get()
Murat Sezgin37fb3952015-03-10 16:45:13 -07004640 * Get pppoe interface specific information
Ben Menchaca84f36632014-02-28 20:57:38 +00004641 */
4642void ecm_db_iface_pppoe_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppoe *pppoe_info)
4643{
4644 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4645 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPPOE, "%p: Bad type, expected pppoe, actual: %d\n", ii, ii->type);
4646 spin_lock_bh(&ecm_db_lock);
4647 memcpy(pppoe_info->remote_mac, ii->type_info.pppoe.remote_mac, sizeof(ii->type_info.pppoe.remote_mac));
4648 pppoe_info->pppoe_session_id = ii->type_info.pppoe.pppoe_session_id;
4649 spin_unlock_bh(&ecm_db_lock);
4650}
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304651
Ben Menchaca84f36632014-02-28 20:57:38 +00004652EXPORT_SYMBOL(ecm_db_iface_pppoe_session_info_get);
4653
4654/*
4655 * ecm_db_iface_find_and_ref_pppoe()
4656 * Lookup and return a iface reference if any
4657 */
4658struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pppoe(uint16_t pppoe_session_id, uint8_t *remote_mac)
4659{
4660 ecm_db_iface_hash_t hash_index;
4661 struct ecm_db_iface_instance *ii;
4662
4663 DEBUG_TRACE("Lookup pppoe iface with addr %x\n", pppoe_session_id);
4664
4665 /*
4666 * Compute the hash chain index and prepare to walk the chain
4667 */
4668 hash_index = ecm_db_iface_generate_hash_index_pppoe(pppoe_session_id);
4669
4670 /*
4671 * Iterate the chain looking for a host with matching details
4672 */
4673 spin_lock_bh(&ecm_db_lock);
4674 ii = ecm_db_iface_table[hash_index];
4675 while (ii) {
4676 if ((ii->type != ECM_DB_IFACE_TYPE_PPPOE)
4677 || (ii->type_info.pppoe.pppoe_session_id != pppoe_session_id)
4678 || memcmp(ii->type_info.pppoe.remote_mac, remote_mac, ETH_ALEN)) {
4679 ii = ii->hash_next;
4680 continue;
4681 }
4682
4683 _ecm_db_iface_ref(ii);
4684 spin_unlock_bh(&ecm_db_lock);
4685 DEBUG_TRACE("iface found %p\n", ii);
4686 return ii;
4687 }
4688 spin_unlock_bh(&ecm_db_lock);
4689 DEBUG_TRACE("Iface not found\n");
4690 return NULL;
4691}
4692EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pppoe);
Murat Sezginaad635c2015-03-06 16:11:41 -08004693#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004694
ratheesh kannothed721852015-09-28 12:39:52 +05304695/*
4696 * ecm_db_iface_update_ae_interface_identifier()
4697 * update ae_interface_identifier in iface instance.
4698 */
4699void ecm_db_iface_update_ae_interface_identifier(struct ecm_db_iface_instance *ii, int32_t ae_interface_identifier)
4700{
4701 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304702
ratheesh kannothed721852015-09-28 12:39:52 +05304703 spin_lock_bh(&ecm_db_lock);
4704 if (ii->ae_interface_identifier == ae_interface_identifier) {
4705 spin_unlock_bh(&ecm_db_lock);
4706 return;
4707 }
4708 ii->ae_interface_identifier = ae_interface_identifier;
4709 spin_unlock_bh(&ecm_db_lock);
4710}
4711EXPORT_SYMBOL(ecm_db_iface_update_ae_interface_identifier);
4712
4713#ifdef ECM_INTERFACE_L2TPV2_ENABLE
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304714/*
4715 * ecm_db_iface_pppol2tpv2_session_info_get
4716 * get l2tpv2 specific info
4717 */
4718void ecm_db_iface_pppol2tpv2_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppol2tpv2 *pppol2tpv2_info)
4719{
4720 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4721 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPPOL2TPV2, "%p: Bad type, expected pppol2tpv2, actual: %d\n", ii, ii->type);
4722 spin_lock_bh(&ecm_db_lock);
4723 memcpy(pppol2tpv2_info, &ii->type_info.pppol2tpv2, sizeof(struct ecm_db_interface_info_pppol2tpv2));
4724 spin_unlock_bh(&ecm_db_lock);
4725}
4726EXPORT_SYMBOL(ecm_db_iface_pppol2tpv2_session_info_get);
4727
4728/*
4729 * ecm_db_iface_find_and_ref_pppol2tpv2()
4730 * Lookup and return a iface reference if any
4731 */
4732struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pppol2tpv2(uint32_t pppol2tpv2_tunnel_id, uint32_t pppol2tpv2_session_id)
4733{
4734 ecm_db_iface_hash_t hash_index;
4735 struct ecm_db_iface_instance *ii;
4736
4737 /*
4738 * Compute the hash chain index and prepare to walk the chain
4739 */
4740 hash_index = ecm_db_iface_generate_hash_index_pppol2tpv2(pppol2tpv2_tunnel_id, pppol2tpv2_session_id);
4741
4742 DEBUG_TRACE("Lookup pppol2tpv2 iface with local_tunnel_id = %d, local_session_id = %d, hash = 0x%x\n", pppol2tpv2_tunnel_id,
4743 pppol2tpv2_session_id, hash_index);
4744
4745 /*
4746 * Iterate the chain looking for a host with matching details
4747 */
4748 spin_lock_bh(&ecm_db_lock);
4749 ii = ecm_db_iface_table[hash_index];
4750
4751 while (ii) {
4752 if ((ii->type != ECM_DB_IFACE_TYPE_PPPOL2TPV2)
4753 || (ii->type_info.pppol2tpv2.l2tp.session.session_id != pppol2tpv2_session_id)
4754 || (ii->type_info.pppol2tpv2.l2tp.tunnel.tunnel_id != pppol2tpv2_tunnel_id)) {
4755 ii = ii->hash_next;
4756 continue;
4757 }
4758
4759 _ecm_db_iface_ref(ii);
4760 spin_unlock_bh(&ecm_db_lock);
4761 DEBUG_TRACE("iface found %p\n", ii);
4762 return ii;
4763 }
4764 spin_unlock_bh(&ecm_db_lock);
4765
4766 DEBUG_TRACE("Iface not found\n");
4767 return NULL;
4768}
4769EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pppol2tpv2);
4770
4771#endif
4772
Shyam Sunder23f2e542015-09-28 14:56:49 +05304773#ifdef ECM_INTERFACE_PPTP_ENABLE
4774/*
4775 * ecm_db_iface_pptp_session_info_get
4776 * get pptp specific info
4777 */
4778void ecm_db_iface_pptp_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info)
4779{
4780 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4781 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPTP, "%p: Bad type, expected pptp, actual: %d\n", ii, ii->type);
4782 spin_lock_bh(&ecm_db_lock);
4783 memcpy(pptp_info, &ii->type_info.pptp, sizeof(struct ecm_db_interface_info_pptp));
4784 spin_unlock_bh(&ecm_db_lock);
4785}
4786EXPORT_SYMBOL(ecm_db_iface_pptp_session_info_get);
4787
4788/*
4789 * ecm_db_iface_find_and_ref_pptp()
4790 * Lookup and return a iface reference if any
4791 */
4792struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pptp(uint32_t pptp_src_call_id, uint32_t pptp_dst_call_id)
4793{
4794 ecm_db_iface_hash_t hash_index;
4795 struct ecm_db_iface_instance *ii;
4796
4797 /*
4798 * Compute the hash chain index and prepare to walk the chain
4799 */
4800 hash_index = ecm_db_iface_generate_hash_index_pptp(pptp_src_call_id, pptp_dst_call_id);
4801
4802 DEBUG_TRACE("Lookup pptp iface with local_call_id = %d, remote_call_id = %d, hash = 0x%x\n", pptp_src_call_id,
4803 pptp_dst_call_id, hash_index);
4804
4805 /*
4806 * Iterate the chain looking for a host with matching details
4807 */
4808 spin_lock_bh(&ecm_db_lock);
4809 ii = ecm_db_iface_table[hash_index];
4810
4811 while (ii) {
4812 if ((ii->type != ECM_DB_IFACE_TYPE_PPTP)
4813 || (ii->type_info.pptp.src_call_id != pptp_src_call_id)
4814 || (ii->type_info.pptp.dst_call_id != pptp_dst_call_id)) {
4815 ii = ii->hash_next;
4816 continue;
4817 }
4818
4819 _ecm_db_iface_ref(ii);
4820 spin_unlock_bh(&ecm_db_lock);
4821 DEBUG_TRACE("iface found %p\n", ii);
4822 return ii;
4823 }
4824 spin_unlock_bh(&ecm_db_lock);
4825
4826 DEBUG_TRACE("Iface not found\n");
4827 return NULL;
4828}
4829EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pptp);
4830#endif
4831
ratheesh kannothcfdcb332015-12-24 07:19:18 +05304832#ifdef ECM_INTERFACE_MAP_T_ENABLE
4833/*
4834 * ecm_db_iface_map_t_info_get
4835 * get map_t specific info
4836 */
4837void ecm_db_iface_map_t_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_map_t *map_t_info)
4838{
4839 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4840 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_MAP_T, "%p: Bad type, expected map_t, actual: %d\n", ii, ii->type);
4841 spin_lock_bh(&ecm_db_lock);
4842 memcpy(map_t_info, &ii->type_info.map_t, sizeof(struct ecm_db_interface_info_map_t));
4843 spin_unlock_bh(&ecm_db_lock);
4844}
4845EXPORT_SYMBOL(ecm_db_iface_map_t_info_get);
4846
4847/*
4848 * ecm_db_iface_find_and_ref_map_t()
4849 * Lookup and return a iface reference if any
4850 */
4851struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_map_t(int if_index)
4852{
4853 ecm_db_iface_hash_t hash_index;
4854 struct ecm_db_iface_instance *ii;
4855
4856 DEBUG_TRACE("Lookup map_t iface with if_index = %d\n", if_index);
4857
4858 /*
4859 * Compute the hash chain index and prepare to walk the chain
4860 */
4861 hash_index = ecm_db_iface_generate_hash_index_map_t(if_index);
4862
4863 /*
4864 * Iterate the chain looking for a host with matching details
4865 */
4866 spin_lock_bh(&ecm_db_lock);
4867 ii = ecm_db_iface_table[hash_index];
4868
4869 while (ii) {
4870 if ((ii->type != ECM_DB_IFACE_TYPE_MAP_T)
4871 || (ii->type_info.map_t.if_index != if_index)) {
4872 ii = ii->hash_next;
4873 continue;
4874 }
4875
4876 _ecm_db_iface_ref(ii);
4877 spin_unlock_bh(&ecm_db_lock);
4878 DEBUG_TRACE("%p: iface found\n", ii);
4879 return ii;
4880 }
4881 spin_unlock_bh(&ecm_db_lock);
4882
4883 DEBUG_TRACE("Iface not found\n");
4884 return NULL;
4885}
4886EXPORT_SYMBOL(ecm_db_iface_find_and_ref_map_t);
4887
4888#endif
4889
Ben Menchaca84f36632014-02-28 20:57:38 +00004890/*
4891 * ecm_db_iface_find_and_ref_unknown()
4892 * Lookup and return a iface reference if any
4893 */
4894struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_unknown(uint32_t os_specific_ident)
4895{
4896 ecm_db_iface_hash_t hash_index;
4897 struct ecm_db_iface_instance *ii;
4898
4899 DEBUG_TRACE("Lookup unknown iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
4900
4901 /*
4902 * Compute the hash chain index and prepare to walk the chain
4903 */
4904 hash_index = ecm_db_iface_generate_hash_index_unknown(os_specific_ident);
4905
4906 /*
4907 * Iterate the chain looking for a host with matching details
4908 */
4909 spin_lock_bh(&ecm_db_lock);
4910 ii = ecm_db_iface_table[hash_index];
4911 while (ii) {
4912 if ((ii->type != ECM_DB_IFACE_TYPE_UNKNOWN) || (ii->type_info.unknown.os_specific_ident != os_specific_ident)) {
4913 ii = ii->hash_next;
4914 continue;
4915 }
4916
4917 _ecm_db_iface_ref(ii);
4918 spin_unlock_bh(&ecm_db_lock);
4919 DEBUG_TRACE("iface found %p\n", ii);
4920 return ii;
4921 }
4922 spin_unlock_bh(&ecm_db_lock);
4923 DEBUG_TRACE("Iface not found\n");
4924 return NULL;
4925}
4926EXPORT_SYMBOL(ecm_db_iface_find_and_ref_unknown);
4927
4928/*
4929 * ecm_db_iface_find_and_ref_loopback()
4930 * Lookup and return a iface reference if any
4931 */
4932struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_loopback(uint32_t os_specific_ident)
4933{
4934 ecm_db_iface_hash_t hash_index;
4935 struct ecm_db_iface_instance *ii;
4936
4937 DEBUG_TRACE("Lookup loopback iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
4938
4939 /*
4940 * Compute the hash chain index and prepare to walk the chain
4941 */
4942 hash_index = ecm_db_iface_generate_hash_index_loopback(os_specific_ident);
4943
4944 /*
4945 * Iterate the chain looking for a host with matching details
4946 */
4947 spin_lock_bh(&ecm_db_lock);
4948 ii = ecm_db_iface_table[hash_index];
4949 while (ii) {
4950 if ((ii->type != ECM_DB_IFACE_TYPE_LOOPBACK) || (ii->type_info.loopback.os_specific_ident != os_specific_ident)) {
4951 ii = ii->hash_next;
4952 continue;
4953 }
4954
4955 _ecm_db_iface_ref(ii);
4956 spin_unlock_bh(&ecm_db_lock);
4957 DEBUG_TRACE("iface found %p\n", ii);
4958 return ii;
4959 }
4960 spin_unlock_bh(&ecm_db_lock);
4961 DEBUG_TRACE("Iface not found\n");
4962 return NULL;
4963}
4964EXPORT_SYMBOL(ecm_db_iface_find_and_ref_loopback);
4965
Murat Sezgin69a27532015-03-12 14:09:40 -07004966#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004967/*
4968 * ecm_db_iface_find_and_ref_ipsec_tunnel()
4969 * Lookup and return a iface reference if any.
4970 * GGG TODO Flesh this out using tunnel endpoint keys
4971 */
4972struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_ipsec_tunnel(uint32_t os_specific_ident)
4973{
4974 ecm_db_iface_hash_t hash_index;
4975 struct ecm_db_iface_instance *ii;
4976
4977 DEBUG_TRACE("Lookup ipsec_tunnel iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
4978
4979 /*
4980 * Compute the hash chain index and prepare to walk the chain
4981 */
4982 hash_index = ecm_db_iface_generate_hash_index_ipsec_tunnel(os_specific_ident);
4983
4984 /*
4985 * Iterate the chain looking for a host with matching details
4986 */
4987 spin_lock_bh(&ecm_db_lock);
4988 ii = ecm_db_iface_table[hash_index];
4989 while (ii) {
4990 if ((ii->type != ECM_DB_IFACE_TYPE_IPSEC_TUNNEL) || (ii->type_info.ipsec_tunnel.os_specific_ident != os_specific_ident)) {
4991 ii = ii->hash_next;
4992 continue;
4993 }
4994
4995 _ecm_db_iface_ref(ii);
4996 spin_unlock_bh(&ecm_db_lock);
4997 DEBUG_TRACE("iface found %p\n", ii);
4998 return ii;
4999 }
5000 spin_unlock_bh(&ecm_db_lock);
5001 DEBUG_TRACE("Iface not found\n");
5002 return NULL;
5003}
5004EXPORT_SYMBOL(ecm_db_iface_find_and_ref_ipsec_tunnel);
Murat Sezgin69a27532015-03-12 14:09:40 -07005005#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00005006
Murat Sezginbde55f92015-03-11 16:44:11 -07005007#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00005008/*
5009 * ecm_db_iface_find_and_ref_sit()
5010 * Lookup and return a iface reference if any
5011 */
5012struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_sit(ip_addr_t saddr, ip_addr_t daddr)
5013{
5014 ecm_db_iface_hash_t hash_index;
5015 struct ecm_db_iface_instance *ii;
5016
5017 DEBUG_TRACE("Lookup sit (6-in-4) iface with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT "\n",
5018 ECM_IP_ADDR_TO_OCTAL(saddr), ECM_IP_ADDR_TO_OCTAL(daddr));
5019
5020 /*
5021 * Compute the hash chain index and prepare to walk the chain
5022 */
5023 hash_index = ecm_db_iface_generate_hash_index_sit(saddr, daddr);
5024
5025 /*
5026 * Iterate the chain looking for a host with matching details
5027 */
5028 spin_lock_bh(&ecm_db_lock);
5029 ii = ecm_db_iface_table[hash_index];
5030 while (ii) {
5031 if ((ii->type != ECM_DB_IFACE_TYPE_SIT)
5032 || !ECM_IP_ADDR_MATCH(ii->type_info.sit.saddr, saddr)
5033 || !ECM_IP_ADDR_MATCH(ii->type_info.sit.daddr, daddr)) {
5034 ii = ii->hash_next;
5035 continue;
5036 }
5037
5038 _ecm_db_iface_ref(ii);
5039 spin_unlock_bh(&ecm_db_lock);
5040 DEBUG_TRACE("iface found %p\n", ii);
5041 return ii;
5042 }
5043 spin_unlock_bh(&ecm_db_lock);
5044 DEBUG_TRACE("Iface not found\n");
5045 return NULL;
5046}
5047EXPORT_SYMBOL(ecm_db_iface_find_and_ref_sit);
Murat Sezginbde55f92015-03-11 16:44:11 -07005048#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00005049
Murat Sezginc1402562015-03-12 12:32:20 -07005050#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +00005051#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00005052/*
5053 * ecm_db_iface_find_and_ref_tunipip6()
5054 * Lookup and return a iface reference if any
5055 */
5056struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_tunipip6(ip_addr_t saddr, ip_addr_t daddr)
5057{
5058 ecm_db_iface_hash_t hash_index;
5059 struct ecm_db_iface_instance *ii;
5060
5061 DEBUG_TRACE("Lookup TUNIPIP6 iface with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT "\n",
5062 ECM_IP_ADDR_TO_OCTAL(saddr), ECM_IP_ADDR_TO_OCTAL(daddr));
5063
5064 /*
5065 * Compute the hash chain index and prepare to walk the chain
5066 */
5067 hash_index = ecm_db_iface_generate_hash_index_tunipip6(saddr, daddr);
5068
5069 /*
5070 * Iterate the chain looking for a host with matching details
5071 */
5072 spin_lock_bh(&ecm_db_lock);
5073 ii = ecm_db_iface_table[hash_index];
5074 while (ii) {
5075 if ((ii->type != ECM_DB_IFACE_TYPE_TUNIPIP6)
5076 || !ECM_IP_ADDR_MATCH(ii->type_info.tunipip6.saddr, saddr)
5077 || !ECM_IP_ADDR_MATCH(ii->type_info.tunipip6.daddr, daddr)) {
5078 ii = ii->hash_next;
5079 continue;
5080 }
5081
5082 _ecm_db_iface_ref(ii);
5083 spin_unlock_bh(&ecm_db_lock);
5084 DEBUG_TRACE("iface found %p\n", ii);
5085 return ii;
5086 }
5087 spin_unlock_bh(&ecm_db_lock);
5088 DEBUG_TRACE("Iface not found\n");
5089 return NULL;
5090}
5091EXPORT_SYMBOL(ecm_db_iface_find_and_ref_tunipip6);
Murat Sezginc1402562015-03-12 12:32:20 -07005092#endif
Gareth Williams8ac34292015-03-17 14:06:58 +00005093#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00005094
5095/*
5096 * ecm_db_mapping_find_and_ref()
5097 * Lookup and return a mapping reference if any.
5098 *
5099 * NOTE: For non-port based protocols the ports are expected to be -(protocol)
5100 */
5101struct ecm_db_mapping_instance *ecm_db_mapping_find_and_ref(ip_addr_t address, int port)
5102{
5103 ecm_db_mapping_hash_t hash_index;
5104 struct ecm_db_mapping_instance *mi;
5105
5106 DEBUG_TRACE("Lookup mapping with addr " ECM_IP_ADDR_OCTAL_FMT " and port %d\n", ECM_IP_ADDR_TO_OCTAL(address), port);
5107
5108 /*
5109 * Compute the hash chain index and prepare to walk the chain
5110 */
5111 hash_index = ecm_db_mapping_generate_hash_index(address, port);
5112
5113 /*
5114 * Iterate the chain looking for a mapping with matching details
5115 */
5116 spin_lock_bh(&ecm_db_lock);
5117 mi = ecm_db_mapping_table[hash_index];
5118 while (mi) {
5119 if (mi->port != port) {
5120 mi = mi->hash_next;
5121 continue;
5122 }
5123
5124 if (!ECM_IP_ADDR_MATCH(mi->host->address, address)) {
5125 mi = mi->hash_next;
5126 continue;
5127 }
5128
5129 _ecm_db_mapping_ref(mi);
5130 spin_unlock_bh(&ecm_db_lock);
5131 DEBUG_TRACE("Mapping found %p\n", mi);
5132 return mi;
5133 }
5134 spin_unlock_bh(&ecm_db_lock);
5135 DEBUG_TRACE("Mapping not found\n");
5136 return NULL;
5137}
5138EXPORT_SYMBOL(ecm_db_mapping_find_and_ref);
5139
5140/*
Gareth Williams54d15d92015-04-24 19:28:27 +01005141 * ecm_db_connection_find_and_ref_chain()
5142 * Given a hash chain index locate the connection
Ben Menchaca84f36632014-02-28 20:57:38 +00005143 */
Gareth Williams54d15d92015-04-24 19:28:27 +01005144static struct ecm_db_connection_instance *ecm_db_connection_find_and_ref_chain(ecm_db_connection_hash_t hash_index,
5145 ip_addr_t host1_addr, ip_addr_t host2_addr,
5146 int protocol, int host1_port, int host2_port)
Ben Menchaca84f36632014-02-28 20:57:38 +00005147{
Ben Menchaca84f36632014-02-28 20:57:38 +00005148 struct ecm_db_connection_instance *ci;
5149
Ben Menchaca84f36632014-02-28 20:57:38 +00005150 /*
5151 * Iterate the chain looking for a connection with matching details
5152 */
5153 spin_lock_bh(&ecm_db_lock);
5154 ci = ecm_db_connection_table[hash_index];
Ben Menchaca84f36632014-02-28 20:57:38 +00005155 while (ci) {
Ben Menchaca84f36632014-02-28 20:57:38 +00005156 /*
5157 * The use of unlikely() is liberally used because under fast-hit scenarios the connection would always be at the start of a chain
5158 */
5159 if (unlikely(ci->protocol != protocol)) {
5160 goto try_next;
5161 }
5162
5163 if (unlikely(!ECM_IP_ADDR_MATCH(host1_addr, ci->mapping_from->host->address))) {
5164 goto try_reverse;
5165 }
5166
5167 if (unlikely(host1_port != ci->mapping_from->port)) {
5168 goto try_reverse;
5169 }
5170
5171 if (unlikely(!ECM_IP_ADDR_MATCH(host2_addr, ci->mapping_to->host->address))) {
5172 goto try_reverse;
5173 }
5174
5175 if (unlikely(host2_port != ci->mapping_to->port)) {
5176 goto try_reverse;
5177 }
5178
5179 goto connection_found;
5180
5181try_reverse:
5182 if (unlikely(!ECM_IP_ADDR_MATCH(host1_addr, ci->mapping_to->host->address))) {
5183 goto try_next;
5184 }
5185
5186 if (unlikely(host1_port != ci->mapping_to->port)) {
5187 goto try_next;
5188 }
5189
5190 if (unlikely(!ECM_IP_ADDR_MATCH(host2_addr, ci->mapping_from->host->address))) {
5191 goto try_next;
5192 }
5193
5194 if (unlikely(host2_port != ci->mapping_from->port)) {
5195 goto try_next;
5196 }
5197
5198 goto connection_found;
5199
5200try_next:
Gareth Williamse5cb08b2015-10-28 17:02:53 +00005201 ci = ci->hash_next;
Ben Menchaca84f36632014-02-28 20:57:38 +00005202 }
Gareth Williamse5cb08b2015-10-28 17:02:53 +00005203 spin_unlock_bh(&ecm_db_lock);
Gareth Williams54d15d92015-04-24 19:28:27 +01005204 DEBUG_TRACE("Connection not found in hash chain\n");
Ben Menchaca84f36632014-02-28 20:57:38 +00005205 return NULL;
5206
5207connection_found:
Gareth Williamse5cb08b2015-10-28 17:02:53 +00005208 _ecm_db_connection_ref(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00005209 spin_unlock_bh(&ecm_db_lock);
Gareth Williamse5cb08b2015-10-28 17:02:53 +00005210 DEBUG_TRACE("Connection found %p\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00005211 return ci;
5212}
Gareth Williams54d15d92015-04-24 19:28:27 +01005213
5214/*
5215 * ecm_db_connection_find_and_ref()
5216 * Locate a connection instance based on addressing, protocol and optional port information.
5217 *
5218 * NOTE: For non-port based protocols then ports are expected to be -(protocol).
5219 */
5220struct ecm_db_connection_instance *ecm_db_connection_find_and_ref(ip_addr_t host1_addr, ip_addr_t host2_addr, int protocol, int host1_port, int host2_port)
5221{
5222 ecm_db_connection_hash_t hash_index;
5223
5224 DEBUG_TRACE("Lookup connection " ECM_IP_ADDR_OCTAL_FMT ":%d <> " ECM_IP_ADDR_OCTAL_FMT ":%d protocol %d\n", ECM_IP_ADDR_TO_OCTAL(host1_addr), host1_port, ECM_IP_ADDR_TO_OCTAL(host2_addr), host2_port, protocol);
5225
5226 /*
5227 * Compute the hash chain index and prepare to walk the chain
5228 */
5229 hash_index = ecm_db_connection_generate_hash_index(host1_addr, host1_port, host2_addr, host2_port, protocol);
5230 return ecm_db_connection_find_and_ref_chain(hash_index, host1_addr, host2_addr, protocol, host1_port, host2_port);
5231}
Ben Menchaca84f36632014-02-28 20:57:38 +00005232EXPORT_SYMBOL(ecm_db_connection_find_and_ref);
5233
5234/*
5235 * ecm_db_connection_serial_find_and_ref()
5236 * Locate a connection instance based on serial if it still exists
5237 */
5238struct ecm_db_connection_instance *ecm_db_connection_serial_find_and_ref(uint32_t serial)
5239{
5240 ecm_db_connection_serial_hash_t serial_hash_index;
5241 struct ecm_db_connection_instance *ci;
5242
5243 DEBUG_TRACE("Lookup connection serial: %u\n", serial);
5244
5245 /*
5246 * Compute the hash chain index and prepare to walk the chain
5247 */
5248 serial_hash_index = ecm_db_connection_generate_serial_hash_index(serial);
5249
5250 /*
5251 * Iterate the chain looking for a connection with matching serial
5252 */
5253 spin_lock_bh(&ecm_db_lock);
5254 ci = ecm_db_connection_serial_table[serial_hash_index];
Ben Menchaca84f36632014-02-28 20:57:38 +00005255 while (ci) {
Ben Menchaca84f36632014-02-28 20:57:38 +00005256 /*
5257 * The use of likely() is used because under fast-hit scenarios the connection would always be at the start of a chain
5258 */
5259 if (likely(ci->serial == serial)) {
Gareth Williamse5cb08b2015-10-28 17:02:53 +00005260 _ecm_db_connection_ref(ci);
5261 spin_unlock_bh(&ecm_db_lock);
5262 DEBUG_TRACE("Connection found %p\n", ci);
5263 return ci;
Ben Menchaca84f36632014-02-28 20:57:38 +00005264 }
5265
Gareth Williamse5cb08b2015-10-28 17:02:53 +00005266 ci = ci->serial_hash_next;
Ben Menchaca84f36632014-02-28 20:57:38 +00005267 }
Gareth Williamse5cb08b2015-10-28 17:02:53 +00005268 spin_unlock_bh(&ecm_db_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00005269 DEBUG_TRACE("Connection not found\n");
5270 return NULL;
Ben Menchaca84f36632014-02-28 20:57:38 +00005271}
5272EXPORT_SYMBOL(ecm_db_connection_serial_find_and_ref);
5273
5274/*
Gareth Williamsb5903892015-03-20 15:13:07 +00005275 * ecm_db_connection_node_to_get_and_ref()
5276 * Return node reference
5277 */
5278struct ecm_db_node_instance *ecm_db_connection_node_to_get_and_ref(struct ecm_db_connection_instance *ci)
5279{
5280 struct ecm_db_node_instance *ni;
5281
5282 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5283
5284 spin_lock_bh(&ecm_db_lock);
5285 ni = ci->to_node;
5286 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
5287 _ecm_db_node_ref(ni);
5288 spin_unlock_bh(&ecm_db_lock);
5289 return ni;
5290}
5291EXPORT_SYMBOL(ecm_db_connection_node_to_get_and_ref);
5292
5293/*
5294 * ecm_db_connection_node_from_get_and_ref()
5295 * Return node reference
5296 */
5297struct ecm_db_node_instance *ecm_db_connection_node_from_get_and_ref(struct ecm_db_connection_instance *ci)
5298{
5299 struct ecm_db_node_instance *ni;
5300
5301 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5302
5303 spin_lock_bh(&ecm_db_lock);
5304 ni = ci->from_node;
5305 _ecm_db_node_ref(ni);
5306 spin_unlock_bh(&ecm_db_lock);
5307 return ni;
5308}
5309EXPORT_SYMBOL(ecm_db_connection_node_from_get_and_ref);
5310
5311#ifdef ECM_DB_XREF_ENABLE
5312/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005313 * ecm_db_mapping_connections_from_get_and_ref_first()
5314 * Return a reference to the first connection made from this mapping
5315 */
5316struct ecm_db_connection_instance *ecm_db_mapping_connections_from_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5317{
5318 struct ecm_db_connection_instance *ci;
5319
5320 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5321
5322 spin_lock_bh(&ecm_db_lock);
5323 ci = mi->from_connections;
5324 if (ci) {
5325 _ecm_db_connection_ref(ci);
5326 }
5327 spin_unlock_bh(&ecm_db_lock);
5328
5329 return ci;
5330}
5331EXPORT_SYMBOL(ecm_db_mapping_connections_from_get_and_ref_first);
5332
5333/*
5334 * ecm_db_mapping_connections_to_get_and_ref_first()
5335 * Return a reference to the first connection made to this mapping
5336 */
5337struct ecm_db_connection_instance *ecm_db_mapping_connections_to_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5338{
5339 struct ecm_db_connection_instance *ci;
5340
5341 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5342
5343 spin_lock_bh(&ecm_db_lock);
5344 ci = mi->to_connections;
5345 if (ci) {
5346 _ecm_db_connection_ref(ci);
5347 }
5348 spin_unlock_bh(&ecm_db_lock);
5349
5350 return ci;
5351}
5352EXPORT_SYMBOL(ecm_db_mapping_connections_to_get_and_ref_first);
5353
5354/*
5355 * ecm_db_mapping_connections_nat_from_get_and_ref_first()
5356 * Return a reference to the first NAT connection made from this mapping
5357 */
5358struct ecm_db_connection_instance *ecm_db_mapping_connections_nat_from_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5359{
5360 struct ecm_db_connection_instance *ci;
5361
5362 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5363
5364 spin_lock_bh(&ecm_db_lock);
5365 ci = mi->from_nat_connections;
5366 if (ci) {
5367 _ecm_db_connection_ref(ci);
5368 }
5369 spin_unlock_bh(&ecm_db_lock);
5370
5371 return ci;
5372}
5373EXPORT_SYMBOL(ecm_db_mapping_connections_nat_from_get_and_ref_first);
5374
5375/*
5376 * ecm_db_mapping_connections_nat_to_get_and_ref_first()
5377 * Return a reference to the first NAT connection made to this mapping
5378 */
5379struct ecm_db_connection_instance *ecm_db_mapping_connections_nat_to_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5380{
5381 struct ecm_db_connection_instance *ci;
5382
5383 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5384
5385 spin_lock_bh(&ecm_db_lock);
5386 ci = mi->to_nat_connections;
5387 if (ci) {
5388 _ecm_db_connection_ref(ci);
5389 }
5390 spin_unlock_bh(&ecm_db_lock);
5391
5392 return ci;
5393}
5394EXPORT_SYMBOL(ecm_db_mapping_connections_nat_to_get_and_ref_first);
5395
5396/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005397 * ecm_db_connection_mapping_from_get_and_ref_next()
5398 * Return reference to next connection in from mapping chain
5399 */
5400struct ecm_db_connection_instance *ecm_db_connection_mapping_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5401{
5402 struct ecm_db_connection_instance *nci;
5403
5404 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5405
5406 spin_lock_bh(&ecm_db_lock);
5407 nci = ci->from_next;
5408 if (nci) {
5409 _ecm_db_connection_ref(nci);
5410 }
5411 spin_unlock_bh(&ecm_db_lock);
5412
5413 return nci;
5414}
5415EXPORT_SYMBOL(ecm_db_connection_mapping_from_get_and_ref_next);
5416
5417/*
5418 * ecm_db_connection_mapping_to_get_and_ref_next()
5419 * Return reference to next connection in to mapping chain
5420 */
5421struct ecm_db_connection_instance *ecm_db_connection_mapping_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5422{
5423 struct ecm_db_connection_instance *nci;
5424
5425 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5426
5427 spin_lock_bh(&ecm_db_lock);
5428 nci = ci->to_next;
5429 if (nci) {
5430 _ecm_db_connection_ref(nci);
5431 }
5432 spin_unlock_bh(&ecm_db_lock);
5433
5434 return nci;
5435}
5436EXPORT_SYMBOL(ecm_db_connection_mapping_to_get_and_ref_next);
5437
5438/*
5439 * ecm_db_connection_mapping_nat_from_get_and_ref_next()
5440 * Return reference to next connection in from NAT mapping chain
5441 */
5442struct ecm_db_connection_instance *ecm_db_connection_mapping_nat_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5443{
5444 struct ecm_db_connection_instance *nci;
5445
5446 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5447
5448 spin_lock_bh(&ecm_db_lock);
5449 nci = ci->from_nat_next;
5450 if (nci) {
5451 _ecm_db_connection_ref(nci);
5452 }
5453 spin_unlock_bh(&ecm_db_lock);
5454
5455 return nci;
5456}
5457EXPORT_SYMBOL(ecm_db_connection_mapping_nat_from_get_and_ref_next);
5458
5459/*
5460 * ecm_db_connection_mapping_nat_to_get_and_ref_next()
5461 * Return reference to next connection in to NAT mapping chain
5462 */
5463struct ecm_db_connection_instance *ecm_db_connection_mapping_nat_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5464{
5465 struct ecm_db_connection_instance *nci;
5466
5467 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5468
5469 spin_lock_bh(&ecm_db_lock);
5470 nci = ci->to_nat_next;
5471 if (nci) {
5472 _ecm_db_connection_ref(nci);
5473 }
5474 spin_unlock_bh(&ecm_db_lock);
5475
5476 return nci;
5477}
5478EXPORT_SYMBOL(ecm_db_connection_mapping_nat_to_get_and_ref_next);
5479
5480/*
5481 * ecm_db_iface_connections_from_get_and_ref_first()
5482 * Return a reference to the first connection made from this iface
5483 */
5484struct ecm_db_connection_instance *ecm_db_iface_connections_from_get_and_ref_first(struct ecm_db_iface_instance *ii)
5485{
5486 struct ecm_db_connection_instance *ci;
5487
5488 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5489
5490 spin_lock_bh(&ecm_db_lock);
5491 ci = ii->from_connections;
5492 if (ci) {
5493 _ecm_db_connection_ref(ci);
5494 }
5495 spin_unlock_bh(&ecm_db_lock);
5496
5497 return ci;
5498}
5499EXPORT_SYMBOL(ecm_db_iface_connections_from_get_and_ref_first);
5500
5501/*
5502 * ecm_db_iface_connections_to_get_and_ref_first()
5503 * Return a reference to the first connection made to this iface
5504 */
5505struct ecm_db_connection_instance *ecm_db_iface_connections_to_get_and_ref_first(struct ecm_db_iface_instance *ii)
5506{
5507 struct ecm_db_connection_instance *ci;
5508
5509 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5510
5511 spin_lock_bh(&ecm_db_lock);
5512 ci = ii->to_connections;
5513 if (ci) {
5514 _ecm_db_connection_ref(ci);
5515 }
5516 spin_unlock_bh(&ecm_db_lock);
5517
5518 return ci;
5519}
5520EXPORT_SYMBOL(ecm_db_iface_connections_to_get_and_ref_first);
5521
5522/*
5523 * ecm_db_iface_connections_nat_from_get_and_ref_first()
5524 * Return a reference to the first NAT connection made from this iface
5525 */
5526struct ecm_db_connection_instance *ecm_db_iface_connections_nat_from_get_and_ref_first(struct ecm_db_iface_instance *ii)
5527{
5528 struct ecm_db_connection_instance *ci;
5529
5530 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5531
5532 spin_lock_bh(&ecm_db_lock);
5533 ci = ii->from_nat_connections;
5534 if (ci) {
5535 _ecm_db_connection_ref(ci);
5536 }
5537 spin_unlock_bh(&ecm_db_lock);
5538
5539 return ci;
5540}
5541EXPORT_SYMBOL(ecm_db_iface_connections_nat_from_get_and_ref_first);
5542
5543/*
5544 * ecm_db_iface_connections_nat_to_get_and_ref_first()
5545 * Return a reference to the first NAT connection made to this iface
5546 */
5547struct ecm_db_connection_instance *ecm_db_iface_connections_nat_to_get_and_ref_first(struct ecm_db_iface_instance *ii)
5548{
5549 struct ecm_db_connection_instance *ci;
5550
5551 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5552
5553 spin_lock_bh(&ecm_db_lock);
5554 ci = ii->to_nat_connections;
5555 if (ci) {
5556 _ecm_db_connection_ref(ci);
5557 }
5558 spin_unlock_bh(&ecm_db_lock);
5559
5560 return ci;
5561}
5562EXPORT_SYMBOL(ecm_db_iface_connections_nat_to_get_and_ref_first);
5563
5564/*
5565 * ecm_db_connection_iface_from_get_and_ref_next()
5566 * Return reference to next connection in from iface chain
5567 */
5568struct ecm_db_connection_instance *ecm_db_connection_iface_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5569{
5570 struct ecm_db_connection_instance *nci;
5571
5572 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5573
5574 spin_lock_bh(&ecm_db_lock);
5575 nci = ci->iface_from_next;
5576 if (nci) {
5577 _ecm_db_connection_ref(nci);
5578 }
5579 spin_unlock_bh(&ecm_db_lock);
5580
5581 return nci;
5582}
5583EXPORT_SYMBOL(ecm_db_connection_iface_from_get_and_ref_next);
5584
5585/*
5586 * ecm_db_connection_iface_to_get_and_ref_next()
5587 * Return reference to next connection in to iface chain
5588 */
5589struct ecm_db_connection_instance *ecm_db_connection_iface_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5590{
5591 struct ecm_db_connection_instance *nci;
5592
5593 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5594
5595 spin_lock_bh(&ecm_db_lock);
5596 nci = ci->iface_to_next;
5597 if (nci) {
5598 _ecm_db_connection_ref(nci);
5599 }
5600 spin_unlock_bh(&ecm_db_lock);
5601
5602 return nci;
5603}
5604EXPORT_SYMBOL(ecm_db_connection_iface_to_get_and_ref_next);
5605
5606/*
5607 * ecm_db_connection_iface_nat_from_get_and_ref_next()
5608 * Return reference to next connection in from NAT iface chain
5609 */
5610struct ecm_db_connection_instance *ecm_db_connection_iface_nat_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5611{
5612 struct ecm_db_connection_instance *nci;
5613
5614 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5615
5616 spin_lock_bh(&ecm_db_lock);
5617 nci = ci->iface_from_nat_next;
5618 if (nci) {
5619 _ecm_db_connection_ref(nci);
5620 }
5621 spin_unlock_bh(&ecm_db_lock);
5622
5623 return nci;
5624}
5625EXPORT_SYMBOL(ecm_db_connection_iface_nat_from_get_and_ref_next);
5626
5627/*
5628 * ecm_db_connection_iface_nat_to_get_and_ref_next()
5629 * Return reference to next connection in to NAT iface chain
5630 */
5631struct ecm_db_connection_instance *ecm_db_connection_iface_nat_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5632{
5633 struct ecm_db_connection_instance *nci;
5634
5635 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5636
5637 spin_lock_bh(&ecm_db_lock);
5638 nci = ci->iface_to_nat_next;
5639 if (nci) {
5640 _ecm_db_connection_ref(nci);
5641 }
5642 spin_unlock_bh(&ecm_db_lock);
5643
5644 return nci;
5645}
5646EXPORT_SYMBOL(ecm_db_connection_iface_nat_to_get_and_ref_next);
5647
5648/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005649 * ecm_db_iface_nodes_get_and_ref_first()
5650 * Return a reference to the first node made from this iface
5651 */
5652struct ecm_db_node_instance *ecm_db_iface_nodes_get_and_ref_first(struct ecm_db_iface_instance *ii)
5653{
5654 struct ecm_db_node_instance *ni;
5655
5656 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5657
5658 spin_lock_bh(&ecm_db_lock);
5659 ni = ii->nodes;
5660 if (ni) {
5661 _ecm_db_node_ref(ni);
5662 }
5663 spin_unlock_bh(&ecm_db_lock);
5664
5665 return ni;
5666}
5667EXPORT_SYMBOL(ecm_db_iface_nodes_get_and_ref_first);
5668
5669/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005670 * ecm_db_iface_node_count_get()
5671 * Return the number of nodes to this iface
5672 */
5673int ecm_db_iface_node_count_get(struct ecm_db_iface_instance *ii)
5674{
5675 int count;
5676
5677 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305678
Ben Menchaca84f36632014-02-28 20:57:38 +00005679 spin_lock_bh(&ecm_db_lock);
5680 count = ii->node_count;
5681 spin_unlock_bh(&ecm_db_lock);
5682 return count;
5683}
5684EXPORT_SYMBOL(ecm_db_iface_node_count_get);
5685
5686/*
5687 * ecm_db_host_mapping_count_get()
5688 * Return the number of mappings to this host
5689 */
5690int ecm_db_host_mapping_count_get(struct ecm_db_host_instance *hi)
5691{
5692 int count;
5693
5694 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305695
Ben Menchaca84f36632014-02-28 20:57:38 +00005696 spin_lock_bh(&ecm_db_lock);
5697 count = hi->mapping_count;
5698 spin_unlock_bh(&ecm_db_lock);
5699 return count;
5700}
5701EXPORT_SYMBOL(ecm_db_host_mapping_count_get);
Gareth Williamsb5903892015-03-20 15:13:07 +00005702#endif
5703
5704/*
5705 * ecm_db_mapping_host_get_and_ref()
5706 */
5707struct ecm_db_host_instance *ecm_db_mapping_host_get_and_ref(struct ecm_db_mapping_instance *mi)
5708{
5709 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
5710
5711 spin_lock_bh(&ecm_db_lock);
5712 _ecm_db_host_ref(mi->host);
5713 spin_unlock_bh(&ecm_db_lock);
5714 return mi->host;
5715}
5716EXPORT_SYMBOL(ecm_db_mapping_host_get_and_ref);
5717
5718/*
5719 * ecm_db_node_iface_get_and_ref()
5720 */
5721struct ecm_db_iface_instance *ecm_db_node_iface_get_and_ref(struct ecm_db_node_instance *ni)
5722{
5723 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
5724
5725 spin_lock_bh(&ecm_db_lock);
5726 _ecm_db_iface_ref(ni->iface);
5727 spin_unlock_bh(&ecm_db_lock);
5728 return ni->iface;
5729}
5730EXPORT_SYMBOL(ecm_db_node_iface_get_and_ref);
Ben Menchaca84f36632014-02-28 20:57:38 +00005731
5732/*
5733 * ecm_db_mapping_connections_total_count_get()
5734 * Return the total number of connections (NAT and non-NAT) this mapping has
5735 */
5736int ecm_db_mapping_connections_total_count_get(struct ecm_db_mapping_instance *mi)
5737{
5738 int count;
5739
5740 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305741
Ben Menchaca84f36632014-02-28 20:57:38 +00005742 spin_lock_bh(&ecm_db_lock);
5743 count = mi->from + mi->to + mi->nat_from + mi->nat_to;
5744 DEBUG_ASSERT(count >= 0, "%p: Count overflow from: %d, to: %d, nat_from: %d, nat_to: %d\n", mi, mi->from, mi->to, mi->nat_from, mi->nat_to);
5745 spin_unlock_bh(&ecm_db_lock);
5746 return count;
5747}
5748EXPORT_SYMBOL(ecm_db_mapping_connections_total_count_get);
5749
5750/*
5751 * ecm_db_connection_mapping_from_get_and_ref()
5752 * Return a reference to the from mapping of the connection
5753 */
5754struct ecm_db_mapping_instance *ecm_db_connection_mapping_from_get_and_ref(struct ecm_db_connection_instance *ci)
5755{
5756 struct ecm_db_mapping_instance *mi;
5757
5758 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305759
Ben Menchaca84f36632014-02-28 20:57:38 +00005760 spin_lock_bh(&ecm_db_lock);
5761 mi = ci->mapping_from;
5762 _ecm_db_mapping_ref(mi);
5763 spin_unlock_bh(&ecm_db_lock);
5764 return mi;
5765}
5766EXPORT_SYMBOL(ecm_db_connection_mapping_from_get_and_ref);
5767
5768/*
5769 * ecm_db_connection_mapping_nat_from_get_and_ref()
5770 * Return a reference to the from NAT mapping of the connection
5771 */
5772struct ecm_db_mapping_instance *ecm_db_connection_mapping_nat_from_get_and_ref(struct ecm_db_connection_instance *ci)
5773{
5774 struct ecm_db_mapping_instance *mi;
5775
5776 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305777
Ben Menchaca84f36632014-02-28 20:57:38 +00005778 spin_lock_bh(&ecm_db_lock);
5779 mi = ci->mapping_nat_from;
5780 _ecm_db_mapping_ref(mi);
5781 spin_unlock_bh(&ecm_db_lock);
5782 return mi;
5783}
5784EXPORT_SYMBOL(ecm_db_connection_mapping_nat_from_get_and_ref);
5785
5786/*
5787 * ecm_db_connection_mapping_to_get_and_ref()
5788 * Return a reference to the from mapping of the connection
5789 */
5790struct ecm_db_mapping_instance *ecm_db_connection_mapping_to_get_and_ref(struct ecm_db_connection_instance *ci)
5791{
5792 struct ecm_db_mapping_instance *mi;
5793
5794 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305795
Ben Menchaca84f36632014-02-28 20:57:38 +00005796 spin_lock_bh(&ecm_db_lock);
5797 mi = ci->mapping_to;
5798 _ecm_db_mapping_ref(mi);
5799 spin_unlock_bh(&ecm_db_lock);
5800 return mi;
5801}
5802EXPORT_SYMBOL(ecm_db_connection_mapping_to_get_and_ref);
5803
5804/*
5805 * ecm_db_connection_mapping_to_nat_get_and_ref()
5806 * Return a reference to the from NAT mapping of the connection
5807 */
5808struct ecm_db_mapping_instance *ecm_db_connection_mapping_nat_to_get_and_ref(struct ecm_db_connection_instance *ci)
5809{
5810 struct ecm_db_mapping_instance *mi;
5811
5812 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305813
Ben Menchaca84f36632014-02-28 20:57:38 +00005814 spin_lock_bh(&ecm_db_lock);
5815 mi = ci->mapping_nat_to;
5816 _ecm_db_mapping_ref(mi);
5817 spin_unlock_bh(&ecm_db_lock);
5818 return mi;
5819}
5820EXPORT_SYMBOL(ecm_db_connection_mapping_nat_to_get_and_ref);
5821
5822/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005823 * ecm_db_timer_groups_check()
5824 * Check for expired group entries, returns the number that have expired
5825 */
5826static uint32_t ecm_db_timer_groups_check(uint32_t time_now)
5827{
5828 ecm_db_timer_group_t i;
5829 uint32_t expired = 0;
5830
5831 DEBUG_TRACE("Timer groups check start %u\n", time_now);
5832
5833 /*
5834 * Examine all timer groups for expired entries.
5835 */
5836 for (i = 0; i < ECM_DB_TIMER_GROUPS_MAX; ++i) {
5837 struct ecm_db_timer_group *timer_group;
5838
5839 /*
5840 * The group tail tracks the oldest entry so that is what we examine.
5841 */
5842 timer_group = &ecm_db_timer_groups[i];
5843 spin_lock_bh(&ecm_db_lock);
5844 while (timer_group->tail) {
5845 struct ecm_db_timer_group_entry *tge;
5846
5847 tge = timer_group->tail;
5848 if (tge->timeout > time_now) {
5849 /*
5850 * Not expired - and no further will be as they are in order
5851 */
5852 break;
5853 }
5854
5855 /*
5856 * Has expired - remove the entry from the list and invoke the callback
5857 * NOTE: We know the entry is at the tail of the group
5858 */
5859 if (tge->prev) {
5860 tge->prev->next = NULL;
5861 } else {
5862 /*
5863 * First in the group
5864 */
5865 DEBUG_ASSERT(timer_group->head == tge, "%p: bad head, expecting %p got %p\n", timer_group, tge, timer_group->head);
5866 timer_group->head = NULL;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305867 }
Ben Menchaca84f36632014-02-28 20:57:38 +00005868 timer_group->tail = tge->prev;
5869 tge->group = ECM_DB_TIMER_GROUPS_MAX;
5870 spin_unlock_bh(&ecm_db_lock);
5871 expired++;
5872 DEBUG_TRACE("%p: Expired\n", tge);
5873 tge->fn(tge->arg);
5874 spin_lock_bh(&ecm_db_lock);
5875 }
5876 spin_unlock_bh(&ecm_db_lock);
5877 }
5878
5879 spin_lock_bh(&ecm_db_lock);
5880 time_now = ecm_db_time;
5881 spin_unlock_bh(&ecm_db_lock);
5882 DEBUG_TRACE("Timer groups check end %u, expired count %u\n", time_now, expired);
5883 return expired;
5884}
5885
5886/*
5887 * ecm_db_connection_classifier_assign()
5888 * Assign a classifier to the connection assigned classifier list.
5889 *
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005890 * This adds the classifier in the ci->assignments list in ascending priority order according to the classifier type.
5891 * Only assigned classifiers are in this list, allowing fast retrival of current assignments, avoiding the need to skip over unassigned classifiers.
Ben Menchaca84f36632014-02-28 20:57:38 +00005892 * Because there is only one of each type of classifier the classifier is also recorded in an array, the position in which is its type value.
5893 * This allows fast lookup based on type too.
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005894 * Further, the connection is recorded in the classifier type assignment array too, this permits iterating of all connections that are assigned to a TYPE of classifier.
Ben Menchaca84f36632014-02-28 20:57:38 +00005895 */
5896void ecm_db_connection_classifier_assign(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *new_ca)
5897{
5898 struct ecm_classifier_instance *ca;
5899 struct ecm_classifier_instance *ca_prev;
5900 ecm_classifier_type_t new_ca_type;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005901#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005902 struct ecm_db_connection_classifier_type_assignment *ta;
5903 struct ecm_db_connection_classifier_type_assignment_list *tal;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005904#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005905
Ben Menchaca84f36632014-02-28 20:57:38 +00005906 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5907
5908 /*
5909 * Get the type (which is also used as the priority)
5910 */
5911 new_ca_type = new_ca->type_get(new_ca);
5912
5913 /*
5914 * Connection holds ref to the classifier
5915 */
5916 new_ca->ref(new_ca);
5917
5918 /*
5919 * Find place to insert the classifier
5920 */
5921 spin_lock_bh(&ecm_db_lock);
5922 ca = ci->assignments;
5923 ca_prev = NULL;
5924 while (ca) {
5925 ecm_classifier_type_t ca_type;
5926 ca_type = ca->type_get(ca);
5927
5928 /*
5929 * If new ca is less important that the current assigned classifier insert here
5930 */
5931 if (new_ca_type < ca_type) {
5932 break;
5933 }
5934 ca_prev = ca;
5935 ca = ca->ca_next;
5936 }
5937
5938 /*
5939 * Insert new_ca before ca and after ca_prev.
5940 */
5941 new_ca->ca_prev = ca_prev;
5942 if (ca_prev) {
5943 ca_prev->ca_next = new_ca;
5944 } else {
5945 DEBUG_ASSERT(ci->assignments == ca, "%p: Bad assigmnment list, expecting: %p, got: %p\n", ci, ca, ci->assignments);
5946 ci->assignments = new_ca;
5947 }
5948
5949 new_ca->ca_next = ca;
5950 if (ca) {
5951 ca->ca_prev = new_ca;
5952 }
5953
5954 /*
5955 * Insert based on type too
5956 */
5957 DEBUG_ASSERT(ci->assignments_by_type[new_ca_type] == NULL, "%p: Only one of each type: %d may be registered, new: %p, existing, %p\n",
5958 ci, new_ca_type, new_ca, ci->assignments_by_type[new_ca_type]);
5959 ci->assignments_by_type[new_ca_type] = new_ca;
5960
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005961#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005962 /*
Murat Sezgince65bc12016-01-07 15:00:17 -08005963 * Default classifier will not be added to the classifier type assignment list.
5964 * Only assigned classifiers can be added.
5965 */
5966 if (new_ca_type == ECM_CLASSIFIER_TYPE_DEFAULT) {
5967 spin_unlock_bh(&ecm_db_lock);
5968 return;
5969 }
5970
5971 /*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005972 * Add the connection into the type assignment list too.
5973 */
5974 ta = &ci->type_assignment[new_ca_type];
5975 if (ta->pending_unassign) {
5976 /*
5977 * The connection is pending unassignment / removal from list, but since it has been
5978 * re-assigned to the same type of classifier we can just clear the flag and avoid the removal.
5979 * NOTE: pending_unassign is only ever true if the iteration count is non-zero i.e. iteration is in progress.
5980 */
5981 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
5982 DEBUG_ASSERT(ta->iteration_count != 0, "%p: Bad pending_unassign: type: %d, Iteration count zero\n", ci, new_ca_type);
5983 ta->pending_unassign = false;
5984 spin_unlock_bh(&ecm_db_lock);
5985 return;
5986 }
5987
5988 /*
5989 * iteration_count should be zero as there should not be a duplicate assignment of the same type.
5990 * This is because if iteration_count was non-zero then pending_unassign should have been true.
5991 */
5992 DEBUG_ASSERT(ta->iteration_count == 0, "%p: Type: %d, Iteration count not zero: %d\n", ci, new_ca_type, ta->iteration_count);
5993
5994 /*
5995 * Insert the connection into the classifier type assignment list, at the head
5996 */
5997 tal = &ecm_db_connection_classifier_type_assignments[new_ca_type];
5998 ta->next = tal->type_assignments_list;
5999 ta->prev = NULL;
6000
6001 /*
6002 * If there is an existing head, it is no longer the head
6003 */
6004 if (tal->type_assignments_list) {
6005 struct ecm_db_connection_classifier_type_assignment *talh;
6006 talh = &tal->type_assignments_list->type_assignment[new_ca_type];
6007 talh->prev = ci;
6008 }
6009
6010 /*
6011 * Set new head
6012 */
6013 tal->type_assignments_list = ci;
6014
6015 /*
6016 * Set magic
6017 */
6018 DEBUG_SET_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC);
6019
6020 /*
6021 * Increment assignment count
6022 */
6023 tal->type_assignment_count++;
6024 DEBUG_ASSERT(tal->type_assignment_count > 0, "Bad iteration count: %d\n", tal->type_assignment_count);
Gareth Williamsb39e7c22015-03-25 10:15:33 +00006025#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00006026 spin_unlock_bh(&ecm_db_lock);
6027}
6028EXPORT_SYMBOL(ecm_db_connection_classifier_assign);
6029
6030/*
6031 * ecm_db_connection_classifier_assignments_get_and_ref()
6032 * Populate the given array with references to the currently assigned classifiers.
6033 *
6034 * This function returns the number of assignments starting from [0].
6035 * [0] is the lowest priority classifier, [return_val - 1] is the highest priority.
6036 * Release each classifier when you are done, for convenience use ecm_db_connection_assignments_release().
6037 *
6038 * NOTE: The array also contains the default classifier too which of course will always be at [0]
6039 *
6040 * WARNING: The array MUST be of size ECM_CLASSIFIER_TYPES.
6041 */
6042int ecm_db_connection_classifier_assignments_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *assignments[])
6043{
6044 int aci_count;
6045 struct ecm_classifier_instance *aci;
6046 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6047
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006048 aci_count = 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00006049 spin_lock_bh(&ecm_db_lock);
6050 aci = ci->assignments;
6051 while (aci) {
6052 aci->ref(aci);
6053 assignments[aci_count++] = aci;
6054 aci = aci->ca_next;
6055 }
6056 spin_unlock_bh(&ecm_db_lock);
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006057 DEBUG_ASSERT(aci_count >= 1, "%p: Must have at least default classifier!\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00006058 return aci_count;
6059}
6060EXPORT_SYMBOL(ecm_db_connection_classifier_assignments_get_and_ref);
6061
6062/*
6063 * ecm_db_connection_assignments_release()
6064 * Release references to classifiers in the assignments array
6065 */
6066void ecm_db_connection_assignments_release(int assignment_count, struct ecm_classifier_instance *assignments[])
6067{
6068 int i;
6069 for (i = 0; i < assignment_count; ++i) {
6070 struct ecm_classifier_instance *aci = assignments[i];
6071 if (aci) {
6072 aci->deref(aci);
6073 }
6074 }
6075}
6076EXPORT_SYMBOL(ecm_db_connection_assignments_release);
6077
6078/*
6079 * ecm_db_connection_assigned_classifier_find_and_ref()
6080 * Return a ref to classifier of the requested type, if found
6081 */
6082struct ecm_classifier_instance *ecm_db_connection_assigned_classifier_find_and_ref(struct ecm_db_connection_instance *ci, ecm_classifier_type_t type)
6083{
6084 struct ecm_classifier_instance *ca;
6085 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6086 spin_lock_bh(&ecm_db_lock);
6087 ca = ci->assignments_by_type[type];
6088 if (ca) {
6089 ca->ref(ca);
6090 }
6091 spin_unlock_bh(&ecm_db_lock);
6092 return ca;
6093}
6094EXPORT_SYMBOL(ecm_db_connection_assigned_classifier_find_and_ref);
6095
6096/*
6097 * ecm_db_connection_classifier_unassign()
6098 * Unassign a classifier
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006099 *
6100 * The default classifier cannot be unassigned.
Ben Menchaca84f36632014-02-28 20:57:38 +00006101 */
6102void ecm_db_connection_classifier_unassign(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *cci)
6103{
6104 ecm_classifier_type_t ca_type;
Ben Menchaca84f36632014-02-28 20:57:38 +00006105
Shyam Sunder8793f612016-01-06 20:16:20 +05306106 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00006107
Ben Menchaca84f36632014-02-28 20:57:38 +00006108 /*
6109 * Get the type
6110 */
6111 ca_type = cci->type_get(cci);
Shyam Sunder8793f612016-01-06 20:16:20 +05306112 DEBUG_ASSERT(ca_type != ECM_CLASSIFIER_TYPE_DEFAULT, "%p: Cannot unassign default", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00006113
Murat Sezginfa915da2016-04-04 16:45:34 -07006114 if (ca_type >= ECM_CLASSIFIER_TYPES) {
6115 DEBUG_WARN("%p: ca_type: %d is higher than the max classifier type number: %d\n", ci, ca_type, (ECM_CLASSIFIER_TYPES - 1));
6116 return;
6117 }
6118
Ben Menchaca84f36632014-02-28 20:57:38 +00006119 DEBUG_TRACE("%p: Unassign type: %d, classifier: %p\n", ci, ca_type, cci);
6120
Ben Menchaca84f36632014-02-28 20:57:38 +00006121 /*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006122 * NOTE: It is possible that in SMP this classifier has already been unassigned.
Ben Menchaca84f36632014-02-28 20:57:38 +00006123 */
Shyam Sunder8793f612016-01-06 20:16:20 +05306124 spin_lock_bh(&ecm_db_lock);
Gareth Williamsee0a38a2014-06-05 15:41:20 +01006125 if (ci->assignments_by_type[ca_type] == NULL) {
6126 spin_unlock_bh(&ecm_db_lock);
6127 DEBUG_TRACE("%p: Classifier type: %d already unassigned\n", ci, ca_type);
6128 return;
6129 }
Shyam Sunder8793f612016-01-06 20:16:20 +05306130 _ecm_db_connection_classifier_unassign(ci, cci, ca_type);
Ben Menchaca84f36632014-02-28 20:57:38 +00006131 spin_unlock_bh(&ecm_db_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00006132}
6133EXPORT_SYMBOL(ecm_db_connection_classifier_unassign);
6134
Gareth Williamsb39e7c22015-03-25 10:15:33 +00006135#ifdef ECM_DB_CTA_TRACK_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00006136/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006137 * ecm_db_connection_by_classifier_type_assignment_get_and_ref_first()
6138 * Return a reference to the first connection for which a classifier of the given type is associated with
6139 *
6140 * WARNING: YOU MUST NOT USE ecm_db_connection_deref() to release the references taken using this API.
6141 * YOU MUST use ecm_db_connection_by_classifier_type_assignment_deref(), this ensures type assignment list integrity.
6142 */
6143struct ecm_db_connection_instance *ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ecm_classifier_type_t ca_type)
6144{
6145 struct ecm_db_connection_classifier_type_assignment_list *tal;
6146 struct ecm_db_connection_instance *ci;
6147
6148 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
6149
6150 DEBUG_TRACE("Get and ref first connection assigned with classifier type: %d\n", ca_type);
6151
6152 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
6153 spin_lock_bh(&ecm_db_lock);
6154 ci = tal->type_assignments_list;
6155 while (ci) {
6156 struct ecm_db_connection_classifier_type_assignment *ta;
6157 ta = &ci->type_assignment[ca_type];
6158 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
6159
6160 if (ta->pending_unassign) {
6161 DEBUG_TRACE("Skip %p, pending unassign for type: %d\n", ci, ca_type);
6162 ci = ta->next;
6163 continue;
6164 }
6165
6166 /*
6167 * Take reference to this connection.
6168 * NOTE: Hold both the connection and the assignment entry so that when we unlock both the connection
6169 * and the type assignment list entry maintains integrity.
6170 */
6171 _ecm_db_connection_ref(ci);
6172 ta->iteration_count++;
6173 DEBUG_ASSERT(ta->iteration_count > 0, "Bad Iteration count: %d for type: %d, connection: %p\n", ta->iteration_count, ca_type, ci);
6174 spin_unlock_bh(&ecm_db_lock);
6175 return ci;
6176 }
6177 spin_unlock_bh(&ecm_db_lock);
6178 return NULL;
6179}
6180EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_get_and_ref_first);
6181
6182/*
6183 * ecm_db_connection_by_classifier_type_assignment_get_and_ref_next()
6184 * Return a reference to the next connection for which a classifier of the given type is associated with.
6185 *
6186 * WARNING: YOU MUST NOT USE ecm_db_connection_deref() to release the references taken using this API.
6187 * YOU MUST use ecm_db_connection_by_classifier_type_assignment_deref(), this ensures type assignment list integrity.
6188 */
6189struct ecm_db_connection_instance *ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(struct ecm_db_connection_instance *ci, ecm_classifier_type_t ca_type)
6190{
6191 struct ecm_db_connection_classifier_type_assignment *ta;
6192 struct ecm_db_connection_instance *cin;
6193
6194 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
6195 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6196
6197 DEBUG_TRACE("Get and ref next connection assigned with classifier type: %d and ci: %p\n", ca_type, ci);
6198
6199 spin_lock_bh(&ecm_db_lock);
6200 ta = &ci->type_assignment[ca_type];
6201 cin = ta->next;
6202 while (cin) {
6203 struct ecm_db_connection_classifier_type_assignment *tan;
6204
6205 tan = &cin->type_assignment[ca_type];
6206 DEBUG_CHECK_MAGIC(tan, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", tan, cin);
6207
6208 if (tan->pending_unassign) {
6209 DEBUG_TRACE("Skip %p, pending unassign for type: %d\n", cin, ca_type);
6210 cin = tan->next;
6211 continue;
6212 }
6213
6214 /*
6215 * Take reference to this connection.
6216 * NOTE: Hold both the connection and the assignment entry so that when we unlock both the connection
6217 * and the type assignment list entry maintains integrity.
6218 */
6219 _ecm_db_connection_ref(cin);
6220 tan->iteration_count++;
6221 DEBUG_ASSERT(tan->iteration_count > 0, "Bad Iteration count: %d for type: %d, connection: %p\n", tan->iteration_count, ca_type, cin);
6222 spin_unlock_bh(&ecm_db_lock);
6223 return cin;
6224 }
6225 spin_unlock_bh(&ecm_db_lock);
6226 return NULL;
6227}
6228EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_get_and_ref_next);
6229
6230/*
6231 * ecm_db_connection_by_classifier_type_assignment_deref()
6232 * Release a reference to a connection while iterating a classifier type assignment list
6233 */
6234void ecm_db_connection_by_classifier_type_assignment_deref(struct ecm_db_connection_instance *ci, ecm_classifier_type_t ca_type)
6235{
6236 struct ecm_db_connection_classifier_type_assignment_list *tal;
6237 struct ecm_db_connection_classifier_type_assignment *ta;
6238
6239 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
6240 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6241
6242 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
6243
6244 /*
6245 * Drop the iteration count
6246 */
6247 spin_lock_bh(&ecm_db_lock);
6248 ta = &ci->type_assignment[ca_type];
6249 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
6250 ta->iteration_count--;
6251 DEBUG_ASSERT(ta->iteration_count >= 0, "Bad Iteration count: %d for type: %d, connection: %p\n", ta->iteration_count, ca_type, ci);
6252
6253 /*
6254 * If there are no more iterations on-going and this is pending unassign then we can remove it from the assignments list
6255 */
6256 if (ta->pending_unassign && (ta->iteration_count == 0)) {
6257 DEBUG_INFO("%p: Remove type assignment: %d\n", ci, ca_type);
6258 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
6259 }
6260 spin_unlock_bh(&ecm_db_lock);
6261 ecm_db_connection_deref(ci);
6262}
6263EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_deref);
6264
6265/*
6266 * ecm_db_connection_make_defunct_by_assignment_type()
6267 * Make defunct all connections that are currently assigned to a classifier of the given type
6268 */
6269void ecm_db_connection_make_defunct_by_assignment_type(ecm_classifier_type_t ca_type)
6270{
6271 struct ecm_db_connection_instance *ci;
6272
6273 DEBUG_INFO("Make defunct all assigned to type: %d\n", ca_type);
6274
6275 ci = ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ca_type);
6276 while (ci) {
6277 struct ecm_db_connection_instance *cin;
6278
6279 DEBUG_TRACE("%p: Make defunct: %d\n", ci, ca_type);
6280 ecm_db_connection_make_defunct(ci);
6281
6282 cin = ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(ci, ca_type);
6283 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
6284 ci = cin;
6285 }
6286}
6287EXPORT_SYMBOL(ecm_db_connection_make_defunct_by_assignment_type);
6288
6289/*
6290 * ecm_db_connection_regenerate_by_assignment_type()
6291 * Cause regeneration all connections that are currently assigned to a classifier of the given type
6292 */
6293void ecm_db_connection_regenerate_by_assignment_type(ecm_classifier_type_t ca_type)
6294{
6295 struct ecm_db_connection_instance *ci;
6296
6297 DEBUG_INFO("Regenerate all assigned to type: %d\n", ca_type);
6298
6299 ci = ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ca_type);
6300 while (ci) {
6301 struct ecm_db_connection_instance *cin;
6302
6303 DEBUG_TRACE("%p: Re-generate: %d\n", ci, ca_type);
Xiaoping Faned6d37e2015-09-17 14:13:47 -07006304 ecm_db_connection_regenerate(ci);
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006305
6306 cin = ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(ci, ca_type);
6307 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
6308 ci = cin;
6309 }
6310}
6311EXPORT_SYMBOL(ecm_db_connection_regenerate_by_assignment_type);
Gareth Williamsb39e7c22015-03-25 10:15:33 +00006312#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006313
6314/*
Ben Menchaca84f36632014-02-28 20:57:38 +00006315 * ecm_db_connection_from_interfaces_get_and_ref()
6316 * Return the interface heirarchy from which this connection is established.
6317 *
6318 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6319 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6320 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6321 *
6322 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6323 */
6324int32_t ecm_db_connection_from_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6325{
6326 int32_t n;
6327 int32_t i;
6328 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6329
6330 spin_lock_bh(&ecm_db_lock);
6331 n = ci->from_interface_first;
6332 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6333 interfaces[i] = ci->from_interfaces[i];
6334 _ecm_db_iface_ref(interfaces[i]);
6335 }
6336 spin_unlock_bh(&ecm_db_lock);
6337 return n;
6338}
6339EXPORT_SYMBOL(ecm_db_connection_from_interfaces_get_and_ref);
6340
6341/*
6342 * ecm_db_connection_to_interfaces_get_and_ref()
6343 * Return the interface heirarchy to which this connection is established.
6344 *
6345 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6346 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6347 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6348 *
6349 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6350 */
6351int32_t ecm_db_connection_to_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6352{
6353 int32_t n;
6354 int32_t i;
6355 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6356
6357 spin_lock_bh(&ecm_db_lock);
6358 n = ci->to_interface_first;
6359 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6360 interfaces[i] = ci->to_interfaces[i];
6361 _ecm_db_iface_ref(interfaces[i]);
6362 }
6363 spin_unlock_bh(&ecm_db_lock);
6364 return n;
6365}
6366EXPORT_SYMBOL(ecm_db_connection_to_interfaces_get_and_ref);
6367
6368/*
6369 * ecm_db_connection_from_nat_interfaces_get_and_ref()
6370 * Return the interface heirarchy from (nat) which this connection is established.
6371 *
6372 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6373 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6374 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6375 *
6376 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6377 */
6378int32_t ecm_db_connection_from_nat_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6379{
6380 int32_t n;
6381 int32_t i;
6382 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6383
6384 spin_lock_bh(&ecm_db_lock);
6385 n = ci->from_nat_interface_first;
6386 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6387 interfaces[i] = ci->from_nat_interfaces[i];
6388 _ecm_db_iface_ref(interfaces[i]);
6389 }
6390 spin_unlock_bh(&ecm_db_lock);
6391 return n;
6392}
6393EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_get_and_ref);
6394
6395/*
6396 * ecm_db_connection_to_nat_interfaces_get_and_ref()
6397 * Return the interface heirarchy to (nat) which this connection is established.
6398 *
6399 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6400 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6401 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6402 *
6403 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6404 */
6405int32_t ecm_db_connection_to_nat_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6406{
6407 int32_t n;
6408 int32_t i;
6409 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6410
6411 spin_lock_bh(&ecm_db_lock);
6412 n = ci->to_nat_interface_first;
6413 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6414 interfaces[i] = ci->to_nat_interfaces[i];
6415 _ecm_db_iface_ref(interfaces[i]);
6416 }
6417 spin_unlock_bh(&ecm_db_lock);
6418 return n;
6419}
6420EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_get_and_ref);
6421
6422/*
6423 * ecm_db_connection_interfaces_deref()
6424 * Release all interfaces in the given interfaces heirarchy array.
6425 *
6426 * 'first' is the number returned by one of the ecm_db_connection_xx_interfaces_get_and_ref().
6427 * You should NOT have released any references to any of the interfaces in the array youself, this releases them all.
6428 */
6429void ecm_db_connection_interfaces_deref(struct ecm_db_iface_instance *interfaces[], int32_t first)
6430{
6431 int32_t i;
6432 DEBUG_ASSERT((first >= 0) && (first <= ECM_DB_IFACE_HEIRARCHY_MAX), "Bad first: %d\n", first);
6433
6434 for (i = first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6435 ecm_db_iface_deref(interfaces[i]);
6436 }
6437}
6438EXPORT_SYMBOL(ecm_db_connection_interfaces_deref);
6439
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306440#ifdef ECM_MULTICAST_ENABLE
6441/*
6442 * ecm_db_multicast_connection_to_interfaces_reset()
6443 * Reset the 'to' interfaces heirarchy with a new set of destination interfaces for
6444 * the multicast connection
6445 */
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306446int ecm_db_multicast_connection_to_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces, int32_t *new_first)
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306447{
6448 struct ecm_db_iface_instance *ii_temp;
6449 struct ecm_db_iface_instance *ii_single;
6450 struct ecm_db_iface_instance **ifaces;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306451 struct ecm_db_iface_instance *ii_db;
6452 struct ecm_db_iface_instance *ii_db_single;
6453 struct ecm_db_iface_instance **ifaces_db;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306454 int32_t *nf_p;
6455 int32_t heirarchy_index;
6456 int32_t i;
6457 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6458
6459 /*
6460 * First remove all old interface hierarchies if any hierarchy
6461 * uphold in the ci->to_mcast_interfaces.
6462 */
6463 ecm_db_multicast_connection_to_interfaces_clear(ci);
6464
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306465 ci->to_mcast_interfaces = (struct ecm_db_iface_instance *)kzalloc(ECM_DB_TO_MCAST_INTERFACES_SIZE, GFP_ATOMIC | __GFP_NOWARN);
6466 if (!ci->to_mcast_interfaces) {
6467 DEBUG_WARN("%p: Memory is not available for to_mcast_interfaces\n", ci);
6468 return -1;
6469 }
6470
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306471 /*
6472 * Iterate the to interface list and add the new interface hierarchies
6473 */
6474 spin_lock_bh(&ecm_db_lock);
6475
6476 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
6477 ii_temp = ecm_db_multicast_if_heirarchy_get(interfaces, heirarchy_index);
6478 nf_p = ecm_db_multicast_if_first_get_at_index(new_first, heirarchy_index);
6479
6480 if (*nf_p == ECM_DB_IFACE_HEIRARCHY_MAX) {
6481 continue;
6482 }
6483
6484 for (i = *nf_p; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6485
6486 /*
6487 * Store valid dest interface list into DB connection
6488 */
6489 ii_single = ecm_db_multicast_if_instance_get_at_index(ii_temp, i);
6490 ifaces = (struct ecm_db_iface_instance **)ii_single;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306491
6492 ii_db = ecm_db_multicast_if_heirarchy_get(ci->to_mcast_interfaces, heirarchy_index);
6493 ii_db_single = ecm_db_multicast_if_instance_get_at_index(ii_db, i);
6494 ifaces_db = (struct ecm_db_iface_instance **)ii_db_single;
6495
6496 *ifaces_db = *ifaces;
6497 _ecm_db_iface_ref(*ifaces_db);
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306498 }
6499 }
6500
6501 /*
6502 * Update the first indices
6503 */
6504 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
6505 nf_p = ecm_db_multicast_if_first_get_at_index(new_first, heirarchy_index);
6506 ci->to_mcast_interface_first[heirarchy_index] = *nf_p;
6507 }
6508
6509 ci->to_mcast_interfaces_set = true;
6510 spin_unlock_bh(&ecm_db_lock);
6511
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306512 return 0;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306513}
6514EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_reset);
6515
6516/*
6517 * ecm_db_multicast_connection_to_interfaces_update()
6518 * Merge the latest valid multicast destination interfaces into DB Connection
6519 * instance. The new list holds the updated list of interfaces for the multicast
6520 * connection, due to JOIN updates.
6521 */
6522void ecm_db_multicast_connection_to_interfaces_update(struct ecm_db_connection_instance *ci,
6523 struct ecm_db_iface_instance *interfaces, int32_t *mc_join_first, int32_t *mc_join_valid_idx)
6524{
6525 struct ecm_db_iface_instance *ii_temp;
6526 struct ecm_db_iface_instance *ii_single;
6527 struct ecm_db_iface_instance **ifaces;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306528 struct ecm_db_iface_instance *ii_db;
6529 struct ecm_db_iface_instance *ii_db_single;
6530 struct ecm_db_iface_instance **ifaces_db;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306531 int32_t *join_first;
6532 int32_t *join_idx;
6533 int heirarchy_index;
6534 int32_t if_index;
6535 int32_t i;
6536
6537 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6538
6539 /*
6540 * Iterate the to interface list, adding in the new
6541 */
6542 spin_lock_bh(&ecm_db_lock);
6543 for (heirarchy_index = 0, if_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
6544 ii_temp = ecm_db_multicast_if_heirarchy_get(interfaces, if_index);
6545 join_first = ecm_db_multicast_if_first_get_at_index(mc_join_first, if_index);
6546 join_idx = ecm_db_multicast_if_num_get_at_index(mc_join_valid_idx, heirarchy_index);
6547
6548 if (*join_idx == 0) {
6549
6550 /*
6551 * No update for the interface at this index
6552 */
6553 continue;
6554 }
6555
6556 /*
6557 * This interface has joined the group. Add it to the list.
6558 */
6559 if (*join_first == ECM_DB_IFACE_HEIRARCHY_MAX) {
6560 if_index++;
6561 continue;
6562 }
6563
6564 ci->to_mcast_interface_first[heirarchy_index] = *join_first;
6565 for (i = *join_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6566
6567 /*
6568 * Store valid dest interface list into DB connection
6569 */
6570 ii_single = ecm_db_multicast_if_instance_get_at_index(ii_temp, i);
6571 ifaces = (struct ecm_db_iface_instance **)ii_single;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306572 ii_db = ecm_db_multicast_if_heirarchy_get(ci->to_mcast_interfaces, heirarchy_index);
6573 ii_db_single = ecm_db_multicast_if_instance_get_at_index(ii_db, i);
6574 ifaces_db = (struct ecm_db_iface_instance **)ii_db_single;
6575 *ifaces_db = *ifaces;
6576 _ecm_db_iface_ref(*ifaces_db);
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306577 }
6578 if_index++;
6579 }
6580 spin_unlock_bh(&ecm_db_lock);
6581 return;
6582}
6583EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_update);
6584#endif
6585
Ben Menchaca84f36632014-02-28 20:57:38 +00006586/*
6587 * ecm_db_connection_from_interfaces_reset()
6588 * Reset the from interfaces heirarchy with a new set of interfaces
6589 *
6590 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6591 * This is deliberate - it's stating that there is no list :-)
6592 */
6593void ecm_db_connection_from_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6594{
6595 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6596 int32_t old_first;
6597 int32_t i;
6598 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6599
6600 /*
6601 * Iterate the from interface list, removing the old and adding in the new
6602 */
6603 spin_lock_bh(&ecm_db_lock);
6604 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6605 /*
6606 * Put any previous interface into the old list
6607 */
6608 old[i] = ci->from_interfaces[i];
6609 ci->from_interfaces[i] = NULL;
6610 if (i < new_first) {
6611 continue;
6612 }
6613 ci->from_interfaces[i] = interfaces[i];
6614 _ecm_db_iface_ref(ci->from_interfaces[i]);
6615 }
6616
6617 /*
6618 * Get old first and update to new first
6619 */
6620 old_first = ci->from_interface_first;
6621 ci->from_interface_first = new_first;
6622 ci->from_interface_set = true;
6623 spin_unlock_bh(&ecm_db_lock);
6624
6625 /*
6626 * Release old
6627 */
6628 ecm_db_connection_interfaces_deref(old, old_first);
6629}
6630EXPORT_SYMBOL(ecm_db_connection_from_interfaces_reset);
6631
6632/*
6633 * ecm_db_connection_to_interfaces_reset()
6634 * Reset the to interfaces heirarchy with a new set of interfaces
6635 *
6636 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6637 * This is deliberate - it's stating that there is no list :-)
6638 */
6639void ecm_db_connection_to_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6640{
6641 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6642 int32_t old_first;
6643 int32_t i;
6644 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6645
6646 /*
6647 * Iterate the to interface list, removing the old and adding in the new
6648 */
6649 spin_lock_bh(&ecm_db_lock);
6650 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6651 /*
6652 * Put any previous interface into the old list
6653 */
6654 old[i] = ci->to_interfaces[i];
6655 ci->to_interfaces[i] = NULL;
6656 if (i < new_first) {
6657 continue;
6658 }
6659 ci->to_interfaces[i] = interfaces[i];
6660 _ecm_db_iface_ref(ci->to_interfaces[i]);
6661 }
6662
6663 /*
6664 * Get old first and update to new first
6665 */
6666 old_first = ci->to_interface_first;
6667 ci->to_interface_first = new_first;
6668 ci->to_interface_set = true;
6669 spin_unlock_bh(&ecm_db_lock);
6670
6671 /*
6672 * Release old
6673 */
6674 ecm_db_connection_interfaces_deref(old, old_first);
6675}
6676EXPORT_SYMBOL(ecm_db_connection_to_interfaces_reset);
6677
6678/*
6679 * ecm_db_connection_from_nat_interfaces_reset()
6680 * Reset the from NAT interfaces heirarchy with a new set of interfaces
6681 *
6682 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6683 * This is deliberate - it's stating that there is no list :-)
6684 */
6685void ecm_db_connection_from_nat_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6686{
6687 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6688 int32_t old_first;
6689 int32_t i;
6690 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6691
6692 /*
6693 * Iterate the from nat interface list, removing the old and adding in the new
6694 */
6695 spin_lock_bh(&ecm_db_lock);
6696 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6697 /*
6698 * Put any previous interface into the old list
6699 */
6700 old[i] = ci->from_nat_interfaces[i];
6701 ci->from_nat_interfaces[i] = NULL;
6702 if (i < new_first) {
6703 continue;
6704 }
6705 ci->from_nat_interfaces[i] = interfaces[i];
6706 _ecm_db_iface_ref(ci->from_nat_interfaces[i]);
6707 }
6708
6709 /*
6710 * Get old first and update to new first
6711 */
6712 old_first = ci->from_nat_interface_first;
6713 ci->from_nat_interface_first = new_first;
6714 ci->from_nat_interface_set = true;
6715 spin_unlock_bh(&ecm_db_lock);
6716
6717 /*
6718 * Release old
6719 */
6720 ecm_db_connection_interfaces_deref(old, old_first);
6721}
6722EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_reset);
6723
6724/*
6725 * ecm_db_connection_to_nat_interfaces_reset()
6726 * Reset the to NAT interfaces heirarchy with a new set of interfaces.
6727 *
6728 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6729 * This is deliberate - it's stating that there is no list :-)
6730 */
6731void ecm_db_connection_to_nat_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6732{
6733 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6734 int32_t old_first;
6735 int32_t i;
6736 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6737
6738 /*
6739 * Iterate the to nat interface list, removing the old and adding in the new
6740 */
6741 spin_lock_bh(&ecm_db_lock);
6742 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6743 /*
6744 * Put any previous interface into the old list
6745 */
6746 old[i] = ci->to_nat_interfaces[i];
6747 ci->to_nat_interfaces[i] = NULL;
6748 if (i < new_first) {
6749 continue;
6750 }
6751 ci->to_nat_interfaces[i] = interfaces[i];
6752 _ecm_db_iface_ref(ci->to_nat_interfaces[i]);
6753 }
6754
6755 /*
6756 * Get old first and update to new first
6757 */
6758 old_first = ci->to_nat_interface_first;
6759 ci->to_nat_interface_first = new_first;
6760 ci->to_nat_interface_set = true;
6761 spin_unlock_bh(&ecm_db_lock);
6762
6763 /*
6764 * Release old
6765 */
6766 ecm_db_connection_interfaces_deref(old, old_first);
6767}
6768EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_reset);
6769
6770/*
6771 * ecm_db_connection_to_nat_interfaces_get_count()
6772 * Return the number of interfaces in the list
6773 */
6774int32_t ecm_db_connection_to_nat_interfaces_get_count(struct ecm_db_connection_instance *ci)
6775{
6776 int32_t first;
6777 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6778 spin_lock_bh(&ecm_db_lock);
6779 first = ci->to_nat_interface_first;
6780 spin_unlock_bh(&ecm_db_lock);
6781 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6782}
6783EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_get_count);
6784
6785/*
6786 * ecm_db_connection_from_nat_interfaces_get_count()
6787 * Return the number of interfaces in the list
6788 */
6789int32_t ecm_db_connection_from_nat_interfaces_get_count(struct ecm_db_connection_instance *ci)
6790{
6791 int32_t first;
6792 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6793 spin_lock_bh(&ecm_db_lock);
6794 first = ci->from_nat_interface_first;
6795 spin_unlock_bh(&ecm_db_lock);
6796 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6797}
6798EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_get_count);
6799
6800/*
6801 * ecm_db_connection_to_interfaces_get_count()
6802 * Return the number of interfaces in the list
6803 */
6804int32_t ecm_db_connection_to_interfaces_get_count(struct ecm_db_connection_instance *ci)
6805{
6806 int32_t first;
6807 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6808 spin_lock_bh(&ecm_db_lock);
6809 first = ci->to_interface_first;
6810 spin_unlock_bh(&ecm_db_lock);
6811 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6812}
6813EXPORT_SYMBOL(ecm_db_connection_to_interfaces_get_count);
6814
6815/*
6816 * ecm_db_connection_from_interfaces_get_count()
6817 * Return the number of interfaces in the list
6818 */
6819int32_t ecm_db_connection_from_interfaces_get_count(struct ecm_db_connection_instance *ci)
6820{
6821 int32_t first;
6822 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6823 spin_lock_bh(&ecm_db_lock);
6824 first = ci->from_interface_first;
6825 spin_unlock_bh(&ecm_db_lock);
6826 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6827}
6828EXPORT_SYMBOL(ecm_db_connection_from_interfaces_get_count);
6829
6830/*
6831 * ecm_db_connection_to_interfaces_set_check()
6832 * Returns true if the interface list has been set - even if set to an empty list!
6833 */
6834bool ecm_db_connection_to_interfaces_set_check(struct ecm_db_connection_instance *ci)
6835{
6836 bool set;
6837
6838 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6839 spin_lock_bh(&ecm_db_lock);
6840 set = ci->to_interface_set;
6841 spin_unlock_bh(&ecm_db_lock);
6842 return set;
6843}
6844EXPORT_SYMBOL(ecm_db_connection_to_interfaces_set_check);
6845
6846/*
6847 * ecm_db_connection_from_interfaces_set_check()
6848 * Returns true if the interface list has been set - even if set to an empty list!
6849 */
6850bool ecm_db_connection_from_interfaces_set_check(struct ecm_db_connection_instance *ci)
6851{
6852 bool set;
6853
6854 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6855 spin_lock_bh(&ecm_db_lock);
6856 set = ci->from_interface_set;
6857 spin_unlock_bh(&ecm_db_lock);
6858 return set;
6859}
6860EXPORT_SYMBOL(ecm_db_connection_from_interfaces_set_check);
6861
6862/*
6863 * ecm_db_connection_to_nat_interfaces_set_check()
6864 * Returns true if the interface list has been set - even if set to an empty list!
6865 */
6866bool ecm_db_connection_to_nat_interfaces_set_check(struct ecm_db_connection_instance *ci)
6867{
6868 bool set;
6869
6870 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6871 spin_lock_bh(&ecm_db_lock);
6872 set = ci->to_nat_interface_set;
6873 spin_unlock_bh(&ecm_db_lock);
6874 return set;
6875}
6876EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_set_check);
6877
6878/*
6879 * ecm_db_connection_from_nat_interfaces_set_check()
6880 * Returns true if the interface list has been set - even if set to an empty list!
6881 */
6882bool ecm_db_connection_from_nat_interfaces_set_check(struct ecm_db_connection_instance *ci)
6883{
6884 bool set;
6885
6886 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6887 spin_lock_bh(&ecm_db_lock);
6888 set = ci->from_nat_interface_set;
6889 spin_unlock_bh(&ecm_db_lock);
6890 return set;
6891}
6892EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_set_check);
6893
6894/*
6895 * ecm_db_connection_from_interfaces_clear()
6896 * Clear down the interfaces list, marking the list as not set
6897 */
6898void ecm_db_connection_from_interfaces_clear(struct ecm_db_connection_instance *ci)
6899{
6900 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
6901 int32_t discard_first;
6902 int32_t i;
6903
6904 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6905
6906 spin_lock_bh(&ecm_db_lock);
6907 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6908 discard[i] = ci->from_interfaces[i];
6909 }
6910
6911 discard_first = ci->from_interface_first;
6912 ci->from_interface_set = false;
6913 ci->from_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
6914 spin_unlock_bh(&ecm_db_lock);
6915
6916 /*
6917 * Release previous
6918 */
6919 ecm_db_connection_interfaces_deref(discard, discard_first);
6920}
6921EXPORT_SYMBOL(ecm_db_connection_from_interfaces_clear);
6922
6923/*
6924 * ecm_db_connection_from_nat_interfaces_clear()
6925 * Clear down the interfaces list, marking the list as not set
6926 */
6927void ecm_db_connection_from_nat_interfaces_clear(struct ecm_db_connection_instance *ci)
6928{
6929 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
6930 int32_t discard_first;
6931 int32_t i;
6932
6933 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6934
6935 spin_lock_bh(&ecm_db_lock);
6936 for (i = ci->from_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6937 discard[i] = ci->from_nat_interfaces[i];
6938 }
6939
6940 discard_first = ci->from_nat_interface_first;
6941 ci->from_nat_interface_set = false;
6942 ci->from_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
6943 spin_unlock_bh(&ecm_db_lock);
6944
6945 /*
6946 * Release previous
6947 */
6948 ecm_db_connection_interfaces_deref(discard, discard_first);
6949}
6950EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_clear);
6951
6952/*
6953 * ecm_db_connection_to_interfaces_clear()
6954 * Clear down the interfaces list, marking the list as not set
6955 */
6956void ecm_db_connection_to_interfaces_clear(struct ecm_db_connection_instance *ci)
6957{
6958 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
6959 int32_t discard_first;
6960 int32_t i;
6961
6962 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6963
6964 spin_lock_bh(&ecm_db_lock);
6965 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6966 discard[i] = ci->to_interfaces[i];
6967 }
6968
6969 discard_first = ci->to_interface_first;
6970 ci->to_interface_set = false;
6971 ci->to_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
6972 spin_unlock_bh(&ecm_db_lock);
6973
6974 /*
6975 * Release previous
6976 */
6977 ecm_db_connection_interfaces_deref(discard, discard_first);
6978}
6979EXPORT_SYMBOL(ecm_db_connection_to_interfaces_clear);
6980
6981/*
6982 * ecm_db_connection_to_nat_interfaces_clear()
6983 * Clear down the interfaces list, marking the list as not set
6984 */
6985void ecm_db_connection_to_nat_interfaces_clear(struct ecm_db_connection_instance *ci)
6986{
6987 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
6988 int32_t discard_first;
6989 int32_t i;
6990
6991 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6992
6993 spin_lock_bh(&ecm_db_lock);
6994 for (i = ci->to_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6995 discard[i] = ci->to_nat_interfaces[i];
6996 }
6997
6998 discard_first = ci->to_nat_interface_first;
6999 ci->to_nat_interface_set = false;
7000 ci->to_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
7001 spin_unlock_bh(&ecm_db_lock);
7002
7003 /*
7004 * Release previous
7005 */
7006 ecm_db_connection_interfaces_deref(discard, discard_first);
7007}
7008EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_clear);
7009
7010/*
Murat Sezginfdb595e2016-05-10 11:27:37 -07007011 * ecm_db_front_end_instance_ref_and_set()
7012 * Refs and sets the front end instance of connection.
7013 */
7014void ecm_db_front_end_instance_ref_and_set(struct ecm_db_connection_instance *ci, struct ecm_front_end_connection_instance *feci)
7015{
7016 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
7017
7018 feci->ref(feci);
7019 ci->feci = feci;
7020}
7021EXPORT_SYMBOL(ecm_db_front_end_instance_ref_and_set);
7022
7023/*
Ben Menchaca84f36632014-02-28 20:57:38 +00007024 * ecm_db_connection_add()
7025 * Add the connection into the database.
7026 *
7027 * NOTE: The parameters are DIRECTIONAL in terms of which mapping established the connection.
7028 * NOTE: Dir confirms if this is an egressing or ingressing connection. This applies to firewalling front ends mostly. If INGRESS then mapping_from is the WAN side. If EGRESS then mapping_to is the WAN side.
7029 */
7030void ecm_db_connection_add(struct ecm_db_connection_instance *ci,
Ben Menchaca84f36632014-02-28 20:57:38 +00007031 struct ecm_db_mapping_instance *mapping_from, struct ecm_db_mapping_instance *mapping_to,
7032 struct ecm_db_mapping_instance *mapping_nat_from, struct ecm_db_mapping_instance *mapping_nat_to,
Gareth Williams90f2a282014-08-27 15:56:25 +01007033 struct ecm_db_node_instance *from_node, struct ecm_db_node_instance *to_node,
7034 struct ecm_db_node_instance *from_nat_node, struct ecm_db_node_instance *to_nat_node,
Gareth Williams3e5b37f2015-05-13 10:04:12 +01007035 int ip_version,
Ben Menchaca84f36632014-02-28 20:57:38 +00007036 int protocol, ecm_db_direction_t dir,
7037 ecm_db_connection_final_callback_t final,
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07007038 ecm_db_connection_defunct_callback_t defunct,
Ben Menchaca84f36632014-02-28 20:57:38 +00007039 ecm_db_timer_group_t tg, bool is_routed,
7040 void *arg)
7041{
7042 ecm_db_connection_hash_t hash_index;
7043 ecm_db_connection_serial_hash_t serial_hash_index;
7044 struct ecm_db_listener_instance *li;
Gareth Williamsb5903892015-03-20 15:13:07 +00007045#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007046 struct ecm_db_iface_instance *iface_from;
7047 struct ecm_db_iface_instance *iface_to;
7048 struct ecm_db_iface_instance *iface_nat_from;
7049 struct ecm_db_iface_instance *iface_nat_to;
Gareth Williamsb5903892015-03-20 15:13:07 +00007050#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007051
7052 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
7053 DEBUG_CHECK_MAGIC(mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_from);
7054 DEBUG_CHECK_MAGIC(mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_to);
7055 DEBUG_CHECK_MAGIC(mapping_nat_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_nat_from);
7056 DEBUG_CHECK_MAGIC(mapping_nat_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_nat_to);
Gareth Williams90f2a282014-08-27 15:56:25 +01007057 DEBUG_CHECK_MAGIC(from_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", from_node);
7058 DEBUG_CHECK_MAGIC(to_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", to_node);
7059 DEBUG_CHECK_MAGIC(from_nat_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", from_nat_node);
7060 DEBUG_CHECK_MAGIC(to_nat_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", to_nat_node);
Ben Menchaca84f36632014-02-28 20:57:38 +00007061 DEBUG_ASSERT((protocol >= 0) && (protocol <= 255), "%p: invalid protocol number %d\n", ci, protocol);
7062
7063 spin_lock_bh(&ecm_db_lock);
7064 DEBUG_ASSERT(!(ci->flags & ECM_DB_CONNECTION_FLAGS_INSERTED), "%p: inserted\n", ci);
7065 spin_unlock_bh(&ecm_db_lock);
7066
7067 /*
7068 * Record owner arg and callbacks
7069 */
7070 ci->final = final;
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07007071 ci->defunct = defunct;
Ben Menchaca84f36632014-02-28 20:57:38 +00007072 ci->arg = arg;
7073
Shyam Sunder317ca912016-01-22 16:51:28 +05307074#ifdef ECM_MULTICAST_ENABLE
7075 ci->ti = NULL;
7076#endif
7077
Ben Menchaca84f36632014-02-28 20:57:38 +00007078 /*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01007079 * Ensure default classifier has been assigned this is a must to ensure minimum level of classification
Ben Menchaca84f36632014-02-28 20:57:38 +00007080 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01007081 DEBUG_ASSERT(ci->assignments_by_type[ECM_CLASSIFIER_TYPE_DEFAULT], "%p: No default classifier assigned\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00007082
7083 /*
7084 * Connection takes references to the mappings
7085 */
7086 ecm_db_mapping_ref(mapping_from);
7087 ecm_db_mapping_ref(mapping_to);
7088 ci->mapping_from = mapping_from;
7089 ci->mapping_to = mapping_to;
7090
7091 ecm_db_mapping_ref(mapping_nat_from);
7092 ecm_db_mapping_ref(mapping_nat_to);
7093 ci->mapping_nat_from = mapping_nat_from;
7094 ci->mapping_nat_to = mapping_nat_to;
7095
7096 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01007097 * Take references to the nodes
7098 */
7099 ci->from_node = from_node;
7100 ecm_db_node_ref(from_node);
7101 ci->to_node = to_node;
7102 ecm_db_node_ref(to_node);
7103
7104 ci->from_nat_node = from_nat_node;
7105 ecm_db_node_ref(from_nat_node);
7106 ci->to_nat_node = to_nat_node;
7107 ecm_db_node_ref(to_nat_node);
7108
7109 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00007110 * Set the protocol and routed flag
7111 */
Gareth Williams3e5b37f2015-05-13 10:04:12 +01007112 ci->ip_version = ip_version;
Ben Menchaca84f36632014-02-28 20:57:38 +00007113 ci->protocol = protocol;
7114 ci->is_routed = is_routed;
7115
7116 /*
7117 * Set direction of connection
7118 */
7119 ci->direction = dir;
7120
7121 /*
7122 * Identify which hash chain this connection will go into
7123 */
7124 hash_index = ecm_db_connection_generate_hash_index(mapping_from->host->address, mapping_from->port, mapping_to->host->address, mapping_to->port, protocol);
7125 ci->hash_index = hash_index;
7126
7127 /*
7128 * Identify which serial hash chain this connection will go into
7129 */
7130 serial_hash_index = ecm_db_connection_generate_serial_hash_index(ci->serial);
7131 ci->serial_hash_index = serial_hash_index;
7132
7133 /*
7134 * Now we need to lock
7135 */
7136 spin_lock_bh(&ecm_db_lock);
7137
7138 /*
7139 * Increment protocol counter stats
7140 */
7141 ecm_db_connection_count_by_protocol[protocol]++;
7142 DEBUG_ASSERT(ecm_db_connection_count_by_protocol[protocol] > 0, "%p: Invalid protocol count %d\n", ci, ecm_db_connection_count_by_protocol[protocol]);
7143
Ben Menchaca84f36632014-02-28 20:57:38 +00007144 /*
7145 * Set time
7146 */
7147 ci->time_added = ecm_db_time;
7148
7149 /*
7150 * Add connection into the global list
7151 */
7152 ci->prev = NULL;
7153 ci->next = ecm_db_connections;
7154 if (ecm_db_connections) {
7155 ecm_db_connections->prev = ci;
7156 }
7157 ecm_db_connections = ci;
7158
7159 /*
7160 * Add this connection into the connections hash table
7161 */
7162 ci->flags |= ECM_DB_CONNECTION_FLAGS_INSERTED;
7163
7164 /*
Gareth Williamsb5903892015-03-20 15:13:07 +00007165 * Insert connection into the connections hash table
Ben Menchaca84f36632014-02-28 20:57:38 +00007166 */
7167 ci->hash_next = ecm_db_connection_table[hash_index];
7168 if (ecm_db_connection_table[hash_index]) {
7169 ecm_db_connection_table[hash_index]->hash_prev = ci;
7170 }
7171 ecm_db_connection_table[hash_index] = ci;
7172 ecm_db_connection_table_lengths[hash_index]++;
7173 DEBUG_ASSERT(ecm_db_connection_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ci, ecm_db_connection_table_lengths[hash_index]);
7174
7175 /*
7176 * Insert connection into the connections serial hash table
7177 */
7178 ci->serial_hash_next = ecm_db_connection_serial_table[serial_hash_index];
7179 if (ecm_db_connection_serial_table[serial_hash_index]) {
7180 ecm_db_connection_serial_table[serial_hash_index]->serial_hash_prev = ci;
7181 }
7182 ecm_db_connection_serial_table[serial_hash_index] = ci;
7183 ecm_db_connection_serial_table_lengths[serial_hash_index]++;
7184 DEBUG_ASSERT(ecm_db_connection_serial_table_lengths[serial_hash_index] > 0, "%p: invalid table len %d\n", ci, ecm_db_connection_serial_table_lengths[serial_hash_index]);
7185
Gareth Williamsb5903892015-03-20 15:13:07 +00007186#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007187 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01007188 * Add this connection into the FROM node
7189 */
7190 ci->node_from_prev = NULL;
7191 ci->node_from_next = from_node->from_connections;
7192 if (from_node->from_connections) {
7193 from_node->from_connections->node_from_prev = ci;
7194 }
7195 from_node->from_connections = ci;
7196 from_node->from_connections_count++;
7197 DEBUG_ASSERT(from_node->from_connections_count > 0, "%p: invalid count\n", ci);
7198
7199 /*
7200 * Add this connection into the TO node
7201 */
7202 ci->node_to_prev = NULL;
7203 ci->node_to_next = to_node->to_connections;
7204 if (to_node->to_connections) {
7205 to_node->to_connections->node_to_prev = ci;
7206 }
7207 to_node->to_connections = ci;
7208 to_node->to_connections_count++;
7209 DEBUG_ASSERT(to_node->to_connections_count > 0, "%p: invalid count\n", ci);
7210
7211 /*
7212 * Add this connection into the FROM NAT node
7213 */
7214 ci->node_from_nat_prev = NULL;
7215 ci->node_from_nat_next = from_nat_node->from_nat_connections;
7216 if (from_nat_node->from_nat_connections) {
7217 from_nat_node->from_nat_connections->node_from_nat_prev = ci;
7218 }
7219 from_nat_node->from_nat_connections = ci;
7220 from_nat_node->from_nat_connections_count++;
7221 DEBUG_ASSERT(from_nat_node->from_nat_connections_count > 0, "%p: invalid count\n", ci);
7222
7223 /*
7224 * Add this connection into the TO NAT node
7225 */
7226 ci->node_to_nat_prev = NULL;
7227 ci->node_to_nat_next = to_nat_node->to_nat_connections;
7228 if (to_nat_node->to_nat_connections) {
7229 to_nat_node->to_nat_connections->node_to_nat_prev = ci;
7230 }
7231 to_nat_node->to_nat_connections = ci;
7232 to_nat_node->to_nat_connections_count++;
7233 DEBUG_ASSERT(to_nat_node->to_nat_connections_count > 0, "%p: invalid count\n", ci);
7234
7235 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00007236 * Add this connection into the FROM mapping
7237 */
7238 ci->from_prev = NULL;
7239 ci->from_next = mapping_from->from_connections;
7240 if (mapping_from->from_connections) {
7241 mapping_from->from_connections->from_prev = ci;
7242 }
7243 mapping_from->from_connections = ci;
7244
7245 /*
7246 * Add this connection into the TO mapping
7247 */
7248 ci->to_prev = NULL;
7249 ci->to_next = mapping_to->to_connections;
7250 if (mapping_to->to_connections) {
7251 mapping_to->to_connections->to_prev = ci;
7252 }
7253 mapping_to->to_connections = ci;
7254
7255 /*
7256 * Add this connection into the FROM NAT mapping
7257 */
7258 ci->from_nat_prev = NULL;
7259 ci->from_nat_next = mapping_nat_from->from_nat_connections;
7260 if (mapping_nat_from->from_nat_connections) {
7261 mapping_nat_from->from_nat_connections->from_nat_prev = ci;
7262 }
7263 mapping_nat_from->from_nat_connections = ci;
7264
7265 /*
7266 * Add this connection into the TO NAT mapping
7267 */
7268 ci->to_nat_prev = NULL;
7269 ci->to_nat_next = mapping_nat_to->to_nat_connections;
7270 if (mapping_nat_to->to_nat_connections) {
7271 mapping_nat_to->to_nat_connections->to_nat_prev = ci;
7272 }
7273 mapping_nat_to->to_nat_connections = ci;
7274
7275 /*
7276 * Add this connection into the FROM iface list of connections
7277 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
7278 * due to the heirarchy of dependencies being kept by the database.
7279 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007280 iface_from = from_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007281 ci->iface_from_prev = NULL;
7282 ci->iface_from_next = iface_from->from_connections;
7283 if (iface_from->from_connections) {
7284 iface_from->from_connections->iface_from_prev = ci;
7285 }
7286 iface_from->from_connections = ci;
7287
7288 /*
7289 * Add this connection into the TO iface list of connections
7290 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
7291 * due to the heirarchy of dependencies being kept by the database.
7292 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007293 iface_to = to_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007294 ci->iface_to_prev = NULL;
7295 ci->iface_to_next = iface_to->to_connections;
7296 if (iface_to->to_connections) {
7297 iface_to->to_connections->iface_to_prev = ci;
7298 }
7299 iface_to->to_connections = ci;
7300
7301 /*
7302 * Add this connection into the FROM NAT iface list of connections
7303 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
7304 * due to the heirarchy of dependencies being kept by the database.
7305 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007306 iface_nat_from = from_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007307 ci->iface_from_nat_prev = NULL;
7308 ci->iface_from_nat_next = iface_nat_from->from_nat_connections;
7309 if (iface_nat_from->from_nat_connections) {
7310 iface_nat_from->from_nat_connections->iface_from_nat_prev = ci;
7311 }
7312 iface_nat_from->from_nat_connections = ci;
7313
7314 /*
7315 * Add this connection into the TO NAT iface list of connections
7316 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
7317 * due to the heirarchy of dependencies being kept by the database.
7318 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007319 iface_nat_to = to_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007320 ci->iface_to_nat_prev = NULL;
7321 ci->iface_to_nat_next = iface_nat_to->to_nat_connections;
7322 if (iface_nat_to->to_nat_connections) {
7323 iface_nat_to->to_nat_connections->iface_to_nat_prev = ci;
7324 }
7325 iface_nat_to->to_nat_connections = ci;
Gareth Williamsb5903892015-03-20 15:13:07 +00007326#endif
Gareth Williams90f2a282014-08-27 15:56:25 +01007327
Ben Menchaca84f36632014-02-28 20:57:38 +00007328 /*
7329 * NOTE: The interface heirarchy lists are deliberately left empty - these are completed
7330 * by the front end if it is appropriate to do so.
7331 */
7332
7333 /*
7334 * Update the counters in the mapping
7335 */
7336 if (protocol == IPPROTO_UDP) {
7337 mapping_from->udp_from++;
7338 mapping_to->udp_to++;
7339 mapping_nat_from->udp_nat_from++;
7340 mapping_nat_to->udp_nat_to++;
7341 } else if (protocol == IPPROTO_TCP) {
7342 mapping_from->tcp_from++;
7343 mapping_to->tcp_to++;
7344 mapping_nat_from->tcp_nat_from++;
7345 mapping_nat_to->tcp_nat_to++;
7346 }
7347
7348 mapping_from->from++;
7349 mapping_to->to++;
7350 mapping_nat_from->nat_from++;
7351 mapping_nat_to->nat_to++;
7352
7353 /*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05307354 * Set the generation number to match global
Ben Menchaca84f36632014-02-28 20:57:38 +00007355 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05307356 ci->generation = ecm_db_connection_generation;
Ben Menchaca84f36632014-02-28 20:57:38 +00007357
7358 spin_unlock_bh(&ecm_db_lock);
7359
7360 /*
7361 * Throw add event to the listeners
7362 */
7363 DEBUG_TRACE("%p: Throw connection added event\n", ci);
7364 li = ecm_db_listeners_get_and_ref_first();
7365 while (li) {
7366 struct ecm_db_listener_instance *lin;
7367 if (li->connection_added) {
7368 li->connection_added(li->arg, ci);
7369 }
7370
7371 /*
7372 * Get next listener
7373 */
7374 lin = ecm_db_listener_get_and_ref_next(li);
7375 ecm_db_listener_deref(li);
7376 li = lin;
7377 }
7378
7379 /*
7380 * Set timer group. 'ref' the connection to ensure it persists for the timer.
7381 */
7382 ecm_db_connection_ref(ci);
7383 ecm_db_timer_group_entry_set(&ci->defunct_timer, tg);
7384}
7385EXPORT_SYMBOL(ecm_db_connection_add);
7386
7387/*
7388 * ecm_db_mapping_add()
7389 * Add a mapping instance into the database
7390 *
7391 * NOTE: The mapping will take a reference to the host instance.
7392 */
7393void ecm_db_mapping_add(struct ecm_db_mapping_instance *mi, struct ecm_db_host_instance *hi, int port,
7394 ecm_db_mapping_final_callback_t final, void *arg)
7395{
7396 ecm_db_mapping_hash_t hash_index;
7397 struct ecm_db_listener_instance *li;
7398
7399 spin_lock_bh(&ecm_db_lock);
7400 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
7401 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007402 DEBUG_ASSERT(!(mi->flags & ECM_DB_MAPPING_FLAGS_INSERTED), "%p: inserted\n", mi);
7403 DEBUG_ASSERT((hi->flags & ECM_DB_HOST_FLAGS_INSERTED), "%p: not inserted\n", hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00007404 DEBUG_ASSERT(!mi->tcp_from && !mi->tcp_to && !mi->udp_from && !mi->udp_to, "%p: protocol count errors\n", mi);
7405#ifdef ECM_DB_XREF_ENABLE
7406 DEBUG_ASSERT(mi->from_connections == NULL, "%p: connections not null\n", mi);
7407 DEBUG_ASSERT(mi->to_connections == NULL, "%p: connections not null\n", mi);
7408 DEBUG_ASSERT(!mi->from && !mi->to && !mi->nat_from && !mi->nat_to, "%p: connection count errors\n", mi);
7409#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007410 spin_unlock_bh(&ecm_db_lock);
7411
7412 mi->arg = arg;
7413 mi->final = final;
7414
7415 /*
7416 * Compute hash table position for insertion
7417 */
7418 hash_index = ecm_db_mapping_generate_hash_index(hi->address, port);
7419 mi->hash_index = hash_index;
7420
7421 /*
7422 * Record port
7423 */
7424 mi->port = port;
7425
7426 /*
7427 * Mapping takes a ref to the host
7428 */
7429 ecm_db_host_ref(hi);
7430 mi->host = hi;
7431
7432 /*
7433 * Set time
7434 */
7435 spin_lock_bh(&ecm_db_lock);
7436 mi->time_added = ecm_db_time;
7437
7438 /*
7439 * Record the mapping is inserted
7440 */
7441 mi->flags |= ECM_DB_MAPPING_FLAGS_INSERTED;
7442
7443 /*
7444 * Add into the global list
7445 */
7446 mi->prev = NULL;
7447 mi->next = ecm_db_mappings;
7448 if (ecm_db_mappings) {
7449 ecm_db_mappings->prev = mi;
7450 }
7451 ecm_db_mappings = mi;
7452
7453 /*
7454 * Insert mapping into the mappings hash table
7455 */
7456 mi->hash_next = ecm_db_mapping_table[hash_index];
7457 if (ecm_db_mapping_table[hash_index]) {
7458 ecm_db_mapping_table[hash_index]->hash_prev = mi;
7459 }
7460 ecm_db_mapping_table[hash_index] = mi;
7461 ecm_db_mapping_table_lengths[hash_index]++;
7462 DEBUG_ASSERT(ecm_db_mapping_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", hi, ecm_db_mapping_table_lengths[hash_index]);
7463
Gareth Williamsb5903892015-03-20 15:13:07 +00007464#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007465 /*
7466 * Insert mapping into the host mapping list
7467 */
7468 mi->mapping_prev = NULL;
7469 mi->mapping_next = hi->mappings;
7470 if (hi->mappings) {
7471 hi->mappings->mapping_prev = mi;
7472 }
7473 hi->mappings = mi;
7474 hi->mapping_count++;
Gareth Williamsb5903892015-03-20 15:13:07 +00007475#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007476 spin_unlock_bh(&ecm_db_lock);
7477
7478 /*
7479 * Throw add event to the listeners
7480 */
7481 DEBUG_TRACE("%p: Throw mapping added event\n", mi);
7482 li = ecm_db_listeners_get_and_ref_first();
7483 while (li) {
7484 struct ecm_db_listener_instance *lin;
7485 if (li->mapping_added) {
7486 li->mapping_added(li->arg, mi);
7487 }
7488
7489 /*
7490 * Get next listener
7491 */
7492 lin = ecm_db_listener_get_and_ref_next(li);
7493 ecm_db_listener_deref(li);
7494 li = lin;
7495 }
7496}
7497EXPORT_SYMBOL(ecm_db_mapping_add);
7498
7499/*
7500 * ecm_db_host_add()
7501 * Add a host instance into the database
7502 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007503void ecm_db_host_add(struct ecm_db_host_instance *hi, ip_addr_t address, bool on_link, ecm_db_host_final_callback_t final, void *arg)
Ben Menchaca84f36632014-02-28 20:57:38 +00007504{
7505 ecm_db_host_hash_t hash_index;
7506 struct ecm_db_listener_instance *li;
7507
7508 spin_lock_bh(&ecm_db_lock);
7509 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007510 DEBUG_ASSERT(!(hi->flags & ECM_DB_HOST_FLAGS_INSERTED), "%p: inserted\n", hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00007511#ifdef ECM_DB_XREF_ENABLE
7512 DEBUG_ASSERT((hi->mappings == NULL) && (hi->mapping_count == 0), "%p: mappings not null\n", hi);
7513#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007514 spin_unlock_bh(&ecm_db_lock);
7515
7516 hi->arg = arg;
7517 hi->final = final;
7518 ECM_IP_ADDR_COPY(hi->address, address);
7519 hi->on_link = on_link;
7520
7521 /*
7522 * Compute hash index into which host will be added
7523 */
7524 hash_index = ecm_db_host_generate_hash_index(address);
7525 hi->hash_index = hash_index;
7526
7527 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00007528 * Add into the global list
7529 */
7530 spin_lock_bh(&ecm_db_lock);
7531 hi->flags |= ECM_DB_HOST_FLAGS_INSERTED;
7532 hi->prev = NULL;
7533 hi->next = ecm_db_hosts;
7534 if (ecm_db_hosts) {
7535 ecm_db_hosts->prev = hi;
7536 }
7537 ecm_db_hosts = hi;
7538
7539 /*
7540 * Add host into the hash table
7541 */
7542 hi->hash_next = ecm_db_host_table[hash_index];
7543 if (ecm_db_host_table[hash_index]) {
7544 ecm_db_host_table[hash_index]->hash_prev = hi;
7545 }
7546 ecm_db_host_table[hash_index] = hi;
7547 ecm_db_host_table_lengths[hash_index]++;
7548 DEBUG_ASSERT(ecm_db_host_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", hi, ecm_db_host_table_lengths[hash_index]);
7549
7550 /*
7551 * Set time of add
7552 */
7553 hi->time_added = ecm_db_time;
Ben Menchaca84f36632014-02-28 20:57:38 +00007554 spin_unlock_bh(&ecm_db_lock);
7555
7556 /*
7557 * Throw add event to the listeners
7558 */
7559 DEBUG_TRACE("%p: Throw host added event\n", hi);
7560 li = ecm_db_listeners_get_and_ref_first();
7561 while (li) {
7562 struct ecm_db_listener_instance *lin;
7563 if (li->host_added) {
7564 li->host_added(li->arg, hi);
7565 }
7566
7567 /*
7568 * Get next listener
7569 */
7570 lin = ecm_db_listener_get_and_ref_next(li);
7571 ecm_db_listener_deref(li);
7572 li = lin;
7573 }
7574}
7575EXPORT_SYMBOL(ecm_db_host_add);
7576
7577/*
7578 * ecm_db_node_add()
7579 * Add a node instance into the database
7580 */
7581void ecm_db_node_add(struct ecm_db_node_instance *ni, struct ecm_db_iface_instance *ii, uint8_t *address,
7582 ecm_db_node_final_callback_t final, void *arg)
7583{
7584 ecm_db_node_hash_t hash_index;
7585 struct ecm_db_listener_instance *li;
7586
7587 spin_lock_bh(&ecm_db_lock);
7588 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
7589 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7590 DEBUG_ASSERT(address, "%p: address null\n", ni);
Gareth Williamsb5903892015-03-20 15:13:07 +00007591 DEBUG_ASSERT((ni->iface == NULL), "%p: iface not null\n", ni);
7592 DEBUG_ASSERT(!(ni->flags & ECM_DB_NODE_FLAGS_INSERTED), "%p: inserted\n", ni);
7593#ifdef ECM_DB_XREF_ENABLE
Gareth Williams90f2a282014-08-27 15:56:25 +01007594 DEBUG_ASSERT((ni->from_connections == NULL) && (ni->from_connections_count == 0), "%p: from_connections not null\n", ni);
7595 DEBUG_ASSERT((ni->to_connections == NULL) && (ni->to_connections_count == 0), "%p: to_connections not null\n", ni);
7596 DEBUG_ASSERT((ni->from_nat_connections == NULL) && (ni->from_nat_connections_count == 0), "%p: from_nat_connections not null\n", ni);
7597 DEBUG_ASSERT((ni->to_nat_connections == NULL) && (ni->to_nat_connections_count == 0), "%p: to_nat_connections not null\n", ni);
Gareth Williamsb5903892015-03-20 15:13:07 +00007598#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007599 spin_unlock_bh(&ecm_db_lock);
7600
7601 memcpy(ni->address, address, ETH_ALEN);
7602 ni->arg = arg;
7603 ni->final = final;
7604
7605 /*
7606 * Compute hash chain for insertion
7607 */
7608 hash_index = ecm_db_node_generate_hash_index(address);
7609 ni->hash_index = hash_index;
7610
7611 /*
7612 * Node takes a ref to the iface
7613 */
7614 ecm_db_iface_ref(ii);
7615 ni->iface = ii;
7616
7617 /*
7618 * Add into the global list
7619 */
7620 spin_lock_bh(&ecm_db_lock);
7621 ni->flags |= ECM_DB_NODE_FLAGS_INSERTED;
7622 ni->prev = NULL;
7623 ni->next = ecm_db_nodes;
7624 if (ecm_db_nodes) {
7625 ecm_db_nodes->prev = ni;
7626 }
7627 ecm_db_nodes = ni;
7628
7629 /*
7630 * Insert into the hash chain
7631 */
7632 ni->hash_next = ecm_db_node_table[hash_index];
7633 if (ecm_db_node_table[hash_index]) {
7634 ecm_db_node_table[hash_index]->hash_prev = ni;
7635 }
7636 ecm_db_node_table[hash_index] = ni;
7637 ecm_db_node_table_lengths[hash_index]++;
7638 DEBUG_ASSERT(ecm_db_node_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ni, ecm_db_node_table_lengths[hash_index]);
7639
7640 /*
7641 * Set time of add
7642 */
7643 ni->time_added = ecm_db_time;
7644
Gareth Williamsb5903892015-03-20 15:13:07 +00007645#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007646 /*
7647 * Insert node into the iface nodes list
7648 */
7649 ni->node_prev = NULL;
7650 ni->node_next = ii->nodes;
7651 if (ii->nodes) {
7652 ii->nodes->node_prev = ni;
7653 }
7654 ii->nodes = ni;
7655 ii->node_count++;
Gareth Williamsb5903892015-03-20 15:13:07 +00007656#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007657 spin_unlock_bh(&ecm_db_lock);
7658
7659 /*
7660 * Throw add event to the listeners
7661 */
7662 DEBUG_TRACE("%p: Throw node added event\n", ni);
7663 li = ecm_db_listeners_get_and_ref_first();
7664 while (li) {
7665 struct ecm_db_listener_instance *lin;
7666 if (li->node_added) {
7667 li->node_added(li->arg, ni);
7668 }
7669
7670 /*
7671 * Get next listener
7672 */
7673 lin = ecm_db_listener_get_and_ref_next(li);
7674 ecm_db_listener_deref(li);
7675 li = lin;
7676 }
7677}
7678EXPORT_SYMBOL(ecm_db_node_add);
7679
Gareth Williamsd5618a82015-05-20 11:13:32 +01007680/*
7681 * ecm_db_adv_stats_state_write()
7682 * Write out advanced stats state
7683 */
7684static int ecm_db_adv_stats_state_write(struct ecm_state_file_instance *sfi,uint64_t from_data_total, uint64_t to_data_total,
7685 uint64_t from_packet_total, uint64_t to_packet_total, uint64_t from_data_total_dropped,
7686 uint64_t to_data_total_dropped, uint64_t from_packet_total_dropped, uint64_t to_packet_total_dropped)
7687{
7688 int result;
7689
7690 if ((result = ecm_state_prefix_add(sfi, "adv_stats"))) {
7691 return result;
7692 }
7693
7694 if ((result = ecm_state_write(sfi, "from_data_total", "%llu", from_data_total))) {
7695 return result;
7696 }
7697 if ((result = ecm_state_write(sfi, "to_data_total", "%llu", to_data_total))) {
7698 return result;
7699 }
7700 if ((result = ecm_state_write(sfi, "from_packet_total", "%llu", from_packet_total))) {
7701 return result;
7702 }
7703 if ((result = ecm_state_write(sfi, "to_packet_total", "%llu", to_packet_total))) {
7704 return result;
7705 }
7706 if ((result = ecm_state_write(sfi, "from_data_total_dropped", "%llu", from_data_total_dropped))) {
7707 return result;
7708 }
7709 if ((result = ecm_state_write(sfi, "to_data_total_dropped", "%llu", to_data_total_dropped))) {
7710 return result;
7711 }
7712 if ((result = ecm_state_write(sfi, "from_packet_total_dropped", "%llu", from_packet_total_dropped))) {
7713 return result;
7714 }
7715 if ((result = ecm_state_write(sfi, "to_packet_total_dropped", "%llu", to_packet_total_dropped))) {
7716 return result;
7717 }
7718
7719 return ecm_state_prefix_remove(sfi);
7720}
7721
Gareth Williamsf98d4192015-03-11 16:55:41 +00007722#ifdef ECM_STATE_OUTPUT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007723/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007724 * ecm_db_iface_state_get_base()
7725 * Get the basic state for an interface object
Ben Menchaca84f36632014-02-28 20:57:38 +00007726 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007727static int ecm_db_iface_state_get_base(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00007728{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007729 int result;
Gareth Williamsb5903892015-03-20 15:13:07 +00007730#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007731 int node_count;
Gareth Williamsb5903892015-03-20 15:13:07 +00007732#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007733 uint32_t time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00007734 int32_t interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07007735 int32_t ae_interface_identifier;
Gareth Williams85331c92015-03-11 20:39:18 +00007736 char name[IFNAMSIZ];
7737 int32_t mtu;
7738 ecm_db_iface_type_t type;
7739#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007740 uint64_t from_data_total;
7741 uint64_t to_data_total;
7742 uint64_t from_packet_total;
7743 uint64_t to_packet_total;
7744 uint64_t from_data_total_dropped;
7745 uint64_t to_data_total_dropped;
7746 uint64_t from_packet_total_dropped;
7747 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00007748#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007749
7750 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7751 DEBUG_TRACE("%p: Open iface msg\n", ii);
7752
Gareth Williamsd5618a82015-05-20 11:13:32 +01007753 if ((result = ecm_state_prefix_add(sfi, "iface"))) {
7754 return result;
7755 }
7756
Gareth Williamsb5903892015-03-20 15:13:07 +00007757#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007758 node_count = ecm_db_iface_node_count_get(ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00007759#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007760 time_added = ii->time_added;
Ben Menchaca84f36632014-02-28 20:57:38 +00007761 type = ii->type;
Gareth Williamsd5618a82015-05-20 11:13:32 +01007762 interface_identifier = ii->interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07007763 ae_interface_identifier = ii->ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +00007764 spin_lock_bh(&ecm_db_lock);
7765 strcpy(name, ii->name);
7766 mtu = ii->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00007767 spin_unlock_bh(&ecm_db_lock);
7768
Gareth Williams85331c92015-03-11 20:39:18 +00007769#ifdef ECM_DB_ADVANCED_STATS_ENABLE
7770 ecm_db_iface_data_stats_get(ii, &from_data_total, &to_data_total,
7771 &from_packet_total, &to_packet_total,
7772 &from_data_total_dropped, &to_data_total_dropped,
7773 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williamsd5618a82015-05-20 11:13:32 +01007774
7775 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
7776 from_packet_total, to_packet_total, from_data_total_dropped,
7777 to_data_total_dropped, from_packet_total_dropped,
7778 to_packet_total_dropped))) {
7779 return result;
7780 }
Gareth Williams85331c92015-03-11 20:39:18 +00007781#endif
7782
Gareth Williamsd5618a82015-05-20 11:13:32 +01007783 if ((result = ecm_state_write(sfi, "type", "%d", type))) {
7784 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007785 }
7786
Gareth Williamsd5618a82015-05-20 11:13:32 +01007787 if ((result = ecm_state_write(sfi, "name", "%s", name))) {
7788 return result;
7789 }
7790
7791 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
7792 return result;
7793 }
7794
7795 if ((result = ecm_state_write(sfi, "mtu", "%d", mtu))) {
7796 return result;
7797 }
7798
7799 if ((result = ecm_state_write(sfi, "interface_identifier", "%d", interface_identifier))) {
7800 return result;
7801 }
7802
Murat Sezgin91c5d712015-06-12 15:16:22 -07007803 if ((result = ecm_state_write(sfi, "ae_interface_identifier", "%d", ae_interface_identifier))) {
Gareth Williamsd5618a82015-05-20 11:13:32 +01007804 return result;
7805 }
7806
7807#ifdef ECM_DB_XREF_ENABLE
7808 if ((result = ecm_state_write(sfi, "nodes", "%d", node_count))) {
7809 return result;
7810 }
7811#endif
7812
7813 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007814}
7815
7816/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007817 * ecm_db_iface_ethernet_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007818 * Return interface type specific state
7819 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007820static int ecm_db_iface_ethernet_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00007821{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007822 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007823 uint8_t address[ETH_ALEN];
7824
7825 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7826 spin_lock_bh(&ecm_db_lock);
7827 memcpy(address, ii->type_info.ethernet.address, ETH_ALEN);
7828 spin_unlock_bh(&ecm_db_lock);
7829
Gareth Williamsd5618a82015-05-20 11:13:32 +01007830 if ((result = ecm_state_prefix_add(sfi, "ethernet"))) {
7831 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007832 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007833
Gareth Williamsd5618a82015-05-20 11:13:32 +01007834 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7835 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007836 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007837
Gareth Williamsd5618a82015-05-20 11:13:32 +01007838 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
7839 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007840 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007841
7842 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007843}
7844
Murat Sezgin910c9662015-03-11 16:15:06 -07007845#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007846/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007847 * ecm_db_iface_lag_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007848 * Return interface type specific state
7849 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007850static int ecm_db_iface_lag_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00007851{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007852 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007853 uint8_t address[ETH_ALEN];
7854
7855 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7856 spin_lock_bh(&ecm_db_lock);
7857 memcpy(address, ii->type_info.lag.address, ETH_ALEN);
7858 spin_unlock_bh(&ecm_db_lock);
7859
Gareth Williamsd5618a82015-05-20 11:13:32 +01007860 if ((result = ecm_state_prefix_add(sfi, "lag"))) {
7861 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007862 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007863 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7864 return result;
7865 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007866
Gareth Williamsd5618a82015-05-20 11:13:32 +01007867 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
7868 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007869 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007870
Gareth Williamsd5618a82015-05-20 11:13:32 +01007871 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007872}
Murat Sezgin910c9662015-03-11 16:15:06 -07007873#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007874
7875/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007876 * ecm_db_iface_bridge_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007877 * Return interface type specific state
7878 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007879static int ecm_db_iface_bridge_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00007880{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007881 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007882 uint8_t address[ETH_ALEN];
7883
7884 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7885 spin_lock_bh(&ecm_db_lock);
7886 memcpy(address, ii->type_info.bridge.address, ETH_ALEN);
7887 spin_unlock_bh(&ecm_db_lock);
7888
Gareth Williamsd5618a82015-05-20 11:13:32 +01007889 if ((result = ecm_state_prefix_add(sfi, "bridge"))) {
7890 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007891 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007892 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7893 return result;
7894 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007895
Gareth Williamsd5618a82015-05-20 11:13:32 +01007896 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
7897 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007898 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007899
Gareth Williamsd5618a82015-05-20 11:13:32 +01007900 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007901}
7902
Murat Sezgin37fb3952015-03-10 16:45:13 -07007903#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007904/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007905 * ecm_db_iface_vlan_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007906 * Return interface type specific state
7907 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007908static int ecm_db_iface_vlan_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00007909{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007910 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007911 uint8_t address[ETH_ALEN];
7912 uint16_t vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307913 uint16_t vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00007914
7915 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7916 spin_lock_bh(&ecm_db_lock);
7917 memcpy(address, ii->type_info.vlan.address, ETH_ALEN);
7918 vlan_tag = ii->type_info.vlan.vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307919 vlan_tpid = ii->type_info.vlan.vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00007920 spin_unlock_bh(&ecm_db_lock);
7921
Gareth Williamsd5618a82015-05-20 11:13:32 +01007922 if ((result = ecm_state_prefix_add(sfi, "vlan"))) {
7923 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007924 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007925 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7926 return result;
7927 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007928
Gareth Williamsd5618a82015-05-20 11:13:32 +01007929 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
7930 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007931 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007932 if ((result = ecm_state_write(sfi, "tag", "%x", vlan_tag))) {
7933 return result;
7934 }
7935 if ((result = ecm_state_write(sfi, "tpid", "%x", vlan_tpid))) {
7936 return result;
7937 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007938
Gareth Williamsd5618a82015-05-20 11:13:32 +01007939 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007940}
Murat Sezgin37fb3952015-03-10 16:45:13 -07007941#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007942
ratheesh kannotha32fdd12015-09-09 08:02:58 +05307943#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007944/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007945 * ecm_db_iface_pppoe_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007946 * Return interface type specific state
7947 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007948static int ecm_db_iface_pppoe_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00007949{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007950 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007951 uint16_t pppoe_session_id;
7952 uint8_t remote_mac[ETH_ALEN];
7953
7954 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7955 spin_lock_bh(&ecm_db_lock);
7956 pppoe_session_id = ii->type_info.pppoe.pppoe_session_id;
7957 memcpy(remote_mac, ii->type_info.pppoe.remote_mac, ETH_ALEN);
7958 spin_unlock_bh(&ecm_db_lock);
7959
Gareth Williamsd5618a82015-05-20 11:13:32 +01007960 if ((result = ecm_state_prefix_add(sfi, "pppoe"))) {
7961 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007962 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007963 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7964 return result;
7965 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007966
Gareth Williamsd5618a82015-05-20 11:13:32 +01007967 if ((result = ecm_state_write(sfi, "remote_max", "%pM", remote_mac))) {
7968 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007969 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007970 if ((result = ecm_state_write(sfi, "session_id", "%u", pppoe_session_id))) {
7971 return result;
7972 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007973
Gareth Williamsd5618a82015-05-20 11:13:32 +01007974 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007975}
Murat Sezginaad635c2015-03-06 16:11:41 -08007976#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007977
ratheesh kannothcfdcb332015-12-24 07:19:18 +05307978#ifdef ECM_INTERFACE_MAP_T_ENABLE
7979/*
7980 * ecm_db_iface_map_t_state_get()
7981 * Return interface type specific state
7982 */
7983static int ecm_db_iface_map_t_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
7984{
7985 int result;
7986 int32_t if_index;
7987
7988 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7989 spin_lock_bh(&ecm_db_lock);
7990 if_index = ii->type_info.map_t.if_index;
7991 spin_unlock_bh(&ecm_db_lock);
7992
7993 if ((result = ecm_state_prefix_add(sfi, "map_t"))) {
7994 return result;
7995 }
7996 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7997 return result;
7998 }
7999
8000 if ((result = ecm_state_write(sfi, "if_index", "%d", if_index))) {
8001 return result;
8002 }
8003
8004 return ecm_state_prefix_remove(sfi);
8005}
8006#endif
8007
ratheesh kannotha32fdd12015-09-09 08:02:58 +05308008#ifdef ECM_INTERFACE_L2TPV2_ENABLE
8009
8010/*
8011 * ecm_db_iface_pppol2tpv2_state_get()
8012 * Return interface type specific state
8013 */
8014static int ecm_db_iface_pppol2tpv2_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
8015{
8016 int result;
8017 struct ecm_db_interface_info_pppol2tpv2 type_info;
8018
8019 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8020 spin_lock_bh(&ecm_db_lock);
8021 memcpy(&type_info, &ii->type_info, sizeof(struct ecm_db_interface_info_pppol2tpv2));
8022 spin_unlock_bh(&ecm_db_lock);
8023
8024 if ((result = ecm_state_prefix_add(sfi, "pppol2tpv2"))) {
8025 return result;
8026 }
8027
8028 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
8029 return result;
8030 }
8031
8032 if ((result = ecm_state_write(sfi, "local_tunnel_id", "%u", type_info.l2tp.tunnel.tunnel_id))) {
8033 return result;
8034 }
8035
8036 if ((result = ecm_state_write(sfi, "local_session_id", "%u", type_info.l2tp.session.session_id))) {
8037 return result;
8038 }
8039
8040 if ((result = ecm_state_write(sfi, "peer_tunnnel_id", "%u", type_info.l2tp.tunnel.peer_tunnel_id))) {
8041 return result;
8042 }
8043
8044 if ((result = ecm_state_write(sfi, "peer_session_id", "%u", type_info.l2tp.session.peer_session_id))) {
8045 return result;
8046 }
8047
8048 return ecm_state_prefix_remove(sfi);
8049}
8050
8051#endif
8052
Shyam Sunder23f2e542015-09-28 14:56:49 +05308053#ifdef ECM_INTERFACE_PPTP_ENABLE
8054/*
8055 * ecm_db_iface_pptp_state_get()
8056 * Return interface type specific state
8057 */
8058static int ecm_db_iface_pptp_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
8059{
8060 int result;
8061 struct ecm_db_interface_info_pptp type_info;
8062
8063 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8064 spin_lock_bh(&ecm_db_lock);
8065 memcpy(&type_info, &ii->type_info, sizeof(struct ecm_db_interface_info_pptp));
8066 spin_unlock_bh(&ecm_db_lock);
8067
8068 result = ecm_state_prefix_add(sfi, "pptp");
8069 if (result) {
8070 return result;
8071 }
8072
8073 result = ecm_db_iface_state_get_base(ii, sfi);
8074 if (result) {
8075 return result;
8076 }
8077
8078 result = ecm_state_write(sfi, "local_call_id", "%u", type_info.src_call_id);
8079 if (result) {
8080 return result;
8081 }
8082
8083 result = ecm_state_write(sfi, "peer_call_id", "%u", type_info.dst_call_id);
8084 if (result) {
8085 return result;
8086 }
8087
8088 return ecm_state_prefix_remove(sfi);
8089}
8090#endif
8091
Ben Menchaca84f36632014-02-28 20:57:38 +00008092/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008093 * ecm_db_iface_unknown_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00008094 * Return interface type specific state
8095 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008096static int ecm_db_iface_unknown_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00008097{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008098 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008099 uint32_t os_specific_ident;
8100
8101 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8102 spin_lock_bh(&ecm_db_lock);
8103 os_specific_ident = ii->type_info.unknown.os_specific_ident;
8104 spin_unlock_bh(&ecm_db_lock);
8105
Gareth Williamsd5618a82015-05-20 11:13:32 +01008106 if ((result = ecm_state_prefix_add(sfi, "pppoe"))) {
8107 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008108 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008109 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
8110 return result;
8111 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008112
Gareth Williamsd5618a82015-05-20 11:13:32 +01008113 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
8114 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008115 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008116
Gareth Williamsd5618a82015-05-20 11:13:32 +01008117 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00008118}
8119
8120/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008121 * ecm_db_iface_loopback_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00008122 * Return interface type specific state
8123 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008124static int ecm_db_iface_loopback_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00008125{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008126 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008127 uint32_t os_specific_ident;
8128
8129 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8130 spin_lock_bh(&ecm_db_lock);
8131 os_specific_ident = ii->type_info.loopback.os_specific_ident;
8132 spin_unlock_bh(&ecm_db_lock);
8133
Gareth Williamsd5618a82015-05-20 11:13:32 +01008134 if ((result = ecm_state_prefix_add(sfi, "loopback"))) {
8135 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008136 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008137 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
8138 return result;
8139 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008140
Gareth Williamsd5618a82015-05-20 11:13:32 +01008141 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
8142 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008143 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008144
Gareth Williamsd5618a82015-05-20 11:13:32 +01008145 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00008146}
8147
Murat Sezgin69a27532015-03-12 14:09:40 -07008148#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00008149/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008150 * ecm_db_iface_ipsec_tunnel_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00008151 * Return interface type specific state
8152 *
8153 * GGG TODO Output state on ipsec tunnel specific data
8154 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008155static int ecm_db_iface_ipsec_tunnel_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00008156{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008157 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008158 uint32_t os_specific_ident;
8159
8160 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8161 spin_lock_bh(&ecm_db_lock);
8162 os_specific_ident = ii->type_info.ipsec_tunnel.os_specific_ident;
8163 spin_unlock_bh(&ecm_db_lock);
8164
Gareth Williamsd5618a82015-05-20 11:13:32 +01008165 if ((result = ecm_state_prefix_add(sfi, "ipsec"))) {
8166 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008167 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008168 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
8169 return result;
8170 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008171
Gareth Williamsd5618a82015-05-20 11:13:32 +01008172 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
8173 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008174 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008175
Gareth Williamsd5618a82015-05-20 11:13:32 +01008176 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00008177}
Murat Sezgin69a27532015-03-12 14:09:40 -07008178#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00008179
Gareth Williamsf98d4192015-03-11 16:55:41 +00008180#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +00008181#ifdef ECM_IPV6_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008182/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008183 * ecm_db_iface_tunipip6_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008184 * Return interface type specific state
8185 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008186static int ecm_db_iface_tunipip6_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008187{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008188 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008189 uint32_t os_specific_ident;
8190
8191 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8192 spin_lock_bh(&ecm_db_lock);
8193 os_specific_ident = ii->type_info.ipsec_tunnel.os_specific_ident;
8194 spin_unlock_bh(&ecm_db_lock);
8195
Gareth Williamsd5618a82015-05-20 11:13:32 +01008196 if ((result = ecm_state_prefix_add(sfi, "tunipip6"))) {
8197 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008198 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008199 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
8200 return result;
8201 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008202
Gareth Williamsd5618a82015-05-20 11:13:32 +01008203 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
8204 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008205 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008206
Gareth Williamsd5618a82015-05-20 11:13:32 +01008207 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008208}
8209#endif
Gareth Williams8ac34292015-03-17 14:06:58 +00008210#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008211
8212#ifdef ECM_INTERFACE_SIT_ENABLE
8213/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008214 * ecm_db_iface_sit_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008215 * Return interface type specific state
8216 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008217static int ecm_db_iface_sit_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008218{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008219 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008220 uint32_t os_specific_ident;
8221
8222 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8223 spin_lock_bh(&ecm_db_lock);
8224 os_specific_ident = ii->type_info.ipsec_tunnel.os_specific_ident;
8225 spin_unlock_bh(&ecm_db_lock);
8226
Gareth Williamsd5618a82015-05-20 11:13:32 +01008227 if ((result = ecm_state_prefix_add(sfi, "sit"))) {
8228 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008229 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008230 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
8231 return result;
8232 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008233
Gareth Williamsd5618a82015-05-20 11:13:32 +01008234 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
8235 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008236 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008237
Gareth Williamsd5618a82015-05-20 11:13:32 +01008238 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008239}
8240#endif
8241
8242/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008243 * ecm_db_iface_state_get()
8244 * Obtain state for the interface.
Gareth Williamsf98d4192015-03-11 16:55:41 +00008245 *
8246 * State specific to the interface type will be returned.
8247 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008248int ecm_db_iface_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_iface_instance *ii)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008249{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008250 int result;
8251
Gareth Williamsf98d4192015-03-11 16:55:41 +00008252 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008253
8254 if ((result = ecm_state_prefix_add(sfi, "iface"))) {
8255 return result;
8256 }
8257
8258 if ((result = ii->state_get(ii, sfi))) {
8259 return result;
8260 }
8261
8262 return ecm_state_prefix_remove(sfi);
8263
Gareth Williamsf98d4192015-03-11 16:55:41 +00008264}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008265EXPORT_SYMBOL(ecm_db_iface_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008266
8267/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008268 * ecm_db_connection_heirarchy_state_get()
8269 * Output state for an interface heirarchy list.
Gareth Williamsf98d4192015-03-11 16:55:41 +00008270 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008271static int ecm_db_connection_heirarchy_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_iface_instance *interfaces[], int32_t first_interface)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008272{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008273 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008274 int count;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008275 int i;
Gareth Williamsd5618a82015-05-20 11:13:32 +01008276 int j;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008277
Gareth Williamsd5618a82015-05-20 11:13:32 +01008278 count = ECM_DB_IFACE_HEIRARCHY_MAX - first_interface;
8279 if ((result = ecm_state_write(sfi, "interface_count", "%d", count))) {
8280 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008281 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008282
8283 /*
8284 * Iterate the interface heirarchy list and output the information
8285 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008286 for (i = first_interface, j = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i, ++j) {
Gareth Williamsf98d4192015-03-11 16:55:41 +00008287 struct ecm_db_iface_instance *ii = interfaces[i];
Gareth Williamsd5618a82015-05-20 11:13:32 +01008288 DEBUG_TRACE("Output interface @ %d: %p\n", i, ii);
8289
8290 if ((result = ecm_state_prefix_index_add(sfi, j))) {
8291 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008292 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008293 result = ii->state_get(ii, sfi);
8294 if (result) {
8295 return result;
8296 }
8297 if ((result = ecm_state_prefix_remove(sfi))) {
8298 return result;
8299 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008300 }
8301
Gareth Williamsd5618a82015-05-20 11:13:32 +01008302 return 0;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008303}
8304
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308305#ifdef ECM_MULTICAST_ENABLE
8306/*
8307 * ecm_db_multicast_to_interfaces_xml_state_get()
8308 * Obtain XML state for the multicast destination interfaces list
8309 */
8310static int ecm_db_multicast_to_interfaces_xml_state_get(struct ecm_db_connection_instance *ci, struct ecm_state_file_instance *sfi)
8311{
8312 struct ecm_db_iface_instance *mc_ifaces;
8313 struct ecm_db_iface_instance *mc_ifaces_single[ECM_DB_IFACE_HEIRARCHY_MAX];
8314 struct ecm_db_iface_instance *ii_temp;
8315 int32_t *mc_ifaces_first;
8316 int32_t *ifaces_first;
8317 int32_t heirarchy_index;
8318 int ret;
8319
8320 ret = ecm_db_multicast_connection_to_interfaces_get_and_ref_all(ci, &mc_ifaces, &mc_ifaces_first);
8321 if (ret == 0) {
Shyam Sunder3af86a52015-08-28 18:04:10 +05308322 return ret;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308323 }
8324
8325 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
8326
8327 ii_temp = ecm_db_multicast_if_heirarchy_get(mc_ifaces, heirarchy_index);
8328 ecm_db_multicast_copy_if_heirarchy(mc_ifaces_single, ii_temp);
8329 ifaces_first = ecm_db_multicast_if_first_get_at_index(mc_ifaces_first, heirarchy_index);
8330
8331 if (ci->to_mcast_interface_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
8332 ret = ecm_db_connection_heirarchy_state_get(sfi, mc_ifaces_single, *ifaces_first);
8333 if (ret) {
8334 ecm_db_multicast_connection_to_interfaces_deref_all(mc_ifaces, mc_ifaces_first);
8335 return ret;
8336 }
8337
8338 }
8339 }
8340 ecm_db_multicast_connection_to_interfaces_deref_all(mc_ifaces, mc_ifaces_first);
8341
8342 return ret;
8343}
8344#endif
8345
Gareth Williamsf98d4192015-03-11 16:55:41 +00008346/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008347 * ecm_db_connection_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008348 * Prepare a connection message
8349 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008350int ecm_db_connection_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_connection_instance *ci)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008351{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008352 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008353 long int expires_in;
8354 int sport;
8355 int sport_nat;
Murat Sezginf21210e2016-04-04 13:58:20 -07008356 char snode_address[ECM_MAC_ADDR_STR_BUFF_SIZE];
8357 char snode_address_nat[ECM_MAC_ADDR_STR_BUFF_SIZE];
8358 char sip_address[ECM_IP_ADDR_STR_BUFF_SIZE];
8359 char sip_address_nat[ECM_IP_ADDR_STR_BUFF_SIZE];
8360 char dnode_address[ECM_MAC_ADDR_STR_BUFF_SIZE];
8361 char dnode_address_nat[ECM_MAC_ADDR_STR_BUFF_SIZE];
Gareth Williamsf98d4192015-03-11 16:55:41 +00008362 int dport;
8363 int dport_nat;
Murat Sezginf21210e2016-04-04 13:58:20 -07008364 char dip_address[ECM_IP_ADDR_STR_BUFF_SIZE];
8365 char dip_address_nat[ECM_IP_ADDR_STR_BUFF_SIZE];
Gareth Williamsf98d4192015-03-11 16:55:41 +00008366 ecm_db_direction_t direction;
Gareth Williams3e5b37f2015-05-13 10:04:12 +01008367 int ip_version;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008368 int protocol;
8369 bool is_routed;
Tushar Mathurd38cacd2015-07-28 12:19:10 +05308370 uint32_t regen_success;
8371 uint32_t regen_fail;
8372 uint16_t regen_required;
8373 uint16_t regen_occurances;
8374 bool regen_in_progress;
8375 uint16_t generation;
8376 uint16_t global_generation;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008377 uint32_t time_added;
8378 uint32_t serial;
8379 uint64_t from_data_total;
8380 uint64_t to_data_total;
8381 uint64_t from_packet_total;
8382 uint64_t to_packet_total;
8383 uint64_t from_data_total_dropped;
8384 uint64_t to_data_total_dropped;
8385 uint64_t from_packet_total_dropped;
8386 uint64_t to_packet_total_dropped;
8387 struct ecm_db_host_instance *hi;
8388 struct ecm_db_node_instance *ni;
8389 int aci_index;
8390 int aci_count;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308391 ip_addr_t __attribute__((unused)) group_ip;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008392 struct ecm_front_end_connection_instance *feci;
8393 struct ecm_classifier_instance *assignments[ECM_CLASSIFIER_TYPES];
8394 int32_t first_interface;
8395 struct ecm_db_iface_instance *interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
8396
8397 DEBUG_TRACE("Prep conn msg for %p\n", ci);
8398
8399 /*
8400 * Identify expiration
8401 */
8402 spin_lock_bh(&ecm_db_lock);
8403 if (ci->defunct_timer.group == ECM_DB_TIMER_GROUPS_MAX) {
8404 expires_in = -1;
8405 } else {
8406 expires_in = (long int)(ci->defunct_timer.timeout - ecm_db_time);
8407 if (expires_in <= 0) {
8408 expires_in = 0;
8409 }
8410 }
Tushar Mathurd38cacd2015-07-28 12:19:10 +05308411
8412 regen_success = ci->regen_success;
8413 regen_fail = ci->regen_fail;
8414 regen_required = ci->regen_required;
8415 regen_occurances = ci->regen_occurances;
8416 regen_in_progress = ci->regen_in_progress;
8417 generation = ci->generation;
8418 global_generation = ecm_db_connection_generation;
8419
Gareth Williamsf98d4192015-03-11 16:55:41 +00008420 spin_unlock_bh(&ecm_db_lock);
8421
8422 /*
8423 * Extract information from the connection for inclusion into the message
8424 */
8425 sport = ci->mapping_from->port;
8426 sport_nat = ci->mapping_nat_from->port;
8427 dport = ci->mapping_to->port;
8428 dport_nat = ci->mapping_nat_to->port;
8429
8430 hi = ci->mapping_to->host;
8431 ecm_ip_addr_to_string(dip_address, hi->address);
8432 ni = ci->to_node;
Murat Sezginf21210e2016-04-04 13:58:20 -07008433 snprintf(dnode_address, sizeof(dnode_address), "%pM", ni->address);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008434 hi = ci->mapping_nat_to->host;
8435 ecm_ip_addr_to_string(dip_address_nat, hi->address);
8436
8437 hi = ci->mapping_from->host;
8438 ecm_ip_addr_to_string(sip_address, hi->address);
8439 ni = ci->from_node;
Murat Sezginf21210e2016-04-04 13:58:20 -07008440 snprintf(snode_address, sizeof(snode_address), "%pM", ni->address);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008441 hi = ci->mapping_nat_from->host;
8442 ecm_ip_addr_to_string(sip_address_nat, hi->address);
8443
8444 ni = ci->to_nat_node;
Murat Sezginf21210e2016-04-04 13:58:20 -07008445 snprintf(dnode_address_nat, sizeof(dnode_address_nat), "%pM", ni->address);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008446
8447 ni = ci->from_nat_node;
Murat Sezginf21210e2016-04-04 13:58:20 -07008448 snprintf(snode_address_nat, sizeof(snode_address_nat), "%pM", ni->address);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008449
8450 direction = ci->direction;
Gareth Williams3e5b37f2015-05-13 10:04:12 +01008451 ip_version = ci->ip_version;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008452 protocol = ci->protocol;
8453 is_routed = ci->is_routed;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008454 time_added = ci->time_added;
8455 serial = ci->serial;
8456 ecm_db_connection_data_stats_get(ci, &from_data_total, &to_data_total,
8457 &from_packet_total, &to_packet_total,
8458 &from_data_total_dropped, &to_data_total_dropped,
8459 &from_packet_total_dropped, &to_packet_total_dropped);
8460
Gareth Williamsd5618a82015-05-20 11:13:32 +01008461 if ((result = ecm_state_prefix_add(sfi, "conn"))) {
8462 return result;
8463 }
8464 if ((result = ecm_state_prefix_index_add(sfi, serial))) {
8465 return result;
8466 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008467
Gareth Williamsd5618a82015-05-20 11:13:32 +01008468 if ((result = ecm_state_write(sfi, "serial", "%u", serial))) {
8469 return result;
8470 }
8471
8472 if ((result = ecm_state_write(sfi, "sip_address", "%s", sip_address))) {
8473 return result;
8474 }
8475
8476 if ((result = ecm_state_write(sfi, "sip_address_nat", "%s", sip_address_nat))) {
8477 return result;
8478 }
8479
8480 if ((result = ecm_state_write(sfi, "sport", "%d", sport))) {
8481 return result;
8482 }
8483
8484 if ((result = ecm_state_write(sfi, "sport_nat", "%d", sport_nat))) {
8485 return result;
8486 }
8487
8488 if ((result = ecm_state_write(sfi, "snode_address", "%s", snode_address))) {
8489 return result;
8490 }
8491
8492 if ((result = ecm_state_write(sfi, "snode_address_nat", "%s", snode_address_nat))) {
8493 return result;
8494 }
8495
8496 if ((result = ecm_state_write(sfi, "dip_address", "%s", dip_address))) {
8497 return result;
8498 }
8499
8500 if ((result = ecm_state_write(sfi, "dip_address_nat", "%s", dip_address_nat))) {
8501 return result;
8502 }
8503
8504 if ((result = ecm_state_write(sfi, "dport", "%d", dport))) {
8505 return result;
8506 }
8507
8508 if ((result = ecm_state_write(sfi, "dport_nat", "%d", dport_nat))) {
8509 return result;
8510 }
8511
8512 if ((result = ecm_state_write(sfi, "dnode_address", "%s", dnode_address))) {
8513 return result;
8514 }
8515
8516 if ((result = ecm_state_write(sfi, "dnode_address_nat", "%s", dnode_address_nat))) {
8517 return result;
8518 }
8519
Gareth Williams3e5b37f2015-05-13 10:04:12 +01008520 if ((result = ecm_state_write(sfi, "ip_version", "%d", ip_version))) {
8521 return result;
8522 }
8523
Gareth Williamsd5618a82015-05-20 11:13:32 +01008524 if ((result = ecm_state_write(sfi, "protocol", "%d", protocol))) {
8525 return result;
8526 }
8527
8528 if ((result = ecm_state_write(sfi, "is_routed", "%d", is_routed))) {
8529 return result;
8530 }
8531
8532 if ((result = ecm_state_write(sfi, "expires", "%ld", expires_in))) {
8533 return result;
8534 }
8535
8536 if ((result = ecm_state_write(sfi, "direction", "%d", direction))) {
8537 return result;
8538 }
8539
8540 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
8541 return result;
8542 }
8543
Tushar Mathurd38cacd2015-07-28 12:19:10 +05308544 if ((result = ecm_state_write(sfi, "regen_success", "%u", regen_success))) {
8545 return result;
8546 }
8547 if ((result = ecm_state_write(sfi, "regen_fail", "%u", regen_fail))) {
8548 return result;
8549 }
8550 if ((result = ecm_state_write(sfi, "regen_required", "%u", regen_required))) {
8551 return result;
8552 }
8553 if ((result = ecm_state_write(sfi, "regen_occurances", "%u", regen_occurances))) {
8554 return result;
8555 }
8556 if ((result = ecm_state_write(sfi, "regen_in_progress", "%u", regen_in_progress))) {
8557 return result;
8558 }
8559 if ((result = ecm_state_write(sfi, "generation", "%u/%u", generation, global_generation))) {
Gareth Williamsd5618a82015-05-20 11:13:32 +01008560 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008561 }
8562
8563 /*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008564 * NOTE: These advanced stats are not conditional compiled.
8565 * Connections always contain these stats
Gareth Williamsf98d4192015-03-11 16:55:41 +00008566 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008567 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
8568 from_packet_total, to_packet_total, from_data_total_dropped,
8569 to_data_total_dropped, from_packet_total_dropped,
8570 to_packet_total_dropped))) {
8571 return result;
8572 }
8573
8574 if ((result = ecm_state_prefix_add(sfi, "from_interfaces"))) {
8575 return result;
8576 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008577 first_interface = ecm_db_connection_from_interfaces_get_and_ref(ci, interfaces);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008578 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008579 ecm_db_connection_interfaces_deref(interfaces, first_interface);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008580 if (result) {
8581 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008582 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008583 if ((result = ecm_state_prefix_remove(sfi))) {
8584 return result;
8585 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008586
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308587#ifdef ECM_MULTICAST_ENABLE
8588 ecm_db_connection_to_address_get(ci, group_ip);
8589 if (ecm_ip_addr_is_multicast(group_ip)) {
8590 if ((result = ecm_state_prefix_add(sfi, "to_mc_interfaces"))) {
8591 return result;
8592 }
8593
8594 if ((result = ecm_db_multicast_to_interfaces_xml_state_get(ci, sfi))) {
8595 return result;
8596 }
8597
8598 if ((result = ecm_state_prefix_remove(sfi))) {
8599 return result;
8600 }
8601 }
8602 else {
8603 if ((result = ecm_state_prefix_add(sfi, "to_interfaces"))) {
8604 return result;
8605 }
8606
8607 first_interface = ecm_db_connection_to_interfaces_get_and_ref(ci, interfaces);
8608 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
8609 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8610 if (result) {
8611 return result;
8612 }
8613
8614 if ((result = ecm_state_prefix_remove(sfi))) {
8615 return result;
8616 }
8617 }
8618#else
Gareth Williamsd5618a82015-05-20 11:13:32 +01008619 if ((result = ecm_state_prefix_add(sfi, "to_interfaces"))) {
8620 return result;
8621 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008622 first_interface = ecm_db_connection_to_interfaces_get_and_ref(ci, interfaces);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008623 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008624 ecm_db_connection_interfaces_deref(interfaces, first_interface);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008625 if (result) {
8626 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008627 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008628 if ((result = ecm_state_prefix_remove(sfi))) {
8629 return result;
8630 }
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308631#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008632
Gareth Williamsd5618a82015-05-20 11:13:32 +01008633 if ((result = ecm_state_prefix_add(sfi, "from_nat_interfaces"))) {
8634 return result;
8635 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008636 first_interface = ecm_db_connection_from_nat_interfaces_get_and_ref(ci, interfaces);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008637 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008638 ecm_db_connection_interfaces_deref(interfaces, first_interface);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008639 if (result) {
8640 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008641 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008642 if ((result = ecm_state_prefix_remove(sfi))) {
8643 return result;
8644 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008645
Gareth Williamsd5618a82015-05-20 11:13:32 +01008646 if ((result = ecm_state_prefix_add(sfi, "to_nat_interfaces"))) {
8647 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008648 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008649 first_interface = ecm_db_connection_to_nat_interfaces_get_and_ref(ci, interfaces);
8650 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
8651 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8652 if (result) {
8653 return result;
8654 }
8655 if ((result = ecm_state_prefix_remove(sfi))) {
8656 return result;
8657 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008658
8659 /*
8660 * Output front end state
8661 */
8662 feci = ecm_db_connection_front_end_get_and_ref(ci);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008663 result = feci->state_get(feci, sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008664 feci->deref(feci);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008665 if (result) {
8666 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008667 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008668
8669 if ((result = ecm_state_prefix_add(sfi, "classifiers"))) {
8670 return result;
8671 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008672
8673 /*
8674 * Grab references to the assigned classifiers so we can produce state for them
8675 */
8676 aci_count = ecm_db_connection_classifier_assignments_get_and_ref(ci, assignments);
8677
8678 /*
8679 * Iterate the assigned classifiers and provide a state record for each
8680 */
8681 for (aci_index = 0; aci_index < aci_count; ++aci_index) {
8682 struct ecm_classifier_instance *aci;
8683
8684 aci = assignments[aci_index];
Gareth Williamsd5618a82015-05-20 11:13:32 +01008685 result = aci->state_get(aci, sfi);
8686 if (result) {
Gareth Williamsf98d4192015-03-11 16:55:41 +00008687 ecm_db_connection_assignments_release(aci_count, assignments);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008688 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008689 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008690 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008691
Gareth Williamsf98d4192015-03-11 16:55:41 +00008692 ecm_db_connection_assignments_release(aci_count, assignments);
8693
Gareth Williamsd5618a82015-05-20 11:13:32 +01008694 if ((result = ecm_state_prefix_remove(sfi))) {
8695 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008696 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008697
8698 if ((result = ecm_state_prefix_remove(sfi))) {
8699 return result;
8700 }
8701
8702 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008703}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008704EXPORT_SYMBOL(ecm_db_connection_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008705
8706/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008707 * ecm_db_mapping_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008708 * Prepare a mapping message
8709 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008710int ecm_db_mapping_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_mapping_instance *mi)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008711{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008712 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008713 int port;
Murat Sezginf21210e2016-04-04 13:58:20 -07008714 char address[ECM_IP_ADDR_STR_BUFF_SIZE];
Gareth Williamsf98d4192015-03-11 16:55:41 +00008715 int tcp_from;
8716 int tcp_to;
8717 int udp_from;
8718 int udp_to;
8719 int from;
8720 int to;
8721 int tcp_nat_from;
8722 int tcp_nat_to;
8723 int udp_nat_from;
8724 int udp_nat_to;
8725 int nat_from;
8726 int nat_to;
8727 uint32_t time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008728 struct ecm_db_host_instance *hi;
8729#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008730 uint64_t from_data_total;
8731 uint64_t to_data_total;
8732 uint64_t from_packet_total;
8733 uint64_t to_packet_total;
8734 uint64_t from_data_total_dropped;
8735 uint64_t to_data_total_dropped;
8736 uint64_t from_packet_total_dropped;
8737 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00008738#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008739
8740 DEBUG_TRACE("Prep mapping msg for %p\n", mi);
8741
8742 /*
8743 * Create a small xml stats element for our mapping.
8744 * Extract information from the mapping for inclusion into the message
8745 */
8746 ecm_db_mapping_port_count_get(mi, &tcp_from, &tcp_to, &udp_from, &udp_to, &from, &to,
8747 &tcp_nat_from, &tcp_nat_to, &udp_nat_from, &udp_nat_to, &nat_from, &nat_to);
8748 port = mi->port;
8749 time_added = mi->time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008750 hi = mi->host;
8751 ecm_ip_addr_to_string(address, hi->address);
8752
8753#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008754 ecm_db_mapping_data_stats_get(mi, &from_data_total, &to_data_total,
8755 &from_packet_total, &to_packet_total,
8756 &from_data_total_dropped, &to_data_total_dropped,
8757 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williams85331c92015-03-11 20:39:18 +00008758#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008759
Gareth Williamsd5618a82015-05-20 11:13:32 +01008760 if ((result = ecm_state_prefix_add(sfi, "mapping"))) {
8761 return result;
8762 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008763
Gareth Williamsd5618a82015-05-20 11:13:32 +01008764 if ((result = ecm_state_write(sfi, "port", "%d", port))) {
8765 return result;
8766 }
8767
8768 if ((result = ecm_state_write(sfi, "from", "%d", from))) {
8769 return result;
8770 }
8771
8772 if ((result = ecm_state_write(sfi, "to", "%d", to))) {
8773 return result;
8774 }
8775
8776 if ((result = ecm_state_write(sfi, "tcp_from", "%d", tcp_from))) {
8777 return result;
8778 }
8779
8780 if ((result = ecm_state_write(sfi, "tcp_to", "%d", tcp_to))) {
8781 return result;
8782 }
8783
8784 if ((result = ecm_state_write(sfi, "udp_from", "%d", udp_from))) {
8785 return result;
8786 }
8787
8788 if ((result = ecm_state_write(sfi, "udp_to", "%d", udp_to))) {
8789 return result;
8790 }
8791
8792 if ((result = ecm_state_write(sfi, "nat_from", "%d", nat_from))) {
8793 return result;
8794 }
8795
8796 if ((result = ecm_state_write(sfi, "nat_to", "%d", nat_to))) {
8797 return result;
8798 }
8799
8800 if ((result = ecm_state_write(sfi, "tcp_nat_from", "%d", tcp_nat_from))) {
8801 return result;
8802 }
8803
8804 if ((result = ecm_state_write(sfi, "tcp_nat_to", "%d", tcp_nat_to))) {
8805 return result;
8806 }
8807
8808 if ((result = ecm_state_write(sfi, "udp_nat_from", "%d", udp_nat_from))) {
8809 return result;
8810 }
8811
8812 if ((result = ecm_state_write(sfi, "udp_nat_to", "%d", udp_nat_to))) {
8813 return result;
8814 }
8815
8816 if ((result = ecm_state_write(sfi, "address", "%s", address))) {
8817 return result;
8818 }
8819
8820 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
8821 return result;
8822 }
8823
8824#ifdef ECM_DB_ADVANCED_STATS_ENABLE
8825 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
8826 from_packet_total, to_packet_total, from_data_total_dropped,
8827 to_data_total_dropped, from_packet_total_dropped,
8828 to_packet_total_dropped))) {
8829 return result;
8830 }
8831#endif
8832
8833 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008834}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008835EXPORT_SYMBOL(ecm_db_mapping_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008836
8837/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008838 * ecm_db_host_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008839 * Prepare a host message
8840 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008841int ecm_db_host_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_host_instance *hi)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008842{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008843 int result;
Murat Sezginf21210e2016-04-04 13:58:20 -07008844 char address[ECM_IP_ADDR_STR_BUFF_SIZE];
Gareth Williamsb5903892015-03-20 15:13:07 +00008845#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008846 int mapping_count;
Gareth Williamsb5903892015-03-20 15:13:07 +00008847#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008848 uint32_t time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008849 bool on_link;
8850#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008851 uint64_t from_data_total;
8852 uint64_t to_data_total;
8853 uint64_t from_packet_total;
8854 uint64_t to_packet_total;
8855 uint64_t from_data_total_dropped;
8856 uint64_t to_data_total_dropped;
8857 uint64_t from_packet_total_dropped;
8858 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00008859#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008860
8861 DEBUG_TRACE("Prep host msg for %p\n", hi);
8862
8863 /*
8864 * Create a small xml stats element for our host.
8865 * Extract information from the host for inclusion into the message
8866 */
Gareth Williamsb5903892015-03-20 15:13:07 +00008867#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008868 mapping_count = ecm_db_host_mapping_count_get(hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00008869#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008870 ecm_ip_addr_to_string(address, hi->address);
8871 time_added = hi->time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008872 on_link = hi->on_link;
8873
8874#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008875 ecm_db_host_data_stats_get(hi, &from_data_total, &to_data_total,
8876 &from_packet_total, &to_packet_total,
8877 &from_data_total_dropped, &to_data_total_dropped,
8878 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williams85331c92015-03-11 20:39:18 +00008879#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008880
Gareth Williamsd5618a82015-05-20 11:13:32 +01008881 if ((result = ecm_state_prefix_add(sfi, "host"))) {
8882 return result;
8883 }
8884
8885 if ((result = ecm_state_write(sfi, "address", "%s", address))) {
8886 return result;
8887 }
8888 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
8889 return result;
8890 }
8891 if ((result = ecm_state_write(sfi, "on_link", "%d", on_link))) {
8892 return result;
8893 }
8894
Gareth Williamsb5903892015-03-20 15:13:07 +00008895#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008896 if ((result = ecm_state_write(sfi, "mappings", "%d", mapping_count))) {
8897 return result;
8898 }
Gareth Williamsb5903892015-03-20 15:13:07 +00008899#endif
Gareth Williamsd5618a82015-05-20 11:13:32 +01008900
Gareth Williams85331c92015-03-11 20:39:18 +00008901#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008902 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
8903 from_packet_total, to_packet_total, from_data_total_dropped,
8904 to_data_total_dropped, from_packet_total_dropped,
8905 to_packet_total_dropped))) {
8906 return result;
8907 }
Gareth Williams85331c92015-03-11 20:39:18 +00008908#endif
Gareth Williamsd5618a82015-05-20 11:13:32 +01008909
8910 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008911}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008912EXPORT_SYMBOL(ecm_db_host_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008913
8914/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008915 * ecm_db_node_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008916 * Prepare a node message
8917 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008918int ecm_db_node_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_node_instance *ni)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008919{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008920 int result;
Murat Sezginf21210e2016-04-04 13:58:20 -07008921 char address[ECM_MAC_ADDR_STR_BUFF_SIZE];
Gareth Williamsb5903892015-03-20 15:13:07 +00008922#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008923 int from_connections_count;
8924 int to_connections_count;
8925 int from_nat_connections_count;
8926 int to_nat_connections_count;
Gareth Williamsb5903892015-03-20 15:13:07 +00008927#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008928 uint32_t time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008929#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008930 uint64_t from_data_total;
8931 uint64_t to_data_total;
8932 uint64_t from_packet_total;
8933 uint64_t to_packet_total;
8934 uint64_t from_data_total_dropped;
8935 uint64_t to_data_total_dropped;
8936 uint64_t from_packet_total_dropped;
8937 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00008938#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008939
8940 DEBUG_TRACE("Prep node msg for %p\n", ni);
8941
8942 /*
8943 * Create a small xml stats block for our managed node, like:
8944 * <node address="" hosts="" time_added="" from_data_total="" to_data_total="" />
8945 *
8946 * Extract information from the node for inclusion into the message
8947 */
Gareth Williamsb5903892015-03-20 15:13:07 +00008948#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008949 spin_lock_bh(&ecm_db_lock);
8950 from_connections_count = ni->from_connections_count;
8951 to_connections_count = ni->to_connections_count;
8952 from_nat_connections_count = ni->from_nat_connections_count;
8953 to_nat_connections_count = ni->to_nat_connections_count;
8954 spin_unlock_bh(&ecm_db_lock);
Gareth Williamsb5903892015-03-20 15:13:07 +00008955#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008956 time_added = ni->time_added;
Murat Sezginf21210e2016-04-04 13:58:20 -07008957 snprintf(address, sizeof(address), "%pM", ni->address);
Gareth Williams85331c92015-03-11 20:39:18 +00008958
8959#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008960 ecm_db_node_data_stats_get(ni, &from_data_total, &to_data_total,
8961 &from_packet_total, &to_packet_total,
8962 &from_data_total_dropped, &to_data_total_dropped,
8963 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williams85331c92015-03-11 20:39:18 +00008964
8965#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008966
Gareth Williamsd5618a82015-05-20 11:13:32 +01008967 if ((result = ecm_state_prefix_add(sfi, "node"))) {
8968 return result;
8969 }
8970 if ((result = ecm_state_write(sfi, "address", "%s", address))) {
8971 return result;
8972 }
8973 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
8974 return result;
8975 }
Gareth Williamsb5903892015-03-20 15:13:07 +00008976#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008977 if ((result = ecm_state_write(sfi, "from_connections_count", "%d", from_connections_count))) {
8978 return result;
8979 }
8980 if ((result = ecm_state_write(sfi, "to_connections_count", "%d", to_connections_count))) {
8981 return result;
8982 }
8983 if ((result = ecm_state_write(sfi, "from_nat_connections_count", "%d", from_nat_connections_count))) {
8984 return result;
8985 }
8986 if ((result = ecm_state_write(sfi, "to_nat_connections_count", "%d", to_nat_connections_count))) {
8987 return result;
8988 }
Gareth Williamsb5903892015-03-20 15:13:07 +00008989#endif
Gareth Williams85331c92015-03-11 20:39:18 +00008990#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008991 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
8992 from_packet_total, to_packet_total, from_data_total_dropped,
8993 to_data_total_dropped, from_packet_total_dropped,
8994 to_packet_total_dropped))) {
8995 return result;
8996 }
Gareth Williams85331c92015-03-11 20:39:18 +00008997#endif
Gareth Williamsd5618a82015-05-20 11:13:32 +01008998 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008999}
Gareth Williamsd5618a82015-05-20 11:13:32 +01009000EXPORT_SYMBOL(ecm_db_node_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00009001
9002/*
9003 * ecm_db_connection_hash_table_lengths_get()
9004 * Return hash table length
9005 */
9006int ecm_db_connection_hash_table_lengths_get(int index)
9007{
9008 int length;
9009
9010 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_MAPPING_HASH_SLOTS), "Bad protocol: %d\n", index);
9011 spin_lock_bh(&ecm_db_lock);
9012 length = ecm_db_connection_table_lengths[index];
9013 spin_unlock_bh(&ecm_db_lock);
9014 return length;
9015}
9016EXPORT_SYMBOL(ecm_db_connection_hash_table_lengths_get);
9017
9018/*
9019 * ecm_db_connection_hash_index_get_next()
9020 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
9021 */
9022int ecm_db_connection_hash_index_get_next(int index)
9023{
9024 index++;
9025 if (index >= ECM_DB_CONNECTION_SERIAL_HASH_SLOTS) {
9026 return -1;
9027 }
9028 return index;
9029}
9030EXPORT_SYMBOL(ecm_db_connection_hash_index_get_next);
9031
9032/*
9033 * ecm_db_connection_hash_index_get_first()
9034 * Return first hash index
9035 */
9036int ecm_db_connection_hash_index_get_first(void)
9037{
9038 return 0;
9039}
9040EXPORT_SYMBOL(ecm_db_connection_hash_index_get_first);
9041
9042/*
9043 * ecm_db_mapping_hash_table_lengths_get()
9044 * Return hash table length
9045 */
9046int ecm_db_mapping_hash_table_lengths_get(int index)
9047{
9048 int length;
9049
9050 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_MAPPING_HASH_SLOTS), "Bad protocol: %d\n", index);
9051 spin_lock_bh(&ecm_db_lock);
9052 length = ecm_db_mapping_table_lengths[index];
9053 spin_unlock_bh(&ecm_db_lock);
9054 return length;
9055}
9056EXPORT_SYMBOL(ecm_db_mapping_hash_table_lengths_get);
9057
9058/*
9059 * ecm_db_mapping_hash_index_get_next()
9060 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
9061 */
9062int ecm_db_mapping_hash_index_get_next(int index)
9063{
9064 index++;
9065 if (index >= ECM_DB_MAPPING_HASH_SLOTS) {
9066 return -1;
9067 }
9068 return index;
9069}
9070EXPORT_SYMBOL(ecm_db_mapping_hash_index_get_next);
9071
9072/*
9073 * ecm_db_mapping_hash_index_get_first()
9074 * Return first hash index
9075 */
9076int ecm_db_mapping_hash_index_get_first(void)
9077{
9078 return 0;
9079}
9080EXPORT_SYMBOL(ecm_db_mapping_hash_index_get_first);
9081
9082/*
9083 * ecm_db_host_hash_table_lengths_get()
9084 * Return hash table length
9085 */
9086int ecm_db_host_hash_table_lengths_get(int index)
9087{
9088 int length;
9089
9090 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_HOST_HASH_SLOTS), "Bad protocol: %d\n", index);
9091 spin_lock_bh(&ecm_db_lock);
9092 length = ecm_db_host_table_lengths[index];
9093 spin_unlock_bh(&ecm_db_lock);
9094 return length;
9095}
9096EXPORT_SYMBOL(ecm_db_host_hash_table_lengths_get);
9097
9098/*
9099 * ecm_db_host_hash_index_get_next()
9100 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
9101 */
9102int ecm_db_host_hash_index_get_next(int index)
9103{
9104 index++;
9105 if (index >= ECM_DB_HOST_HASH_SLOTS) {
9106 return -1;
9107 }
9108 return index;
9109}
9110EXPORT_SYMBOL(ecm_db_host_hash_index_get_next);
9111
9112/*
9113 * ecm_db_host_hash_index_get_first()
9114 * Return first hash index
9115 */
9116int ecm_db_host_hash_index_get_first(void)
9117{
9118 return 0;
9119}
9120EXPORT_SYMBOL(ecm_db_host_hash_index_get_first);
9121
9122/*
9123 * ecm_db_node_hash_table_lengths_get()
9124 * Return hash table length
9125 */
9126int ecm_db_node_hash_table_lengths_get(int index)
9127{
9128 int length;
9129
9130 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_NODE_HASH_SLOTS), "Bad protocol: %d\n", index);
9131 spin_lock_bh(&ecm_db_lock);
9132 length = ecm_db_node_table_lengths[index];
9133 spin_unlock_bh(&ecm_db_lock);
9134 return length;
9135}
9136EXPORT_SYMBOL(ecm_db_node_hash_table_lengths_get);
9137
9138/*
9139 * ecm_db_node_hash_index_get_next()
9140 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
9141 */
9142int ecm_db_node_hash_index_get_next(int index)
9143{
9144 index++;
9145 if (index >= ECM_DB_NODE_HASH_SLOTS) {
9146 return -1;
9147 }
9148 return index;
9149}
9150EXPORT_SYMBOL(ecm_db_node_hash_index_get_next);
9151
9152/*
9153 * ecm_db_node_hash_index_get_first()
9154 * Return first hash index
9155 */
9156int ecm_db_node_hash_index_get_first(void)
9157{
9158 return 0;
9159}
9160EXPORT_SYMBOL(ecm_db_node_hash_index_get_first);
9161
9162/*
9163 * ecm_db_iface_hash_table_lengths_get()
9164 * Return hash table length
9165 */
9166int ecm_db_iface_hash_table_lengths_get(int index)
9167{
9168 int length;
9169
9170 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_IFACE_HASH_SLOTS), "Bad protocol: %d\n", index);
9171 spin_lock_bh(&ecm_db_lock);
9172 length = ecm_db_iface_table_lengths[index];
9173 spin_unlock_bh(&ecm_db_lock);
9174 return length;
9175}
9176EXPORT_SYMBOL(ecm_db_iface_hash_table_lengths_get);
9177
9178/*
9179 * ecm_db_iface_hash_index_get_next()
9180 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
9181 */
9182int ecm_db_iface_hash_index_get_next(int index)
9183{
9184 index++;
9185 if (index >= ECM_DB_IFACE_HASH_SLOTS) {
9186 return -1;
9187 }
9188 return index;
9189}
9190EXPORT_SYMBOL(ecm_db_iface_hash_index_get_next);
9191
9192/*
9193 * ecm_db_iface_hash_index_get_first()
9194 * Return first hash index
9195 */
9196int ecm_db_iface_hash_index_get_first(void)
9197{
9198 return 0;
9199}
9200EXPORT_SYMBOL(ecm_db_iface_hash_index_get_first);
9201
9202/*
9203 * ecm_db_protocol_get_next()
9204 * Given a number, return the next one OR return -1 for no more protocol numbers to return.
9205 */
9206int ecm_db_protocol_get_next(int protocol)
9207{
9208 protocol++;
9209 if (protocol >= ECM_DB_PROTOCOL_COUNT) {
9210 return -1;
9211 }
9212 return protocol;
9213}
9214EXPORT_SYMBOL(ecm_db_protocol_get_next);
9215
9216/*
9217 * ecm_db_protocol_get_first()
9218 * Return first protocol number
9219 */
9220int ecm_db_protocol_get_first(void)
9221{
9222 return 0;
9223}
9224EXPORT_SYMBOL(ecm_db_protocol_get_first);
9225#endif
9226
9227/*
9228 * ecm_db_iface_add_ethernet()
9229 * Add a iface instance into the database
9230 */
9231void ecm_db_iface_add_ethernet(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -07009232 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009233 ecm_db_iface_final_callback_t final, void *arg)
9234{
9235 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009236 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009237 struct ecm_db_listener_instance *li;
9238 struct ecm_db_interface_info_ethernet *type_info;
9239
9240 spin_lock_bh(&ecm_db_lock);
9241 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9242 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009243#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009244 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009245#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009246 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9247 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9248 spin_unlock_bh(&ecm_db_lock);
9249
9250 /*
9251 * Record general info
9252 */
9253 ii->type = ECM_DB_IFACE_TYPE_ETHERNET;
9254#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009255 ii->state_get = ecm_db_iface_ethernet_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009256#endif
9257 ii->arg = arg;
9258 ii->final = final;
9259 strcpy(ii->name, name);
9260 ii->mtu = mtu;
9261 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009262 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009263
9264 /*
9265 * Type specific info
9266 */
9267 type_info = &ii->type_info.ethernet;
9268 memcpy(type_info->address, address, ETH_ALEN);
9269
9270 /*
9271 * Compute hash chain for insertion
9272 */
9273 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
9274 ii->hash_index = hash_index;
9275
Murat Sezgin91c5d712015-06-12 15:16:22 -07009276 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9277 ii->iface_id_hash_index = iface_id_hash_index;
9278
Gareth Williamsf98d4192015-03-11 16:55:41 +00009279 /*
9280 * Add into the global list
9281 */
9282 spin_lock_bh(&ecm_db_lock);
9283 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9284 ii->prev = NULL;
9285 ii->next = ecm_db_interfaces;
9286 if (ecm_db_interfaces) {
9287 ecm_db_interfaces->prev = ii;
9288 }
9289 ecm_db_interfaces = ii;
9290
9291 /*
9292 * Insert into chain
9293 */
9294 ii->hash_next = ecm_db_iface_table[hash_index];
9295 if (ecm_db_iface_table[hash_index]) {
9296 ecm_db_iface_table[hash_index]->hash_prev = ii;
9297 }
9298 ecm_db_iface_table[hash_index] = ii;
9299 ecm_db_iface_table_lengths[hash_index]++;
9300 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9301
9302 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
9303
9304 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009305 * Insert into interface identifier chain
9306 */
9307 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9308 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9309 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9310 }
9311 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9312 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9313 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
9314
9315 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009316 * Set time of addition
9317 */
9318 ii->time_added = ecm_db_time;
9319 spin_unlock_bh(&ecm_db_lock);
9320
9321 /*
9322 * Throw add event to the listeners
9323 */
9324 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9325 li = ecm_db_listeners_get_and_ref_first();
9326 while (li) {
9327 struct ecm_db_listener_instance *lin;
9328 if (li->iface_added) {
9329 li->iface_added(li->arg, ii);
9330 }
9331
9332 /*
9333 * Get next listener
9334 */
9335 lin = ecm_db_listener_get_and_ref_next(li);
9336 ecm_db_listener_deref(li);
9337 li = lin;
9338 }
9339}
9340EXPORT_SYMBOL(ecm_db_iface_add_ethernet);
9341
9342#ifdef ECM_INTERFACE_BOND_ENABLE
9343/*
9344 * ecm_db_iface_add_lag()
9345 * Add a iface instance into the database
9346 */
9347void ecm_db_iface_add_lag(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -07009348 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009349 ecm_db_iface_final_callback_t final, void *arg)
9350{
9351 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009352 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009353 struct ecm_db_listener_instance *li;
9354 struct ecm_db_interface_info_lag *type_info;
9355
9356 spin_lock_bh(&ecm_db_lock);
9357 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9358 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009359#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009360 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009361#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009362 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9363 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9364 spin_unlock_bh(&ecm_db_lock);
9365
9366 /*
9367 * Record general info
9368 */
9369 ii->type = ECM_DB_IFACE_TYPE_LAG;
9370#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009371 ii->state_get = ecm_db_iface_lag_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009372#endif
9373 ii->arg = arg;
9374 ii->final = final;
9375 strcpy(ii->name, name);
9376 ii->mtu = mtu;
9377 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009378 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009379
9380 /*
9381 * Type specific info
9382 */
9383 type_info = &ii->type_info.lag;
9384 memcpy(type_info->address, address, ETH_ALEN);
9385
9386 /*
9387 * Compute hash chain for insertion
9388 */
9389 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
9390 ii->hash_index = hash_index;
9391
Murat Sezgin91c5d712015-06-12 15:16:22 -07009392 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9393 ii->iface_id_hash_index = iface_id_hash_index;
9394
Gareth Williamsf98d4192015-03-11 16:55:41 +00009395 /*
9396 * Add into the global list
9397 */
9398 spin_lock_bh(&ecm_db_lock);
9399 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9400 ii->prev = NULL;
9401 ii->next = ecm_db_interfaces;
9402 if (ecm_db_interfaces) {
9403 ecm_db_interfaces->prev = ii;
9404 }
9405 ecm_db_interfaces = ii;
9406
9407 /*
9408 * Insert into chain
9409 */
9410 ii->hash_next = ecm_db_iface_table[hash_index];
9411 if (ecm_db_iface_table[hash_index]) {
9412 ecm_db_iface_table[hash_index]->hash_prev = ii;
9413 }
9414 ecm_db_iface_table[hash_index] = ii;
9415 ecm_db_iface_table_lengths[hash_index]++;
9416 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9417
9418 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
9419
9420 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009421 * Insert into interface identifier chain
9422 */
9423 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9424 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9425 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9426 }
9427 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9428 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9429 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
9430
9431 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009432 * Set time of addition
9433 */
9434 ii->time_added = ecm_db_time;
9435 spin_unlock_bh(&ecm_db_lock);
9436
9437 /*
9438 * Throw add event to the listeners
9439 */
9440 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9441 li = ecm_db_listeners_get_and_ref_first();
9442 while (li) {
9443 struct ecm_db_listener_instance *lin;
9444 if (li->iface_added) {
9445 li->iface_added(li->arg, ii);
9446 }
9447
9448 /*
9449 * Get next listener
9450 */
9451 lin = ecm_db_listener_get_and_ref_next(li);
9452 ecm_db_listener_deref(li);
9453 li = lin;
9454 }
9455}
9456EXPORT_SYMBOL(ecm_db_iface_add_lag);
9457#endif
9458
9459/*
9460 * ecm_db_iface_add_bridge()
9461 * Add a iface instance into the database
9462 */
9463void ecm_db_iface_add_bridge(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -07009464 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009465 ecm_db_iface_final_callback_t final, void *arg)
9466{
9467 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009468 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009469 struct ecm_db_listener_instance *li;
9470 struct ecm_db_interface_info_bridge *type_info;
9471
9472 spin_lock_bh(&ecm_db_lock);
9473 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9474 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009475#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009476 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009477#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009478 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9479 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9480 spin_unlock_bh(&ecm_db_lock);
9481
9482 /*
9483 * Record general info
9484 */
9485 ii->type = ECM_DB_IFACE_TYPE_BRIDGE;
9486#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009487 ii->state_get = ecm_db_iface_bridge_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009488#endif
9489 ii->arg = arg;
9490 ii->final = final;
9491 strcpy(ii->name, name);
9492 ii->mtu = mtu;
9493 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009494 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009495
9496 /*
9497 * Type specific info
9498 */
9499 type_info = &ii->type_info.bridge;
9500 memcpy(type_info->address, address, ETH_ALEN);
9501
9502 /*
9503 * Compute hash chain for insertion
9504 */
9505 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
9506 ii->hash_index = hash_index;
9507
Murat Sezgin91c5d712015-06-12 15:16:22 -07009508 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9509 ii->iface_id_hash_index = iface_id_hash_index;
9510
Gareth Williamsf98d4192015-03-11 16:55:41 +00009511 /*
9512 * Add into the global list
9513 */
9514 spin_lock_bh(&ecm_db_lock);
9515 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9516 ii->prev = NULL;
9517 ii->next = ecm_db_interfaces;
9518 if (ecm_db_interfaces) {
9519 ecm_db_interfaces->prev = ii;
9520 }
9521 ecm_db_interfaces = ii;
9522
9523 /*
9524 * Insert into chain
9525 */
9526 ii->hash_next = ecm_db_iface_table[hash_index];
9527 if (ecm_db_iface_table[hash_index]) {
9528 ecm_db_iface_table[hash_index]->hash_prev = ii;
9529 }
9530 ecm_db_iface_table[hash_index] = ii;
9531 ecm_db_iface_table_lengths[hash_index]++;
9532 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9533
9534 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
9535
9536 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009537 * Insert into interface identifier chain
9538 */
9539 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9540 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9541 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9542 }
9543 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9544 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9545 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
9546
9547 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009548 * Set time of addition
9549 */
9550 ii->time_added = ecm_db_time;
9551 spin_unlock_bh(&ecm_db_lock);
9552
9553 /*
9554 * Throw add event to the listeners
9555 */
9556 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9557 li = ecm_db_listeners_get_and_ref_first();
9558 while (li) {
9559 struct ecm_db_listener_instance *lin;
9560 if (li->iface_added) {
9561 li->iface_added(li->arg, ii);
9562 }
9563
9564 /*
9565 * Get next listener
9566 */
9567 lin = ecm_db_listener_get_and_ref_next(li);
9568 ecm_db_listener_deref(li);
9569 li = lin;
9570 }
9571}
9572EXPORT_SYMBOL(ecm_db_iface_add_bridge);
9573
9574#ifdef ECM_INTERFACE_VLAN_ENABLE
9575/*
9576 * ecm_db_iface_add_vlan()
9577 * Add a iface instance into the database
9578 */
9579void ecm_db_iface_add_vlan(struct ecm_db_iface_instance *ii, uint8_t *address, uint16_t vlan_tag, uint16_t vlan_tpid, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -07009580 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009581 ecm_db_iface_final_callback_t final, void *arg)
9582{
9583 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009584 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009585 struct ecm_db_listener_instance *li;
9586 struct ecm_db_interface_info_vlan *type_info;
9587
9588 spin_lock_bh(&ecm_db_lock);
9589 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9590 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009591#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009592 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009593#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009594 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9595 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9596 spin_unlock_bh(&ecm_db_lock);
9597
9598 /*
9599 * Record general info
9600 */
9601 ii->type = ECM_DB_IFACE_TYPE_VLAN;
9602#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009603 ii->state_get = ecm_db_iface_vlan_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009604#endif
9605 ii->arg = arg;
9606 ii->final = final;
9607 strcpy(ii->name, name);
9608 ii->mtu = mtu;
9609 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009610 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009611
9612 /*
9613 * Type specific info
9614 */
9615 type_info = &ii->type_info.vlan;
9616 type_info->vlan_tag = vlan_tag;
9617 type_info->vlan_tpid = vlan_tpid;
9618 memcpy(type_info->address, address, ETH_ALEN);
9619
9620 /*
9621 * Compute hash chain for insertion
9622 */
9623 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
9624 ii->hash_index = hash_index;
9625
Murat Sezgin91c5d712015-06-12 15:16:22 -07009626 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9627 ii->iface_id_hash_index = iface_id_hash_index;
9628
Gareth Williamsf98d4192015-03-11 16:55:41 +00009629 /*
9630 * Add into the global list
9631 */
9632 spin_lock_bh(&ecm_db_lock);
9633 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9634 ii->prev = NULL;
9635 ii->next = ecm_db_interfaces;
9636 if (ecm_db_interfaces) {
9637 ecm_db_interfaces->prev = ii;
9638 }
9639 ecm_db_interfaces = ii;
9640
9641 /*
9642 * Insert into chain
9643 */
9644 ii->hash_next = ecm_db_iface_table[hash_index];
9645 if (ecm_db_iface_table[hash_index]) {
9646 ecm_db_iface_table[hash_index]->hash_prev = ii;
9647 }
9648 ecm_db_iface_table[hash_index] = ii;
9649 ecm_db_iface_table_lengths[hash_index]++;
9650 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9651
9652 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
9653
9654 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009655 * Insert into interface identifier chain
9656 */
9657 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9658 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9659 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9660 }
9661 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9662 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9663 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
9664
9665 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009666 * Set time of addition
9667 */
9668 ii->time_added = ecm_db_time;
9669 spin_unlock_bh(&ecm_db_lock);
9670
9671 /*
9672 * Throw add event to the listeners
9673 */
9674 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9675 li = ecm_db_listeners_get_and_ref_first();
9676 while (li) {
9677 struct ecm_db_listener_instance *lin;
9678 if (li->iface_added) {
9679 li->iface_added(li->arg, ii);
9680 }
9681
9682 /*
9683 * Get next listener
9684 */
9685 lin = ecm_db_listener_get_and_ref_next(li);
9686 ecm_db_listener_deref(li);
9687 li = lin;
9688 }
9689}
9690EXPORT_SYMBOL(ecm_db_iface_add_vlan);
9691#endif
9692
ratheesh kannothcfdcb332015-12-24 07:19:18 +05309693#ifdef ECM_INTERFACE_MAP_T_ENABLE
9694/*
9695 * ecm_db_iface_add_map_t()
9696 * Add a iface instance into the database
9697 */
9698void ecm_db_iface_add_map_t(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_map_t *map_t_info,
9699 char *name, int32_t mtu, int32_t interface_identifier,
9700 int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
9701 void *arg)
9702{
9703 ecm_db_iface_hash_t hash_index;
9704 ecm_db_iface_id_hash_t iface_id_hash_index;
9705 struct ecm_db_listener_instance *li;
9706 struct ecm_db_interface_info_map_t *type_info;
9707
9708 spin_lock_bh(&ecm_db_lock);
9709 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9710#ifdef ECM_DB_XREF_ENABLE
9711 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
9712#endif
9713 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9714 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9715 spin_unlock_bh(&ecm_db_lock);
9716
9717 /*
9718 * Record general info
9719 */
9720 ii->type = ECM_DB_IFACE_TYPE_MAP_T;
9721#ifdef ECM_STATE_OUTPUT_ENABLE
9722 ii->state_get = ecm_db_iface_map_t_state_get;
9723#endif
9724 ii->arg = arg;
9725 ii->final = final;
9726 strlcpy(ii->name, name, IFNAMSIZ);
9727 ii->mtu = mtu;
9728 ii->interface_identifier = interface_identifier;
9729 ii->ae_interface_identifier = ae_interface_identifier;
9730
9731 /*
9732 * Type specific info
9733 */
9734 type_info = &ii->type_info.map_t;
9735 memcpy(type_info, map_t_info, sizeof(struct ecm_db_interface_info_map_t));
9736
9737 /*
9738 * Compute hash chain for insertion
9739 */
9740 hash_index = ecm_db_iface_generate_hash_index_map_t(type_info->if_index);
9741 ii->hash_index = hash_index;
9742
9743 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9744 ii->iface_id_hash_index = iface_id_hash_index;
9745 /*
9746 * Add into the global list
9747 */
9748 spin_lock_bh(&ecm_db_lock);
9749 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9750 ii->prev = NULL;
9751 ii->next = ecm_db_interfaces;
9752 if (ecm_db_interfaces) {
9753 ecm_db_interfaces->prev = ii;
9754 }
9755 ecm_db_interfaces = ii;
9756
9757 /*
9758 * Insert into chain
9759 */
9760 ii->hash_next = ecm_db_iface_table[hash_index];
9761 if (ecm_db_iface_table[hash_index]) {
9762 ecm_db_iface_table[hash_index]->hash_prev = ii;
9763 }
9764 ecm_db_iface_table[hash_index] = ii;
9765 ecm_db_iface_table_lengths[hash_index]++;
9766 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9767
9768 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
9769
9770 /*
9771 * Insert into interface identifier chain
9772 */
9773 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9774 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9775 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9776 }
9777 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9778 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9779 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
9780
9781 /*
9782 * Set time of addition
9783 */
9784 ii->time_added = ecm_db_time;
9785 spin_unlock_bh(&ecm_db_lock);
9786
9787 /*
9788 * Throw add event to the listeners
9789 */
9790 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9791 li = ecm_db_listeners_get_and_ref_first();
9792 while (li) {
9793 struct ecm_db_listener_instance *lin;
9794 if (li->iface_added) {
9795 li->iface_added(li->arg, ii);
9796 }
9797
9798 /*
9799 * Get next listener
9800 */
9801 lin = ecm_db_listener_get_and_ref_next(li);
9802 ecm_db_listener_deref(li);
9803 li = lin;
9804 }
9805}
9806EXPORT_SYMBOL(ecm_db_iface_add_map_t);
9807#endif
9808
ratheesh kannotha32fdd12015-09-09 08:02:58 +05309809#ifdef ECM_INTERFACE_PPPOE_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009810/*
9811 * ecm_db_iface_add_pppoe()
9812 * Add a iface instance into the database
9813 */
9814void ecm_db_iface_add_pppoe(struct ecm_db_iface_instance *ii, uint16_t pppoe_session_id, uint8_t *remote_mac,
9815 char *name, int32_t mtu, int32_t interface_identifier,
Murat Sezgin91c5d712015-06-12 15:16:22 -07009816 int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009817 void *arg)
9818{
9819 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009820 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009821 struct ecm_db_listener_instance *li;
9822 struct ecm_db_interface_info_pppoe *type_info;
9823
9824 spin_lock_bh(&ecm_db_lock);
9825 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009826#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009827 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009828#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009829 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9830 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9831 spin_unlock_bh(&ecm_db_lock);
9832
9833 /*
9834 * Record general info
9835 */
9836 ii->type = ECM_DB_IFACE_TYPE_PPPOE;
9837#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009838 ii->state_get = ecm_db_iface_pppoe_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009839#endif
9840 ii->arg = arg;
9841 ii->final = final;
9842 strcpy(ii->name, name);
9843 ii->mtu = mtu;
9844 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009845 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009846
9847 /*
9848 * Type specific info
9849 */
9850 type_info = &ii->type_info.pppoe;
9851 type_info->pppoe_session_id = pppoe_session_id;
9852 memcpy(type_info->remote_mac, remote_mac, ETH_ALEN);
9853
9854 /*
9855 * Compute hash chain for insertion
9856 */
9857 hash_index = ecm_db_iface_generate_hash_index_pppoe(pppoe_session_id);
9858 ii->hash_index = hash_index;
9859
Murat Sezgin91c5d712015-06-12 15:16:22 -07009860 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9861 ii->iface_id_hash_index = iface_id_hash_index;
9862
Gareth Williamsf98d4192015-03-11 16:55:41 +00009863 /*
9864 * Add into the global list
9865 */
9866 spin_lock_bh(&ecm_db_lock);
9867 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9868 ii->prev = NULL;
9869 ii->next = ecm_db_interfaces;
9870 if (ecm_db_interfaces) {
9871 ecm_db_interfaces->prev = ii;
9872 }
9873 ecm_db_interfaces = ii;
9874
9875 /*
9876 * Insert into chain
9877 */
9878 ii->hash_next = ecm_db_iface_table[hash_index];
9879 if (ecm_db_iface_table[hash_index]) {
9880 ecm_db_iface_table[hash_index]->hash_prev = ii;
9881 }
9882 ecm_db_iface_table[hash_index] = ii;
9883 ecm_db_iface_table_lengths[hash_index]++;
9884 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9885
9886 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
9887
9888 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009889 * Insert into interface identifier chain
9890 */
9891 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9892 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9893 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9894 }
9895 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9896 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9897 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
9898
9899 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009900 * Set time of addition
9901 */
9902 ii->time_added = ecm_db_time;
9903 spin_unlock_bh(&ecm_db_lock);
9904
9905 /*
9906 * Throw add event to the listeners
9907 */
9908 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9909 li = ecm_db_listeners_get_and_ref_first();
9910 while (li) {
9911 struct ecm_db_listener_instance *lin;
9912 if (li->iface_added) {
9913 li->iface_added(li->arg, ii);
9914 }
9915
9916 /*
9917 * Get next listener
9918 */
9919 lin = ecm_db_listener_get_and_ref_next(li);
9920 ecm_db_listener_deref(li);
9921 li = lin;
9922 }
9923}
9924EXPORT_SYMBOL(ecm_db_iface_add_pppoe);
9925#endif
9926
ratheesh kannotha32fdd12015-09-09 08:02:58 +05309927#ifdef ECM_INTERFACE_L2TPV2_ENABLE
9928/*
9929 * ecm_db_iface_add_pppol2tpv2()
9930 * Add a iface instance into the database
9931 */
9932void ecm_db_iface_add_pppol2tpv2(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppol2tpv2 *pppol2tpv2_info,
9933 char *name, int32_t mtu, int32_t interface_identifier,
9934 int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
9935 void *arg)
9936{
9937 ecm_db_iface_hash_t hash_index;
9938 ecm_db_iface_id_hash_t iface_id_hash_index;
9939 struct ecm_db_listener_instance *li;
9940 struct ecm_db_interface_info_pppol2tpv2 *type_info;
9941
9942 spin_lock_bh(&ecm_db_lock);
9943 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9944#ifdef ECM_DB_XREF_ENABLE
9945 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
9946#endif
9947 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9948 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9949 spin_unlock_bh(&ecm_db_lock);
9950
9951 /*
9952 * Record general info
9953 */
9954 ii->type = ECM_DB_IFACE_TYPE_PPPOL2TPV2;
9955#ifdef ECM_STATE_OUTPUT_ENABLE
9956 ii->state_get = ecm_db_iface_pppol2tpv2_state_get;
9957#endif
9958 ii->arg = arg;
9959 ii->final = final;
9960 strlcpy(ii->name, name, IFNAMSIZ);
9961 ii->mtu = mtu;
9962 ii->interface_identifier = interface_identifier;
9963 ii->ae_interface_identifier = ae_interface_identifier;
9964
9965 /*
9966 * Type specific info
9967 */
9968 type_info = &ii->type_info.pppol2tpv2;
9969 memcpy(type_info, pppol2tpv2_info, sizeof(struct ecm_db_interface_info_pppol2tpv2));
9970
9971 /*
9972 * Compute hash chain for insertion
9973 */
9974 hash_index = ecm_db_iface_generate_hash_index_pppol2tpv2(type_info->l2tp.tunnel.tunnel_id,
9975 type_info->l2tp.session.session_id);
9976 ii->hash_index = hash_index;
9977
9978 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9979 ii->iface_id_hash_index = iface_id_hash_index;
9980 /*
9981 * Add into the global list
9982 */
9983 spin_lock_bh(&ecm_db_lock);
9984 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9985 ii->prev = NULL;
9986 ii->next = ecm_db_interfaces;
9987 if (ecm_db_interfaces) {
9988 ecm_db_interfaces->prev = ii;
9989 }
9990 ecm_db_interfaces = ii;
9991
9992 /*
9993 * Insert into chain
9994 */
9995 ii->hash_next = ecm_db_iface_table[hash_index];
9996 if (ecm_db_iface_table[hash_index]) {
9997 ecm_db_iface_table[hash_index]->hash_prev = ii;
9998 }
9999 ecm_db_iface_table[hash_index] = ii;
10000 ecm_db_iface_table_lengths[hash_index]++;
10001 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10002
10003 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
10004
10005 /*
10006 * Insert into interface identifier chain
10007 */
10008 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10009 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10010 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10011 }
10012 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10013 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10014 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
10015
10016 /*
10017 * Set time of addition
10018 */
10019 ii->time_added = ecm_db_time;
10020 spin_unlock_bh(&ecm_db_lock);
10021
10022 /*
10023 * Throw add event to the listeners
10024 */
10025 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10026 li = ecm_db_listeners_get_and_ref_first();
10027 while (li) {
10028 struct ecm_db_listener_instance *lin;
10029 if (li->iface_added) {
10030 li->iface_added(li->arg, ii);
10031 }
10032
10033 /*
10034 * Get next listener
10035 */
10036 lin = ecm_db_listener_get_and_ref_next(li);
10037 ecm_db_listener_deref(li);
10038 li = lin;
10039 }
10040}
10041EXPORT_SYMBOL(ecm_db_iface_add_pppol2tpv2);
10042
10043#endif
10044
Shyam Sunder23f2e542015-09-28 14:56:49 +053010045#ifdef ECM_INTERFACE_PPTP_ENABLE
10046/*
10047 * ecm_db_iface_add_pptp()
10048 * Add a iface instance into the database
10049 */
10050void ecm_db_iface_add_pptp(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info,
10051 char *name, int32_t mtu, int32_t interface_identifier,
10052 int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
10053 void *arg)
10054{
10055 ecm_db_iface_hash_t hash_index;
10056 ecm_db_iface_id_hash_t iface_id_hash_index;
10057 struct ecm_db_listener_instance *li;
10058 struct ecm_db_interface_info_pptp *type_info;
10059
10060 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
10061 spin_lock_bh(&ecm_db_lock);
10062#ifdef ECM_DB_XREF_ENABLE
10063 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
10064#endif
10065 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10066 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10067 spin_unlock_bh(&ecm_db_lock);
10068
10069 /*
10070 * Record general info
10071 */
10072 ii->type = ECM_DB_IFACE_TYPE_PPTP;
10073#ifdef ECM_STATE_OUTPUT_ENABLE
10074 ii->state_get = ecm_db_iface_pptp_state_get;
10075#endif
10076 ii->arg = arg;
10077 ii->final = final;
10078 strlcpy(ii->name, name, IFNAMSIZ);
10079 ii->mtu = mtu;
10080 ii->interface_identifier = interface_identifier;
10081 ii->ae_interface_identifier = ae_interface_identifier;
10082
10083 /*
10084 * Type specific info
10085 */
10086 type_info = &ii->type_info.pptp;
10087 memcpy(type_info, pptp_info, sizeof(struct ecm_db_interface_info_pptp));
10088
10089 /*
10090 * Compute hash chain for insertion
10091 */
10092 hash_index = ecm_db_iface_generate_hash_index_pptp(type_info->src_call_id,
10093 type_info->dst_call_id);
10094 ii->hash_index = hash_index;
10095
10096 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10097 ii->iface_id_hash_index = iface_id_hash_index;
10098 /*
10099 * Add into the global list
10100 */
10101 spin_lock_bh(&ecm_db_lock);
10102 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10103 ii->prev = NULL;
10104 ii->next = ecm_db_interfaces;
10105 if (ecm_db_interfaces) {
10106 ecm_db_interfaces->prev = ii;
10107 }
10108 ecm_db_interfaces = ii;
10109
10110 /*
10111 * Insert into chain
10112 */
10113 ii->hash_next = ecm_db_iface_table[hash_index];
10114 if (ecm_db_iface_table[hash_index]) {
10115 ecm_db_iface_table[hash_index]->hash_prev = ii;
10116 }
10117 ecm_db_iface_table[hash_index] = ii;
10118 ecm_db_iface_table_lengths[hash_index]++;
10119 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10120
10121 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
10122
10123 /*
10124 * Insert into interface identifier chain
10125 */
10126 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10127 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10128 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10129 }
10130 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10131 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10132 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
10133
10134 /*
10135 * Set time of addition
10136 */
10137 ii->time_added = ecm_db_time;
10138 spin_unlock_bh(&ecm_db_lock);
10139
10140 /*
10141 * Throw add event to the listeners
10142 */
10143 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10144 li = ecm_db_listeners_get_and_ref_first();
10145 while (li) {
10146 struct ecm_db_listener_instance *lin;
10147 if (li->iface_added) {
10148 li->iface_added(li->arg, ii);
10149 }
10150
10151 /*
10152 * Get next listener
10153 */
10154 lin = ecm_db_listener_get_and_ref_next(li);
10155 ecm_db_listener_deref(li);
10156 li = lin;
10157 }
10158}
10159EXPORT_SYMBOL(ecm_db_iface_add_pptp);
10160#endif
10161
Ben Menchaca84f36632014-02-28 20:57:38 +000010162/*
10163 * ecm_db_iface_add_unknown()
10164 * Add a iface instance into the database
10165 */
10166void ecm_db_iface_add_unknown(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -070010167 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +000010168 ecm_db_iface_final_callback_t final, void *arg)
10169{
10170 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010171 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +000010172 struct ecm_db_listener_instance *li;
10173 struct ecm_db_interface_info_unknown *type_info;
10174
10175 spin_lock_bh(&ecm_db_lock);
10176 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010177#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010178 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010179#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010180 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10181 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10182 spin_unlock_bh(&ecm_db_lock);
10183
10184 /*
10185 * Record general info
10186 */
10187 ii->type = ECM_DB_IFACE_TYPE_UNKNOWN;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010188#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +010010189 ii->state_get = ecm_db_iface_unknown_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010190#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010191 ii->arg = arg;
10192 ii->final = final;
10193 strcpy(ii->name, name);
10194 ii->mtu = mtu;
10195 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010196 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +000010197
10198 /*
10199 * Type specific info
10200 */
10201 type_info = &ii->type_info.unknown;
10202 type_info->os_specific_ident = os_specific_ident;
10203
10204 /*
10205 * Compute hash chain for insertion
10206 */
10207 hash_index = ecm_db_iface_generate_hash_index_unknown(os_specific_ident);
10208 ii->hash_index = hash_index;
10209
Murat Sezgin91c5d712015-06-12 15:16:22 -070010210 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10211 ii->iface_id_hash_index = iface_id_hash_index;
10212
Ben Menchaca84f36632014-02-28 20:57:38 +000010213 /*
10214 * Add into the global list
10215 */
10216 spin_lock_bh(&ecm_db_lock);
10217 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10218 ii->prev = NULL;
10219 ii->next = ecm_db_interfaces;
10220 if (ecm_db_interfaces) {
10221 ecm_db_interfaces->prev = ii;
10222 }
10223 ecm_db_interfaces = ii;
10224
10225 /*
10226 * Insert into chain
10227 */
10228 ii->hash_next = ecm_db_iface_table[hash_index];
10229 if (ecm_db_iface_table[hash_index]) {
10230 ecm_db_iface_table[hash_index]->hash_prev = ii;
10231 }
10232 ecm_db_iface_table[hash_index] = ii;
10233 ecm_db_iface_table_lengths[hash_index]++;
10234 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10235
10236 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
10237
10238 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -070010239 * Insert into interface identifier chain
10240 */
10241 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10242 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10243 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10244 }
10245 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10246 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10247 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
10248
10249 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010250 * Set time of addition
10251 */
10252 ii->time_added = ecm_db_time;
10253 spin_unlock_bh(&ecm_db_lock);
10254
10255 /*
10256 * Throw add event to the listeners
10257 */
10258 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10259 li = ecm_db_listeners_get_and_ref_first();
10260 while (li) {
10261 struct ecm_db_listener_instance *lin;
10262 if (li->iface_added) {
10263 li->iface_added(li->arg, ii);
10264 }
10265
10266 /*
10267 * Get next listener
10268 */
10269 lin = ecm_db_listener_get_and_ref_next(li);
10270 ecm_db_listener_deref(li);
10271 li = lin;
10272 }
10273}
10274EXPORT_SYMBOL(ecm_db_iface_add_unknown);
10275
10276/*
10277 * ecm_db_iface_add_loopback()
10278 * Add a iface instance into the database
10279 */
10280void ecm_db_iface_add_loopback(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -070010281 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +000010282 ecm_db_iface_final_callback_t final, void *arg)
10283{
10284 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010285 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +000010286 struct ecm_db_listener_instance *li;
10287 struct ecm_db_interface_info_loopback *type_info;
10288
10289 spin_lock_bh(&ecm_db_lock);
10290 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010291#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010292 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010293#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010294 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10295 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10296 spin_unlock_bh(&ecm_db_lock);
10297
10298 /*
10299 * Record general info
10300 */
10301 ii->type = ECM_DB_IFACE_TYPE_LOOPBACK;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010302#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +010010303 ii->state_get = ecm_db_iface_loopback_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010304#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010305 ii->arg = arg;
10306 ii->final = final;
10307 strcpy(ii->name, name);
10308 ii->mtu = mtu;
10309 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010310 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +000010311
10312 /*
10313 * Type specific info
10314 */
10315 type_info = &ii->type_info.loopback;
10316 type_info->os_specific_ident = os_specific_ident;
10317
10318 /*
10319 * Compute hash chain for insertion
10320 */
10321 hash_index = ecm_db_iface_generate_hash_index_loopback(os_specific_ident);
10322 ii->hash_index = hash_index;
10323
Murat Sezgin91c5d712015-06-12 15:16:22 -070010324 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10325 ii->iface_id_hash_index = iface_id_hash_index;
10326
Ben Menchaca84f36632014-02-28 20:57:38 +000010327 /*
10328 * Add into the global list
10329 */
10330 spin_lock_bh(&ecm_db_lock);
10331 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10332 ii->prev = NULL;
10333 ii->next = ecm_db_interfaces;
10334 if (ecm_db_interfaces) {
10335 ecm_db_interfaces->prev = ii;
10336 }
10337 ecm_db_interfaces = ii;
10338
10339 /*
10340 * Insert into chain
10341 */
10342 ii->hash_next = ecm_db_iface_table[hash_index];
10343 if (ecm_db_iface_table[hash_index]) {
10344 ecm_db_iface_table[hash_index]->hash_prev = ii;
10345 }
10346 ecm_db_iface_table[hash_index] = ii;
10347 ecm_db_iface_table_lengths[hash_index]++;
10348 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10349
10350 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
10351
10352 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -070010353 * Insert into interface identifier chain
10354 */
10355 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10356 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10357 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10358 }
10359 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10360 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10361 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
10362
10363 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010364 * Set time of addition
10365 */
10366 ii->time_added = ecm_db_time;
10367 spin_unlock_bh(&ecm_db_lock);
10368
10369 /*
10370 * Throw add event to the listeners
10371 */
10372 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10373 li = ecm_db_listeners_get_and_ref_first();
10374 while (li) {
10375 struct ecm_db_listener_instance *lin;
10376 if (li->iface_added) {
10377 li->iface_added(li->arg, ii);
10378 }
10379
10380 /*
10381 * Get next listener
10382 */
10383 lin = ecm_db_listener_get_and_ref_next(li);
10384 ecm_db_listener_deref(li);
10385 li = lin;
10386 }
10387}
10388EXPORT_SYMBOL(ecm_db_iface_add_loopback);
10389
Murat Sezginbde55f92015-03-11 16:44:11 -070010390#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010391/*
Zhu Ken56477be2014-08-05 17:50:28 +080010392 * ecm_db_iface_sit_daddr_is_null()
10393 * The sit addr is null or not
10394 */
10395bool ecm_db_iface_sit_daddr_is_null(struct ecm_db_iface_instance *ii)
10396{
10397 return ii->type_info.sit.daddr[0] == 0;
10398}
10399EXPORT_SYMBOL(ecm_db_iface_sit_daddr_is_null);
10400
10401/*
Ben Menchaca84f36632014-02-28 20:57:38 +000010402 * ecm_db_iface_add_sit()
10403 * Add a iface instance into the database
10404 */
10405void ecm_db_iface_add_sit(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_sit *type_info, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -070010406 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +000010407 ecm_db_iface_final_callback_t final, void *arg)
10408{
10409 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010410 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +000010411 struct ecm_db_listener_instance *li;
10412
10413 spin_lock_bh(&ecm_db_lock);
10414 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010415#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010416 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010417#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010418 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10419 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10420 spin_unlock_bh(&ecm_db_lock);
10421
10422 /*
10423 * Record general info
10424 */
10425 ii->type = ECM_DB_IFACE_TYPE_SIT;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010426#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +010010427 ii->state_get = ecm_db_iface_sit_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010428#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010429 ii->arg = arg;
10430 ii->final = final;
10431 strcpy(ii->name, name);
10432 ii->mtu = mtu;
10433 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010434 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +000010435
10436 /*
10437 * Type specific info to be copied
10438 */
10439 ii->type_info.sit = *type_info;
10440
10441 /*
10442 * Compute hash chain for insertion
10443 */
10444 hash_index = ecm_db_iface_generate_hash_index_sit(type_info->saddr, type_info->daddr);
10445 ii->hash_index = hash_index;
10446
Murat Sezgin91c5d712015-06-12 15:16:22 -070010447 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10448 ii->iface_id_hash_index = iface_id_hash_index;
10449
Ben Menchaca84f36632014-02-28 20:57:38 +000010450 /*
10451 * Add into the global list
10452 */
10453 spin_lock_bh(&ecm_db_lock);
10454 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10455 ii->prev = NULL;
10456 ii->next = ecm_db_interfaces;
10457 if (ecm_db_interfaces) {
10458 ecm_db_interfaces->prev = ii;
10459 }
10460 ecm_db_interfaces = ii;
10461
10462 /*
10463 * Insert into chain
10464 */
10465 ii->hash_next = ecm_db_iface_table[hash_index];
10466 if (ecm_db_iface_table[hash_index]) {
10467 ecm_db_iface_table[hash_index]->hash_prev = ii;
10468 }
10469 ecm_db_iface_table[hash_index] = ii;
10470 ecm_db_iface_table_lengths[hash_index]++;
10471 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10472
10473 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
10474
10475 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -070010476 * Insert into interface identifier chain
10477 */
10478 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10479 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10480 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10481 }
10482 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10483 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10484 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
10485
10486 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010487 * Set time of addition
10488 */
10489 ii->time_added = ecm_db_time;
10490 spin_unlock_bh(&ecm_db_lock);
10491
10492 /*
10493 * Throw add event to the listeners
10494 */
10495 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10496 li = ecm_db_listeners_get_and_ref_first();
10497 while (li) {
10498 struct ecm_db_listener_instance *lin;
10499 if (li->iface_added) {
10500 li->iface_added(li->arg, ii);
10501 }
10502
10503 /*
10504 * Get next listener
10505 */
10506 lin = ecm_db_listener_get_and_ref_next(li);
10507 ecm_db_listener_deref(li);
10508 li = lin;
10509 }
10510}
10511EXPORT_SYMBOL(ecm_db_iface_add_sit);
Murat Sezginbde55f92015-03-11 16:44:11 -070010512#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010513
Murat Sezginc1402562015-03-12 12:32:20 -070010514#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +000010515#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010516/*
10517 * ecm_db_iface_add_tunipip6()
10518 * Add a iface instance into the database
10519 */
10520void ecm_db_iface_add_tunipip6(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_tunipip6 *type_info, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -070010521 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +000010522 ecm_db_iface_final_callback_t final, void *arg)
10523{
10524 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010525 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +000010526 struct ecm_db_listener_instance *li;
10527
10528 spin_lock_bh(&ecm_db_lock);
10529 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010530#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010531 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010532#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010533 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10534 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10535 spin_unlock_bh(&ecm_db_lock);
10536
10537 /*
10538 * Record general info
10539 */
10540 ii->type = ECM_DB_IFACE_TYPE_TUNIPIP6;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010541#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +010010542 ii->state_get = ecm_db_iface_tunipip6_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010543#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010544 ii->arg = arg;
10545 ii->final = final;
10546 strcpy(ii->name, name);
10547 ii->mtu = mtu;
10548 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010549 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +000010550
10551 /*
10552 * Type specific info to be copied
10553 */
10554 ii->type_info.tunipip6 = *type_info;
10555
10556 /*
10557 * Compute hash chain for insertion
10558 */
10559 hash_index = ecm_db_iface_generate_hash_index_tunipip6(type_info->saddr, type_info->daddr);
10560 ii->hash_index = hash_index;
10561
Murat Sezgin91c5d712015-06-12 15:16:22 -070010562 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10563 ii->iface_id_hash_index = iface_id_hash_index;
10564
Ben Menchaca84f36632014-02-28 20:57:38 +000010565 /*
10566 * Add into the global list
10567 */
10568 spin_lock_bh(&ecm_db_lock);
10569 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10570 ii->prev = NULL;
10571 ii->next = ecm_db_interfaces;
10572 if (ecm_db_interfaces) {
10573 ecm_db_interfaces->prev = ii;
10574 }
10575 ecm_db_interfaces = ii;
10576
10577 /*
10578 * Insert into chain
10579 */
10580 ii->hash_next = ecm_db_iface_table[hash_index];
10581 if (ecm_db_iface_table[hash_index]) {
10582 ecm_db_iface_table[hash_index]->hash_prev = ii;
10583 }
10584 ecm_db_iface_table[hash_index] = ii;
10585 ecm_db_iface_table_lengths[hash_index]++;
10586 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10587
10588 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
10589
10590 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -070010591 * Insert into interface identifier chain
10592 */
10593 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10594 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10595 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10596 }
10597 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10598 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10599 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
10600
10601 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010602 * Set time of addition
10603 */
10604 ii->time_added = ecm_db_time;
10605 spin_unlock_bh(&ecm_db_lock);
10606
10607 /*
10608 * Throw add event to the listeners
10609 */
10610 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10611 li = ecm_db_listeners_get_and_ref_first();
10612 while (li) {
10613 struct ecm_db_listener_instance *lin;
10614 if (li->iface_added) {
10615 li->iface_added(li->arg, ii);
10616 }
10617
10618 /*
10619 * Get next listener
10620 */
10621 lin = ecm_db_listener_get_and_ref_next(li);
10622 ecm_db_listener_deref(li);
10623 li = lin;
10624 }
10625}
10626EXPORT_SYMBOL(ecm_db_iface_add_tunipip6);
Murat Sezginc1402562015-03-12 12:32:20 -070010627#endif
Gareth Williams8ac34292015-03-17 14:06:58 +000010628#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010629
Murat Sezgin69a27532015-03-12 14:09:40 -070010630#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010631/*
10632 * ecm_db_iface_add_ipsec_tunnel()
10633 * Add a iface instance into the database
10634 *
10635 * GGG TODO This needs to take ipsec tunnel endpoint information etc. something very appropriate for ipsec tunnels, anyhow.
10636 */
10637void ecm_db_iface_add_ipsec_tunnel(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -070010638 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +000010639 ecm_db_iface_final_callback_t final, void *arg)
10640{
10641 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010642 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +000010643 struct ecm_db_listener_instance *li;
10644 struct ecm_db_interface_info_ipsec_tunnel *type_info;
10645
10646 spin_lock_bh(&ecm_db_lock);
10647 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010648#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010649 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010650#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010651 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10652 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10653 spin_unlock_bh(&ecm_db_lock);
10654
10655 /*
10656 * Record general info
10657 */
Ankit Dhanuka60683c52014-06-09 17:43:38 +053010658 ii->type = ECM_DB_IFACE_TYPE_IPSEC_TUNNEL;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010659#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +010010660 ii->state_get = ecm_db_iface_ipsec_tunnel_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010661#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010662 ii->arg = arg;
10663 ii->final = final;
10664 strcpy(ii->name, name);
10665 ii->mtu = mtu;
10666 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010667 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +000010668
10669 /*
10670 * Type specific info
10671 */
10672 type_info = &ii->type_info.ipsec_tunnel;
10673 type_info->os_specific_ident = os_specific_ident;
10674
10675 /*
10676 * Compute hash chain for insertion
10677 */
10678 hash_index = ecm_db_iface_generate_hash_index_ipsec_tunnel(os_specific_ident);
10679 ii->hash_index = hash_index;
10680
Murat Sezgin91c5d712015-06-12 15:16:22 -070010681 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10682 ii->iface_id_hash_index = iface_id_hash_index;
10683
Ben Menchaca84f36632014-02-28 20:57:38 +000010684 /*
10685 * Add into the global list
10686 */
10687 spin_lock_bh(&ecm_db_lock);
10688 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10689 ii->prev = NULL;
10690 ii->next = ecm_db_interfaces;
10691 if (ecm_db_interfaces) {
10692 ecm_db_interfaces->prev = ii;
10693 }
10694 ecm_db_interfaces = ii;
10695
10696 /*
10697 * Insert into chain
10698 */
10699 ii->hash_next = ecm_db_iface_table[hash_index];
10700 if (ecm_db_iface_table[hash_index]) {
10701 ecm_db_iface_table[hash_index]->hash_prev = ii;
10702 }
10703 ecm_db_iface_table[hash_index] = ii;
10704 ecm_db_iface_table_lengths[hash_index]++;
10705 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10706
10707 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
10708
10709 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -070010710 * Insert into interface identifier chain
10711 */
10712 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10713 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10714 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10715 }
10716 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10717 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10718 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
10719
10720 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010721 * Set time of addition
10722 */
10723 ii->time_added = ecm_db_time;
10724 spin_unlock_bh(&ecm_db_lock);
10725
10726 /*
10727 * Throw add event to the listeners
10728 */
10729 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10730 li = ecm_db_listeners_get_and_ref_first();
10731 while (li) {
10732 struct ecm_db_listener_instance *lin;
10733 if (li->iface_added) {
10734 li->iface_added(li->arg, ii);
10735 }
10736
10737 /*
10738 * Get next listener
10739 */
10740 lin = ecm_db_listener_get_and_ref_next(li);
10741 ecm_db_listener_deref(li);
10742 li = lin;
10743 }
10744}
10745EXPORT_SYMBOL(ecm_db_iface_add_ipsec_tunnel);
Murat Sezgin69a27532015-03-12 14:09:40 -070010746#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010747
10748/*
10749 * ecm_db_listener_add()
10750 * Add a listener instance into the database.
10751 */
10752void ecm_db_listener_add(struct ecm_db_listener_instance *li,
10753 ecm_db_iface_listener_added_callback_t iface_added,
10754 ecm_db_iface_listener_removed_callback_t iface_removed,
10755 ecm_db_node_listener_added_callback_t node_added,
10756 ecm_db_node_listener_removed_callback_t node_removed,
10757 ecm_db_host_listener_added_callback_t host_added,
10758 ecm_db_host_listener_removed_callback_t host_removed,
10759 ecm_db_mapping_listener_added_callback_t mapping_added,
10760 ecm_db_mapping_listener_removed_callback_t mapping_removed,
10761 ecm_db_connection_listener_added_callback_t connection_added,
10762 ecm_db_connection_listener_removed_callback_t connection_removed,
10763 ecm_db_listener_final_callback_t final,
10764 void *arg)
10765{
10766 spin_lock_bh(&ecm_db_lock);
10767 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed\n", li);
10768 DEBUG_ASSERT(!(li->flags & ECM_DB_LISTENER_FLAGS_INSERTED), "%p: inserted\n", li);
10769 spin_unlock_bh(&ecm_db_lock);
10770
10771 li->arg = arg;
10772 li->final = final;
10773 li->iface_added = iface_added;
10774 li->iface_removed = iface_removed;
10775 li->node_added = node_added;
10776 li->node_removed = node_removed;
10777 li->host_added = host_added;
10778 li->host_removed = host_removed;
10779 li->mapping_added = mapping_added;
10780 li->mapping_removed = mapping_removed;
10781 li->connection_added = connection_added;
10782 li->connection_removed = connection_removed;
10783
10784 /*
10785 * Add instance into listener list
10786 */
10787 spin_lock_bh(&ecm_db_lock);
10788 li->flags |= ECM_DB_LISTENER_FLAGS_INSERTED;
10789 li->next = ecm_db_listeners;
10790 ecm_db_listeners = li;
10791 spin_unlock_bh(&ecm_db_lock);
10792}
10793EXPORT_SYMBOL(ecm_db_listener_add);
10794
10795/*
10796 * ecm_db_connection_alloc()
10797 * Allocate a connection instance
10798 */
10799struct ecm_db_connection_instance *ecm_db_connection_alloc(void)
10800{
10801 struct ecm_db_connection_instance *ci;
Shyam Sunder3b049ff2015-05-18 20:44:30 +053010802 int __attribute__((unused)) i;
Murat Sezgin66d19912016-09-20 13:55:25 -070010803 unsigned int conn_count;
10804
10805 /*
10806 * If we have exceeded the conntrack connection limit then do not allocate new instance.
10807 */
10808 conn_count = (unsigned int)ecm_db_connection_count_get();
10809 if (conn_count >= nf_conntrack_max) {
10810 DEBUG_WARN("ECM Connection count limit reached: db: %u, ct: %u\n", conn_count, nf_conntrack_max);
10811 return NULL;
10812 }
Ben Menchaca84f36632014-02-28 20:57:38 +000010813
10814 /*
10815 * Allocate the connection
10816 */
10817 ci = (struct ecm_db_connection_instance *)kzalloc(sizeof(struct ecm_db_connection_instance), GFP_ATOMIC | __GFP_NOWARN);
10818 if (!ci) {
10819 DEBUG_WARN("Connection alloc failed\n");
10820 return NULL;
10821 }
10822
10823 /*
10824 * Initialise the defunct timer entry
10825 */
10826 ecm_db_timer_group_entry_init(&ci->defunct_timer, ecm_db_connection_defunct_callback, ci);
10827
10828 /*
10829 * Refs is 1 for the creator of the connection
10830 */
10831 ci->refs = 1;
10832 DEBUG_SET_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC);
10833
10834 /*
Nicolas Costaf46c33b2014-05-15 10:02:00 -050010835 * Initialise the interfaces from/to lists.
10836 * Interfaces are added from end of array.
10837 */
10838 ci->from_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10839 ci->to_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10840 ci->from_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10841 ci->to_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10842
Shyam Sunder3b049ff2015-05-18 20:44:30 +053010843#ifdef ECM_MULTICAST_ENABLE
10844 for (i = 0; i < ECM_DB_MULTICAST_IF_MAX; ++i) {
10845 ci->to_mcast_interface_first[i] = ECM_DB_IFACE_HEIRARCHY_MAX;
10846 }
10847#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -050010848 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010849 * If the master thread is terminating then we cannot create new instances
10850 */
10851 spin_lock_bh(&ecm_db_lock);
10852 if (ecm_db_terminate_pending) {
10853 spin_unlock_bh(&ecm_db_lock);
10854 DEBUG_WARN("Thread terminating\n");
10855 kfree(ci);
10856 return NULL;
10857 }
10858
10859 /*
10860 * Assign runtime unique serial
10861 */
10862 ci->serial = ecm_db_connection_serial++;
10863
Ben Menchaca84f36632014-02-28 20:57:38 +000010864 ecm_db_connection_count++;
10865 DEBUG_ASSERT(ecm_db_connection_count > 0, "%p: connection count wrap\n", ci);
10866 spin_unlock_bh(&ecm_db_lock);
10867
10868 DEBUG_TRACE("Connection created %p\n", ci);
10869 return ci;
10870}
10871EXPORT_SYMBOL(ecm_db_connection_alloc);
10872
10873/*
10874 * ecm_db_mapping_alloc()
10875 * Allocate a mapping instance
10876 */
10877struct ecm_db_mapping_instance *ecm_db_mapping_alloc(void)
10878{
10879 struct ecm_db_mapping_instance *mi;
10880
10881 mi = (struct ecm_db_mapping_instance *)kzalloc(sizeof(struct ecm_db_mapping_instance), GFP_ATOMIC | __GFP_NOWARN);
10882 if (!mi) {
10883 DEBUG_WARN("Alloc failed\n");
10884 return NULL;
10885 }
10886
10887 mi->refs = 1;
10888 DEBUG_SET_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC);
10889
10890 /*
10891 * Alloc operation must be atomic to ensure thread and module can be held
10892 */
10893 spin_lock_bh(&ecm_db_lock);
10894
10895 /*
10896 * If the event processing thread is terminating then we cannot create new instances
10897 */
10898 if (ecm_db_terminate_pending) {
10899 spin_unlock_bh(&ecm_db_lock);
10900 DEBUG_WARN("Thread terminating\n");
10901 kfree(mi);
10902 return NULL;
10903 }
10904
Ben Menchaca84f36632014-02-28 20:57:38 +000010905 ecm_db_mapping_count++;
10906 spin_unlock_bh(&ecm_db_lock);
10907
10908 DEBUG_TRACE("Mapping created %p\n", mi);
10909 return mi;
10910}
10911EXPORT_SYMBOL(ecm_db_mapping_alloc);
10912
Ben Menchaca84f36632014-02-28 20:57:38 +000010913/*
10914 * ecm_db_host_alloc()
10915 * Allocate a host instance
10916 */
10917struct ecm_db_host_instance *ecm_db_host_alloc(void)
10918{
10919 struct ecm_db_host_instance *hi;
10920 hi = (struct ecm_db_host_instance *)kzalloc(sizeof(struct ecm_db_host_instance), GFP_ATOMIC | __GFP_NOWARN);
10921 if (!hi) {
10922 DEBUG_WARN("Alloc failed\n");
10923 return NULL;
10924 }
10925
10926 hi->refs = 1;
10927 DEBUG_SET_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC);
10928
10929 /*
10930 * Alloc operation must be atomic to ensure thread and module can be held
10931 */
10932 spin_lock_bh(&ecm_db_lock);
10933
10934 /*
10935 * If the event processing thread is terminating then we cannot create new instances
10936 */
10937 if (ecm_db_terminate_pending) {
10938 spin_unlock_bh(&ecm_db_lock);
10939 DEBUG_WARN("Thread terminating\n");
10940 kfree(hi);
10941 return NULL;
10942 }
10943
Ben Menchaca84f36632014-02-28 20:57:38 +000010944 ecm_db_host_count++;
10945 spin_unlock_bh(&ecm_db_lock);
10946
10947 DEBUG_TRACE("Host created %p\n", hi);
10948 return hi;
10949}
10950EXPORT_SYMBOL(ecm_db_host_alloc);
10951
10952/*
10953 * ecm_db_node_alloc()
10954 * Allocate a node instance
10955 */
10956struct ecm_db_node_instance *ecm_db_node_alloc(void)
10957{
10958 struct ecm_db_node_instance *ni;
10959
10960 ni = (struct ecm_db_node_instance *)kzalloc(sizeof(struct ecm_db_node_instance), GFP_ATOMIC | __GFP_NOWARN);
10961 if (!ni) {
10962 DEBUG_WARN("Alloc failed\n");
10963 return NULL;
10964 }
10965
10966 ni->refs = 1;
10967 DEBUG_SET_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC);
10968
10969 /*
10970 * Alloc operation must be atomic to ensure thread and module can be held
10971 */
10972 spin_lock_bh(&ecm_db_lock);
10973
10974 /*
10975 * If the event processing thread is terminating then we cannot create new instances
10976 */
10977 if (ecm_db_terminate_pending) {
10978 spin_unlock_bh(&ecm_db_lock);
10979 DEBUG_WARN("Thread terminating\n");
10980 kfree(ni);
10981 return NULL;
10982 }
10983
Ben Menchaca84f36632014-02-28 20:57:38 +000010984 ecm_db_node_count++;
10985 spin_unlock_bh(&ecm_db_lock);
10986
10987 DEBUG_TRACE("Node created %p\n", ni);
10988 return ni;
10989}
10990EXPORT_SYMBOL(ecm_db_node_alloc);
10991
10992/*
10993 * ecm_db_iface_alloc()
10994 * Allocate a iface instance
10995 */
10996struct ecm_db_iface_instance *ecm_db_iface_alloc(void)
10997{
10998 struct ecm_db_iface_instance *ii;
10999
11000 ii = (struct ecm_db_iface_instance *)kzalloc(sizeof(struct ecm_db_iface_instance), GFP_ATOMIC | __GFP_NOWARN);
11001 if (!ii) {
11002 DEBUG_WARN("Alloc failed\n");
11003 return NULL;
11004 }
11005
11006 ii->refs = 1;
11007 DEBUG_SET_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC);
11008
11009 /*
11010 * Alloc operation must be atomic to ensure thread and module can be held
11011 */
11012 spin_lock_bh(&ecm_db_lock);
11013
11014 /*
11015 * If the event processing thread is terminating then we cannot create new instances
11016 */
11017 if (ecm_db_terminate_pending) {
11018 spin_unlock_bh(&ecm_db_lock);
11019 DEBUG_WARN("Thread terminating\n");
11020 kfree(ii);
11021 return NULL;
11022 }
11023
Ben Menchaca84f36632014-02-28 20:57:38 +000011024 ecm_db_iface_count++;
11025 spin_unlock_bh(&ecm_db_lock);
11026
11027 DEBUG_TRACE("iface created %p\n", ii);
11028 return ii;
11029}
11030EXPORT_SYMBOL(ecm_db_iface_alloc);
11031
11032/*
11033 * ecm_db_listener_alloc()
11034 * Allocate a listener instance
11035 */
11036struct ecm_db_listener_instance *ecm_db_listener_alloc(void)
11037{
11038 struct ecm_db_listener_instance *li;
11039
11040 li = (struct ecm_db_listener_instance *)kzalloc(sizeof(struct ecm_db_listener_instance), GFP_ATOMIC | __GFP_NOWARN);
11041 if (!li) {
11042 DEBUG_WARN("Alloc failed\n");
11043 return NULL;
11044 }
11045
11046 li->refs = 1;
11047 DEBUG_SET_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC);
11048
11049 /*
11050 * Alloc operation must be atomic to ensure thread and module can be held
11051 */
11052 spin_lock_bh(&ecm_db_lock);
11053
11054 /*
11055 * If the event processing thread is terminating then we cannot create new instances
11056 */
11057 if (ecm_db_terminate_pending) {
11058 spin_unlock_bh(&ecm_db_lock);
11059 DEBUG_WARN("Thread terminating\n");
11060 kfree(li);
11061 return NULL;
11062 }
11063
Ben Menchaca84f36632014-02-28 20:57:38 +000011064 ecm_db_listeners_count++;
11065 DEBUG_ASSERT(ecm_db_listeners_count > 0, "%p: listener count wrap\n", li);
Nicolas Costaf46c33b2014-05-15 10:02:00 -050011066 spin_unlock_bh(&ecm_db_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +000011067
11068 DEBUG_TRACE("Listener created %p\n", li);
Ben Menchaca84f36632014-02-28 20:57:38 +000011069 return li;
11070}
11071EXPORT_SYMBOL(ecm_db_listener_alloc);
11072
Shyam Sunder1f037262015-05-18 20:04:13 +053011073#ifdef ECM_MULTICAST_ENABLE
11074/*
11075 * _ecm_db_multicast_tuple_instance_ref()
11076 * Increment tuple reference count by one
11077 */
11078static void _ecm_db_multicast_tuple_instance_ref(struct ecm_db_multicast_tuple_instance *ti)
11079{
11080 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
11081 ti->refs++;
11082 DEBUG_TRACE("%p: ti ref %d\n", ti, ti->refs);
11083 DEBUG_ASSERT(ti->refs > 0, "%p: ref wrap\n", ti)
11084}
11085
11086/*
11087 * ecm_db_multicast_alloc_connection()
11088 * Allocate memory for the connection structure.
11089 */
11090struct ecm_db_multicast_tuple_instance *ecm_db_multicast_tuple_instance_alloc(ip_addr_t origin, ip_addr_t group, uint16_t src_port, uint16_t dst_port)
11091{
11092 struct ecm_db_multicast_tuple_instance *ti;
11093 ti = (struct ecm_db_multicast_tuple_instance *)kzalloc(sizeof(struct ecm_db_multicast_tuple_instance), GFP_ATOMIC | __GFP_NOWARN);
11094 if (!ti) {
11095 DEBUG_WARN("ti: Alloc failed\n");
11096 return NULL;
11097 }
11098 ti->src_port = src_port;
11099 ti->dst_port = dst_port;
11100 ECM_IP_ADDR_COPY(ti->src_ip, origin);
11101 ECM_IP_ADDR_COPY(ti->grp_ip, group);
11102 ti->proto = IPPROTO_UDP;
11103 ti->hash_index = ecm_db_multicast_generate_hash_index(group);
11104 ti->flags = 0;
11105 ti->refs = 1;
11106 ti->next = NULL;
11107 ti->prev = NULL;
11108 DEBUG_SET_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC);
11109
11110 return ti;
11111}
11112EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_alloc);
11113
11114/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053011115 * ecm_db_multicast_connection_find_and_ref()
Shyam Sunder1f037262015-05-18 20:04:13 +053011116 * Called by MFC event update to fetch connection from the table
Shyam Sunder3af86a52015-08-28 18:04:10 +053011117 * This function takes a ref count for both tuple_instance and 'ci'
11118 * Call ecm_db_multicast_connection_deref function for deref both
11119 * 'ti' and 'ci'
Shyam Sunder1f037262015-05-18 20:04:13 +053011120 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053011121struct ecm_db_multicast_tuple_instance *ecm_db_multicast_connection_find_and_ref(ip_addr_t origin, ip_addr_t group)
Shyam Sunder1f037262015-05-18 20:04:13 +053011122{
11123 ecm_db_multicast_tuple_instance_hash_t hash_index;
11124 struct ecm_db_multicast_tuple_instance *ti;
11125
11126 /*
11127 * Compute the hash chain index
11128 */
11129 hash_index = ecm_db_multicast_generate_hash_index(group);
11130
11131 spin_lock_bh(&ecm_db_lock);
11132 ti = ecm_db_multicast_tuple_instance_table[hash_index];
11133
11134 /*
11135 * Traverse through the list and find the ti
11136 */
11137 while (ti) {
11138 if (!(ECM_IP_ADDR_MATCH(ti->src_ip, origin) && ECM_IP_ADDR_MATCH(ti->grp_ip, group))) {
11139 ti = ti->next;
11140 continue;
11141 }
11142
11143 _ecm_db_multicast_tuple_instance_ref(ti);
Shyam Sunder3af86a52015-08-28 18:04:10 +053011144 _ecm_db_connection_ref(ti->ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053011145 spin_unlock_bh(&ecm_db_lock);
11146 DEBUG_TRACE("multicast tuple instance found %p\n", ti);
11147 return ti;
11148 }
11149
11150 spin_unlock_bh(&ecm_db_lock);
11151 DEBUG_TRACE("multicast tuple instance not found\n");
11152 return NULL;
11153}
Shyam Sunder3af86a52015-08-28 18:04:10 +053011154EXPORT_SYMBOL(ecm_db_multicast_connection_find_and_ref);
Shyam Sunder1f037262015-05-18 20:04:13 +053011155
11156/*
11157 * ecm_db_multicast_tuple_instance_deref()
11158 * Deref the reference count or
Shyam Sunder3af86a52015-08-28 18:04:10 +053011159 * Free the tuple_instance struct, when the multicast connection dies
Shyam Sunder1f037262015-05-18 20:04:13 +053011160 */
11161int ecm_db_multicast_tuple_instance_deref(struct ecm_db_multicast_tuple_instance *ti)
11162{
Shyam Sunder317ca912016-01-22 16:51:28 +053011163 int refs;
Shyam Sunder1f037262015-05-18 20:04:13 +053011164 spin_lock_bh(&ecm_db_lock);
Shyam Sunder317ca912016-01-22 16:51:28 +053011165 refs = _ecm_db_multicast_tuple_instance_deref(ti);
Shyam Sunder1f037262015-05-18 20:04:13 +053011166 spin_unlock_bh(&ecm_db_lock);
Shyam Sunder317ca912016-01-22 16:51:28 +053011167 return refs;
Shyam Sunder1f037262015-05-18 20:04:13 +053011168}
11169EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_deref);
11170
11171/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053011172 * ecm_db_multicast_connection_deref()
11173 * Deref both 'ti' and 'ci'
11174 * call this function after ecm_db_multicast_connection_find_and_ref()
11175 */
11176void ecm_db_multicast_connection_deref(struct ecm_db_multicast_tuple_instance *ti)
11177{
11178 struct ecm_db_connection_instance *ci;
11179 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
11180
11181 ci = ti->ci;
11182 ecm_db_multicast_tuple_instance_deref(ti);
11183 ecm_db_connection_deref(ci);
11184
11185}
11186EXPORT_SYMBOL(ecm_db_multicast_connection_deref);
11187
11188/*
Shyam Sunder1f037262015-05-18 20:04:13 +053011189 * ecm_db_multicast_tuple_instance_add()
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011190 * Add the tuple instance into the hash table. Also, attach the tuple instance
11191 * with connection instance.
11192 *
Shyam Sunder1f037262015-05-18 20:04:13 +053011193 * Note: This function takes a reference count and caller has to also call
11194 * ecm_db_multicast_tuple_instance_deref() after this function.
11195 */
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011196void ecm_db_multicast_tuple_instance_add(struct ecm_db_multicast_tuple_instance *ti, struct ecm_db_connection_instance *ci)
Shyam Sunder1f037262015-05-18 20:04:13 +053011197{
11198 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
11199
11200 spin_lock_bh(&ecm_db_lock);
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011201 DEBUG_ASSERT(!(ti->flags & ECM_DB_MULTICAST_TUPLE_INSTANCE_FLAGS_INSERTED), "%p: inserted\n", ti);
11202
11203 /*
11204 * Attach the multicast tuple instance with the connection instance
11205 */
11206 ci->ti = ti;
Shyam Sunder3af86a52015-08-28 18:04:10 +053011207 ti->ci = ci;
Shyam Sunder1f037262015-05-18 20:04:13 +053011208
11209 /*
11210 * Take a local reference to ti
11211 */
11212 _ecm_db_multicast_tuple_instance_ref(ti);
11213 ti->next = ecm_db_multicast_tuple_instance_table[ti->hash_index];
11214 if (ecm_db_multicast_tuple_instance_table[ti->hash_index]) {
11215 ecm_db_multicast_tuple_instance_table[ti->hash_index]->prev = ti;
11216 }
11217
11218 ecm_db_multicast_tuple_instance_table[ti->hash_index] = ti;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011219
11220 ti->flags |= ECM_DB_MULTICAST_TUPLE_INSTANCE_FLAGS_INSERTED;
Shyam Sunder1f037262015-05-18 20:04:13 +053011221 spin_unlock_bh(&ecm_db_lock);
11222
11223}
11224EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_add);
11225
11226/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053011227 * ecm_db_multicast_connection_get_and_ref_first()
Shyam Sunder1f037262015-05-18 20:04:13 +053011228 * Return the first tuple instance from the table when given a group
Shyam Sunder3af86a52015-08-28 18:04:10 +053011229 * Also take a ref count for 'ci', once done call ecm_db_multicast_connection_deref()
11230 * to deref both 'ti' and 'ci'
Shyam Sunder1f037262015-05-18 20:04:13 +053011231 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053011232struct ecm_db_multicast_tuple_instance *ecm_db_multicast_connection_get_and_ref_first(ip_addr_t group)
Shyam Sunder1f037262015-05-18 20:04:13 +053011233{
11234 ecm_db_multicast_tuple_instance_hash_t hash_index;
11235 struct ecm_db_multicast_tuple_instance *ti;
11236
11237 hash_index = ecm_db_multicast_generate_hash_index(group);
11238
11239 spin_lock_bh(&ecm_db_lock);
11240 ti = ecm_db_multicast_tuple_instance_table[hash_index];
11241 if (ti) {
11242 _ecm_db_multicast_tuple_instance_ref(ti);
Shyam Sunder3af86a52015-08-28 18:04:10 +053011243 _ecm_db_connection_ref(ti->ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053011244 }
11245 spin_unlock_bh(&ecm_db_lock);
11246
11247 return ti;
11248}
Shyam Sunder3af86a52015-08-28 18:04:10 +053011249EXPORT_SYMBOL(ecm_db_multicast_connection_get_and_ref_first);
Shyam Sunder1f037262015-05-18 20:04:13 +053011250
11251/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053011252 * ecm_db_multicast_connection_get_and_ref_next()
11253 * Return the next tuple instance node and
11254 * take a ref count for 'ci', once done call ecm_db_multicast_connection_deref()
11255 * to deref both 'ti' and 'ci'
Shyam Sunder1f037262015-05-18 20:04:13 +053011256 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053011257struct ecm_db_multicast_tuple_instance *ecm_db_multicast_connection_get_and_ref_next(struct ecm_db_multicast_tuple_instance *ti)
Shyam Sunder1f037262015-05-18 20:04:13 +053011258{
11259 struct ecm_db_multicast_tuple_instance *tin;
11260 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
11261 spin_lock_bh(&ecm_db_lock);
11262 tin = ti->next;
11263 if (tin) {
11264 _ecm_db_multicast_tuple_instance_ref(tin);
Shyam Sunder3af86a52015-08-28 18:04:10 +053011265 _ecm_db_connection_ref(tin->ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053011266 }
11267 spin_unlock_bh(&ecm_db_lock);
11268 return tin;
11269}
Shyam Sunder3af86a52015-08-28 18:04:10 +053011270EXPORT_SYMBOL(ecm_db_multicast_connection_get_and_ref_next);
Shyam Sunder1f037262015-05-18 20:04:13 +053011271
11272/*
11273 * ecm_db_multicast_tuple_instance_source_ip_get()
11274 * This function return the source IP for a connection object
11275 */
11276void ecm_db_multicast_tuple_instance_source_ip_get(struct ecm_db_multicast_tuple_instance *ti, ip_addr_t origin)
11277{
11278 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
11279 ECM_IP_ADDR_COPY(origin, ti->src_ip);
11280}
11281EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_source_ip_get);
11282
11283/*
Shyam Sunderf34c25b2015-06-11 21:14:50 +053011284 * ecm_db_multicast_tuple_instance_group_ip_get()
11285 * This function return the group IP for a connection object
11286 */
11287void ecm_db_multicast_tuple_instance_group_ip_get(struct ecm_db_multicast_tuple_instance *ti, ip_addr_t group)
11288{
11289 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
11290 ECM_IP_ADDR_COPY(group, ti->grp_ip);
11291}
11292EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_group_ip_get);
11293
11294/*
Shyam Sunder1f037262015-05-18 20:04:13 +053011295 * ecm_db_multicast_tuple_instance_flags_get()
11296 * Return flags related to Multicast connection
11297 */
11298uint32_t ecm_db_multicast_tuple_instance_flags_get(struct ecm_db_multicast_tuple_instance *ti)
11299{
11300 uint32_t flags;
11301
11302 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed\n", ti);
11303 spin_lock_bh(&ecm_db_lock);
11304 flags = ti->flags;
11305 spin_unlock_bh(&ecm_db_lock);
11306 return flags;
11307}
11308EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_flags_get);
11309
11310/*
11311 * ecm_db_multicast_tuple_instance_flags_set()
11312 * Set the multicast connection flags
11313 */
11314void ecm_db_multicast_tuple_instance_flags_set(struct ecm_db_multicast_tuple_instance *ti, uint32_t flags)
11315{
11316 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed\n", ti);
11317
11318 spin_lock_bh(&ecm_db_lock);
11319 ti->flags |= flags;
11320 spin_unlock_bh(&ecm_db_lock);
11321}
11322EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_flags_set);
11323
11324/*
11325 * ecm_db_multicast_tuple_instance_flags_clear()
11326 * Clear the multicast connection flags
11327 */
11328void ecm_db_multicast_tuple_instance_flags_clear(struct ecm_db_multicast_tuple_instance *ti, uint32_t flags)
11329{
11330 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed\n", ti);
11331
11332 spin_lock_bh(&ecm_db_lock);
11333 ti->flags &= ~flags;
11334 spin_unlock_bh(&ecm_db_lock);
11335}
11336EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_flags_clear);
11337
11338/*
11339 * ecm_db_multicast_connection_to_interfaces_get_and_ref_all()
11340 * Return the list of multicast destination interface heirarchies to which this connection is established.
11341 * The function returns the heirarchies using the 'interface' pointer passed to it. It also returns the first
11342 * index in the interface heirarchy for each of the heirarchies using the 'ifaces_first' pointer.
11343 *
11344 * NOTE: This function allocates the memory for the destination interface heirachy. This memory is expected to be
11345 * freed only by making a call to ecm_db_multicast_connection_interfaces_deref_all().
11346 *
11347 * The size of the buffer allocated for the heirarchies and pointed to by 'interfaces' is as large as
11348 * sizeof(struct ecm_db_iface_instance *) * ECM_DB_MULTICAST_IF_MAX * ECM_DB_IFACE_HEIRARCHY_MAX.
11349 * Returns the number of interface heirarchies in the list as a return value.
11350 *
11351 * Each interface is referenced on return, be sure to release them using ecm_db_multicast_connection_interfaces_deref_all().
11352 */
11353int32_t ecm_db_multicast_connection_to_interfaces_get_and_ref_all(struct ecm_db_connection_instance *ci,
11354 struct ecm_db_iface_instance **interfaces, int32_t **ifaces_first)
11355{
11356 struct ecm_db_iface_instance *heirarchy_base;
11357 struct ecm_db_iface_instance *heirarchy_temp;
11358 struct ecm_db_iface_instance *ii_single;
11359 struct ecm_db_iface_instance **ifaces;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011360 struct ecm_db_iface_instance *ii_db;
11361 struct ecm_db_iface_instance *ii_db_single;
11362 struct ecm_db_iface_instance **ifaces_db;
Shyam Sunder1f037262015-05-18 20:04:13 +053011363 int32_t *ii_first_base;
11364 int32_t *ii_first;
11365 int32_t heirarchy_index;
11366 int32_t ii_index;
11367 int32_t if_count = 0;
11368
11369 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
11370
11371 heirarchy_base = (struct ecm_db_iface_instance *)kzalloc(ECM_DB_TO_MCAST_INTERFACES_SIZE, GFP_ATOMIC | __GFP_NOWARN);
11372 if (!heirarchy_base) {
11373 DEBUG_WARN("%p: No memory for interface hierarchies \n", ci);
11374 return if_count;
11375 }
11376
11377 ii_first_base = (int32_t *)kzalloc(sizeof(int32_t *) * ECM_DB_MULTICAST_IF_MAX, GFP_ATOMIC | __GFP_NOWARN);
11378 if (!ii_first_base) {
11379 DEBUG_WARN("%p: No memory for first interface \n", ci);
11380 kfree(heirarchy_base);
11381 return if_count;
11382 }
11383
11384 spin_lock_bh(&ecm_db_lock);
11385 if (!ci->to_mcast_interfaces_set) {
11386 spin_unlock_bh(&ecm_db_lock);
11387 kfree(ii_first_base);
11388 kfree(heirarchy_base);
11389 return if_count;
11390 }
11391
11392 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
11393
11394 heirarchy_temp = ecm_db_multicast_if_heirarchy_get(heirarchy_base, heirarchy_index);
11395
11396 if (ci->to_mcast_interface_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
11397 if_count++;
11398 }
11399
11400 for (ii_index = ci->to_mcast_interface_first[heirarchy_index]; ii_index < ECM_DB_IFACE_HEIRARCHY_MAX; ++ii_index) {
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011401 ii_db = ecm_db_multicast_if_heirarchy_get(ci->to_mcast_interfaces, heirarchy_index);
11402 ii_db_single = ecm_db_multicast_if_instance_get_at_index(ii_db, ii_index);
11403 ifaces_db = (struct ecm_db_iface_instance **)ii_db_single;
Shyam Sunder1f037262015-05-18 20:04:13 +053011404
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011405 /*
11406 * Take a reference count
11407 */
11408 _ecm_db_iface_ref(*ifaces_db);
11409
Shyam Sunder1f037262015-05-18 20:04:13 +053011410 ii_single = ecm_db_multicast_if_instance_get_at_index(heirarchy_temp, ii_index);
11411 ifaces = (struct ecm_db_iface_instance **)ii_single;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011412 *ifaces = *ifaces_db;
Shyam Sunder1f037262015-05-18 20:04:13 +053011413 }
11414
11415 ii_first = ecm_db_multicast_if_first_get_at_index(ii_first_base, heirarchy_index);
11416 *ii_first = ci->to_mcast_interface_first[heirarchy_index];
11417 }
11418
11419 *interfaces = heirarchy_base;
11420 *ifaces_first = ii_first_base;
11421
11422 spin_unlock_bh(&ecm_db_lock);
11423 return if_count;
11424}
11425EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_get_and_ref_all);
11426
11427/*
11428 * ecm_db_multicast_connection_to_interfaces_set_check()
11429 * Returns true if the multicast destination interfaces list has been set.
11430 */
11431bool ecm_db_multicast_connection_to_interfaces_set_check(struct ecm_db_connection_instance *ci)
11432{
11433 bool set;
11434
11435 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
11436 spin_lock_bh(&ecm_db_lock);
11437 set = ci->to_mcast_interfaces_set;
11438 spin_unlock_bh(&ecm_db_lock);
11439 return set;
11440}
11441EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_set_check);
11442
11443/*
11444 * ecm_db_multicast_connection_to_interfaces_set_clear()
11445 * Clear the to_mcast_interfaces_set flag if the multicast destination interfaces list has been freed.
11446 */
11447static void _ecm_db_multicast_connection_to_interfaces_set_clear(struct ecm_db_connection_instance *ci)
11448{
11449 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053011450 ci->to_mcast_interfaces_set = false;
Shyam Sunder1f037262015-05-18 20:04:13 +053011451}
11452
11453/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053011454 * ecm_db_multicast_connection_get_from_tuple()
Shyam Sunder1f037262015-05-18 20:04:13 +053011455 * Return the connection instance
11456 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053011457struct ecm_db_connection_instance *ecm_db_multicast_connection_get_from_tuple(struct ecm_db_multicast_tuple_instance *ti)
Shyam Sunder1f037262015-05-18 20:04:13 +053011458{
Shyam Sunder3af86a52015-08-28 18:04:10 +053011459 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
11460 DEBUG_ASSERT(ti->ci, "%p: Bad multicast connection instance \n", ti);
11461
11462 return ti->ci;
Shyam Sunder1f037262015-05-18 20:04:13 +053011463}
Shyam Sunder3af86a52015-08-28 18:04:10 +053011464EXPORT_SYMBOL(ecm_db_multicast_connection_get_from_tuple);
Shyam Sunder1f037262015-05-18 20:04:13 +053011465
11466/*
11467 * ecm_db_multicast_connection_to_interfaces_deref_all()
11468 * Deref all destination multicast interface heirarchies at once
11469 */
11470void ecm_db_multicast_connection_to_interfaces_deref_all(struct ecm_db_iface_instance *interfaces, int32_t *ifaces_first)
11471{
11472 struct ecm_db_iface_instance *ifaces_single;
11473 struct ecm_db_iface_instance *ii_temp[ECM_DB_IFACE_HEIRARCHY_MAX];
11474 int32_t *to_first;
11475 int heirarchy_index;
Shyam Sunder1f037262015-05-18 20:04:13 +053011476 DEBUG_ASSERT(interfaces, "Bad memory, multicast interfaces list has been already freed\n");
11477 DEBUG_ASSERT(ifaces_first, "Bad memory, multicast interfaces first has been already freed\n");
11478
11479 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
11480 to_first = ecm_db_multicast_if_first_get_at_index(ifaces_first, heirarchy_index);
11481 if (*to_first < ECM_DB_IFACE_HEIRARCHY_MAX) {
11482 ifaces_single = ecm_db_multicast_if_heirarchy_get(interfaces, heirarchy_index);
11483 ecm_db_multicast_copy_if_heirarchy(ii_temp, ifaces_single);
11484 ecm_db_connection_interfaces_deref(ii_temp, *to_first);
11485 }
11486 }
11487
11488 /*
11489 * Free the temporary memory allocated by ecm_db_multicast_connection_to_interfaces_get_and_ref_all()
11490 */
11491 kfree(interfaces);
11492 kfree(ifaces_first);
11493
11494}
11495EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_deref_all);
11496
11497/*
11498 * _ecm_db_multicast_connection_to_interface_first_is_valid()
11499 * Check if destnation interfaces first list uphold a valid interface
11500 * first or all entries have discarded.
11501 */
11502static bool _ecm_db_multicast_connection_to_interface_first_is_valid(int32_t ifaces_first[])
11503{
11504 int heirarchy_index;
11505
11506 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
11507 if (ifaces_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
11508 return true;
11509 }
11510 }
11511
11512 return false;
11513}
11514
11515/*
11516 * ecm_db_multicast_connection_to_interfaces_clear_at_index()
11517 * Dereference and clear a interface heirarchy at 'index' position
11518 */
11519void ecm_db_multicast_connection_to_interfaces_clear_at_index(struct ecm_db_connection_instance *ci, uint32_t index)
11520{
11521 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011522 struct ecm_db_iface_instance *ifaces_db_single;
Shyam Sunder1f037262015-05-18 20:04:13 +053011523 int32_t discard_first;
Shyam Sunder1f037262015-05-18 20:04:13 +053011524
11525 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
11526
11527 /*
11528 * Invalid Index Value
11529 */
11530 DEBUG_ASSERT((index < ECM_DB_MULTICAST_IF_MAX), "%p: Invalid index for multicast interface heirarchies list %u\n", ci, index);
11531
11532 spin_lock_bh(&ecm_db_lock);
11533 if (ci->to_mcast_interface_first[index] == ECM_DB_IFACE_HEIRARCHY_MAX) {
11534 spin_unlock_bh(&ecm_db_lock);
11535 return;
11536 }
11537
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011538 ifaces_db_single = ecm_db_multicast_if_heirarchy_get(ci->to_mcast_interfaces, index);
11539 ecm_db_multicast_copy_if_heirarchy(discard, ifaces_db_single);
Shyam Sunder1f037262015-05-18 20:04:13 +053011540
11541 discard_first = ci->to_mcast_interface_first[index];
11542 ci->to_mcast_interface_first[index] = ECM_DB_IFACE_HEIRARCHY_MAX;
11543
11544 /*
11545 * If this is the only valid interface hierarchy left in the list of destination
11546 * interface hierarchies then clear the ci->to_mcast_interfaces_set flag here before
11547 * deleting this.
11548 */
11549 if (!_ecm_db_multicast_connection_to_interface_first_is_valid(ci->to_mcast_interface_first)) {
11550 ci->to_mcast_interfaces_set = false;
11551 }
11552
11553 spin_unlock_bh(&ecm_db_lock);
11554
11555 ecm_db_connection_interfaces_deref(discard, discard_first);
11556}
11557EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_clear_at_index);
11558
11559/*
11560 * ecm_db_multicast_connection_to_interfaces_clear()
11561 * Deref and clear all destination multicast interface heirarchies
11562 */
11563void ecm_db_multicast_connection_to_interfaces_clear(struct ecm_db_connection_instance *ci)
11564{
11565 int heirarchy_index;
11566 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
11567
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011568 spin_lock_bh(&ecm_db_lock);
11569 if (!ci->to_mcast_interfaces) {
11570 spin_unlock_bh(&ecm_db_lock);
11571 return;
11572 }
11573
Shyam Sunder1f037262015-05-18 20:04:13 +053011574 _ecm_db_multicast_connection_to_interfaces_set_clear(ci);
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011575 spin_unlock_bh(&ecm_db_lock);
11576
Shyam Sunder1f037262015-05-18 20:04:13 +053011577 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
11578 ecm_db_multicast_connection_to_interfaces_clear_at_index(ci, heirarchy_index);
11579 }
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011580
11581 kfree(ci->to_mcast_interfaces);
11582 ci->to_mcast_interfaces = NULL;
Shyam Sunder1f037262015-05-18 20:04:13 +053011583}
11584EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_clear);
11585#endif
11586
Ben Menchaca84f36632014-02-28 20:57:38 +000011587/*
11588 * ecm_db_time_get()
11589 * Return database time, in seconds since the database started.
11590 */
11591uint32_t ecm_db_time_get(void)
11592{
11593 uint32_t time_now;
11594 spin_lock_bh(&ecm_db_lock);
11595 time_now = ecm_db_time;
11596 spin_unlock_bh(&ecm_db_lock);
11597 return time_now;
11598}
11599EXPORT_SYMBOL(ecm_db_time_get);
11600
11601/*
Ben Menchaca84f36632014-02-28 20:57:38 +000011602 * ecm_db_get_defunct_all()
11603 * Reading this file returns the accumulated total of all objects
11604 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011605static ssize_t ecm_db_get_defunct_all(struct file *file,
11606 char __user *user_buf,
11607 size_t sz, loff_t *ppos)
Ben Menchaca84f36632014-02-28 20:57:38 +000011608{
Murat Sezgin908ecb32015-05-10 20:54:36 -070011609 int ret;
Ben Menchaca84f36632014-02-28 20:57:38 +000011610 int num;
Murat Sezgin908ecb32015-05-10 20:54:36 -070011611 char *buf;
11612
11613 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
11614 if (!buf) {
11615 return -ENOMEM;
11616 }
Ben Menchaca84f36632014-02-28 20:57:38 +000011617
11618 /*
11619 * Operate under our locks
11620 */
11621 spin_lock_bh(&ecm_db_lock);
11622 num = ecm_db_connection_count + ecm_db_mapping_count + ecm_db_host_count
11623 + ecm_db_node_count + ecm_db_iface_count;
11624 spin_unlock_bh(&ecm_db_lock);
11625
Murat Sezgin908ecb32015-05-10 20:54:36 -070011626 ret = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
11627 if (ret < 0) {
11628 kfree(buf);
11629 return ret;
11630 }
11631
11632 ret = simple_read_from_buffer(user_buf, sz, ppos, buf, ret);
11633 kfree(buf);
11634 return ret;
Ben Menchaca84f36632014-02-28 20:57:38 +000011635}
11636
11637/*
11638 * ecm_db_set_defunct_all()
11639 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011640static ssize_t ecm_db_set_defunct_all(struct file *file,
11641 const char __user *user_buf,
11642 size_t sz, loff_t *ppos)
Ben Menchaca84f36632014-02-28 20:57:38 +000011643{
11644 ecm_db_connection_defunct_all();
Murat Sezgin908ecb32015-05-10 20:54:36 -070011645 return sz;
Ben Menchaca84f36632014-02-28 20:57:38 +000011646}
11647
11648/*
Murat Sezgin908ecb32015-05-10 20:54:36 -070011649 * File operations for defunct_all.
11650 */
11651static struct file_operations ecm_db_defunct_all_fops = {
11652 .read = ecm_db_get_defunct_all,
11653 .write = ecm_db_set_defunct_all,
11654};
11655
11656/*
Ben Menchaca84f36632014-02-28 20:57:38 +000011657 * ecm_db_get_connection_counts_simple()
11658 * Return total of connections for each simple protocol (tcp, udp, other). Primarily for use by the luci-bwc service.
11659 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011660static ssize_t ecm_db_get_connection_counts_simple(struct file *file,
11661 char __user *user_buf,
11662 size_t sz, loff_t *ppos)
Ben Menchaca84f36632014-02-28 20:57:38 +000011663{
11664 int tcp_count;
11665 int udp_count;
11666 int other_count;
11667 int total_count;
Murat Sezgin908ecb32015-05-10 20:54:36 -070011668 int ret;
11669 char *buf;
11670
11671 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
11672 if (!buf) {
11673 return -ENOMEM;
11674 }
Ben Menchaca84f36632014-02-28 20:57:38 +000011675
11676 /*
11677 * Get snapshot of the protocol counts
11678 */
11679 spin_lock_bh(&ecm_db_lock);
11680 tcp_count = ecm_db_connection_count_by_protocol[IPPROTO_TCP];
11681 udp_count = ecm_db_connection_count_by_protocol[IPPROTO_UDP];
11682 total_count = ecm_db_connection_count;
11683 other_count = total_count - (tcp_count + udp_count);
11684 spin_unlock_bh(&ecm_db_lock);
11685
Murat Sezgin908ecb32015-05-10 20:54:36 -070011686 ret = snprintf(buf, (ssize_t)PAGE_SIZE, "tcp %d udp %d other %d total %d\n", tcp_count, udp_count, other_count, total_count);
11687 if (ret < 0) {
11688 kfree(buf);
11689 return -EFAULT;
11690 }
11691
11692 ret = simple_read_from_buffer(user_buf, sz, ppos, buf, ret);
11693 kfree(buf);
11694 return ret;
Ben Menchaca84f36632014-02-28 20:57:38 +000011695}
11696
Ben Menchaca84f36632014-02-28 20:57:38 +000011697/*
Murat Sezgin908ecb32015-05-10 20:54:36 -070011698 * File operations for simple connection counts.
Ben Menchaca84f36632014-02-28 20:57:38 +000011699 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011700static struct file_operations ecm_db_connection_count_simple_fops = {
11701 .read = ecm_db_get_connection_counts_simple,
Ben Menchaca84f36632014-02-28 20:57:38 +000011702};
11703
11704/*
Ben Menchaca84f36632014-02-28 20:57:38 +000011705 * ecm_db_timer_callback()
11706 * Manage expiration of connections
11707 * NOTE: This is softirq context
11708 */
11709static void ecm_db_timer_callback(unsigned long data)
11710{
11711 uint32_t timer;
11712
11713 /*
11714 * Increment timer.
11715 */
11716 spin_lock_bh(&ecm_db_lock);
11717 timer = ++ecm_db_time;
11718 spin_unlock_bh(&ecm_db_lock);
11719 DEBUG_TRACE("Garbage timer tick %d\n", timer);
11720
11721 /*
11722 * Check timer groups
11723 */
11724 ecm_db_timer_groups_check(timer);
11725
11726 /*
11727 * Set the timer for the next second
11728 */
11729 ecm_db_timer.expires += HZ;
11730 if (ecm_db_timer.expires <= jiffies) {
11731 DEBUG_WARN("losing time %lu, jiffies = %lu\n", ecm_db_timer.expires, jiffies);
11732 ecm_db_timer.expires = jiffies + HZ;
11733 }
11734 add_timer(&ecm_db_timer);
11735}
Gareth Williamsd5618a82015-05-20 11:13:32 +010011736#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000011737/*
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011738 * ecm_db_node_from_connections_get_and_ref_first()
11739 * Obtain a ref to the first connection instance of "from list" of node, if any
11740 */
11741static inline struct ecm_db_connection_instance *ecm_db_node_from_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11742{
11743 struct ecm_db_connection_instance *ci;
11744 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11745 spin_lock_bh(&ecm_db_lock);
11746 ci = node->from_connections;
11747 if (ci) {
11748 _ecm_db_connection_ref(ci);
11749 }
11750 spin_unlock_bh(&ecm_db_lock);
11751 return ci;
11752}
11753
11754/*
11755 * ecm_db_node_from_connection_get_and_ref_next()
11756 * Return the next connection in the "from list" of given a connection
11757 */
11758static inline struct ecm_db_connection_instance *ecm_db_node_from_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11759{
11760 struct ecm_db_connection_instance *cin;
11761 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11762 spin_lock_bh(&ecm_db_lock);
11763 cin = ci->node_from_next;
11764 if (cin) {
11765 _ecm_db_connection_ref(cin);
11766 }
11767 spin_unlock_bh(&ecm_db_lock);
11768 return cin;
11769}
11770
11771/*
11772 * ecm_db_node_to_connections_get_and_ref_first()
11773 * Obtain a ref to the first connection instance of a "to list" of node, if any
11774 */
11775static inline struct ecm_db_connection_instance *ecm_db_node_to_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11776{
11777 struct ecm_db_connection_instance *ci;
11778 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11779 spin_lock_bh(&ecm_db_lock);
11780 ci = node->to_connections;
11781 if (ci) {
11782 _ecm_db_connection_ref(ci);
11783 }
11784 spin_unlock_bh(&ecm_db_lock);
11785 return ci;
11786}
11787
11788/*
11789 * ecm_db_node_to_connection_get_and_ref_next()
11790 * Return the next connection in the "to list" of given a connection
11791 */
11792static inline struct ecm_db_connection_instance *ecm_db_node_to_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11793{
11794 struct ecm_db_connection_instance *cin;
11795 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11796 spin_lock_bh(&ecm_db_lock);
11797 cin = ci->node_to_next;
11798 if (cin) {
11799 _ecm_db_connection_ref(cin);
11800 }
11801 spin_unlock_bh(&ecm_db_lock);
11802 return cin;
11803}
11804
11805/*
11806 * ecm_db_node_from_nat_connections_get_and_ref_first()
11807 * Obtain a ref to the first connection instance of a "from_nat list" of node, if any
11808 */
11809static inline struct ecm_db_connection_instance *ecm_db_node_from_nat_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11810{
11811 struct ecm_db_connection_instance *ci;
11812 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11813 spin_lock_bh(&ecm_db_lock);
11814 ci = node->from_nat_connections;
11815 if (ci) {
11816 _ecm_db_connection_ref(ci);
11817 }
11818 spin_unlock_bh(&ecm_db_lock);
11819 return ci;
11820}
11821
11822/*
11823 * ecm_db_node_from_nat_connection_get_and_ref_next()
11824 * Return the next connection in the "from nat list" of given a connection
11825 */
11826static inline struct ecm_db_connection_instance *ecm_db_node_from_nat_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11827{
11828 struct ecm_db_connection_instance *cin;
11829 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11830 spin_lock_bh(&ecm_db_lock);
11831 cin = ci->node_from_nat_next;
11832 if (cin) {
11833 _ecm_db_connection_ref(cin);
11834 }
11835 spin_unlock_bh(&ecm_db_lock);
11836 return cin;
11837}
11838
11839/*
11840 * ecm_db_node_to_nat_connections_get_and_ref_first()
11841 * Obtain a ref to the first connection instance of a "to_nat list" of node, if any
11842 */
11843static inline struct ecm_db_connection_instance *ecm_db_node_to_nat_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11844{
11845 struct ecm_db_connection_instance *ci;
11846 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11847 spin_lock_bh(&ecm_db_lock);
11848 ci = node->to_nat_connections;
11849 if (ci) {
11850 _ecm_db_connection_ref(ci);
11851 }
11852 spin_unlock_bh(&ecm_db_lock);
11853 return ci;
11854}
11855
11856/*
11857 * ecm_db_node_to_nat_connection_get_and_ref_next()
11858 * Return the next connection in the "to nat list" of given a connection
11859 */
11860static inline struct ecm_db_connection_instance *ecm_db_node_to_nat_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11861{
11862 struct ecm_db_connection_instance *cin;
11863 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11864 spin_lock_bh(&ecm_db_lock);
11865 cin = ci->node_to_nat_next;
11866 if (cin) {
11867 _ecm_db_connection_ref(cin);
11868 }
11869 spin_unlock_bh(&ecm_db_lock);
11870 return cin;
11871}
11872
11873/*
11874 * ecm_db_connection_decelerate_and_defunct()
11875 * decelerate and defunct a connection
11876 */
11877static inline void ecm_db_connection_decelerate_and_defunct(struct ecm_db_connection_instance *ci)
11878{
11879 struct ecm_front_end_connection_instance *feci = NULL;
11880
11881 if(unlikely(!ci)) {
11882 DEBUG_WARN("%p: ecm db connection instance pointer is null\n", ci);
11883 return;
11884 }
11885
11886 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11887
11888 feci = ecm_db_connection_front_end_get_and_ref(ci);
11889
11890 feci->decelerate(feci);
11891 feci->deref(feci);
11892 ecm_db_connection_make_defunct(ci);
11893}
11894
11895/*
Murat Sezgine34b0172015-11-05 21:58:14 -080011896 * ecm_db_should_keep_connection()
11897 * check if any classifier believes this connection should
11898 * be kept
11899 */
11900static bool ecm_db_should_keep_connection(
11901 struct ecm_db_connection_instance *ci, uint8_t *mac)
11902{
11903 bool should_keep_connection = false;
11904 int assignment_count;
11905 int aci_index;
11906 struct ecm_classifier_instance *assignments[ECM_CLASSIFIER_TYPES];
11907
11908 assignment_count =
11909 ecm_db_connection_classifier_assignments_get_and_ref(ci, assignments);
11910 for (aci_index = 0; aci_index < assignment_count; ++aci_index) {
11911 struct ecm_classifier_instance *aci;
11912 aci = assignments[aci_index];
11913 if (aci->should_keep_connection &&
11914 aci->should_keep_connection(aci, mac)) {
11915 should_keep_connection = true;
11916 break;
11917 }
11918 }
11919 ecm_db_connection_assignments_release(assignment_count, assignments);
11920
11921 return should_keep_connection;
11922}
11923
11924/*
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011925 * ecm_db_traverse_node_from_connection_list_and_decelerate()
11926 * traverse from_list of a node and calls ecm_db_connection_decelerate_and_defunct()
11927 * for each entry
11928 */
Murat Sezgine34b0172015-11-05 21:58:14 -080011929void ecm_db_traverse_node_from_connection_list_and_decelerate(
11930 struct ecm_db_node_instance *node)
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011931{
11932 struct ecm_db_connection_instance *ci = NULL;
11933
11934 /*
11935 * Iterate all from connections
11936 */
11937 ci = ecm_db_node_from_connections_get_and_ref_first(node);
11938 while (ci) {
11939 struct ecm_db_connection_instance *cin;
11940
Murat Sezgine34b0172015-11-05 21:58:14 -080011941 if (!ecm_db_should_keep_connection(ci, node->address)) {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080011942 DEBUG_TRACE("%p: defunct %d\n", ci, ci->serial);
Murat Sezgine34b0172015-11-05 21:58:14 -080011943 ecm_db_connection_decelerate_and_defunct(ci);
11944 } else {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080011945 DEBUG_TRACE("%p: keeping connection %d\n", ci, ci->serial);
Murat Sezgine34b0172015-11-05 21:58:14 -080011946 }
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011947
11948 cin = ecm_db_node_from_connection_get_and_ref_next(ci);
11949 ecm_db_connection_deref(ci);
11950 ci = cin;
11951 }
11952 DEBUG_INFO("%p: Defuncting node's from connection list complete\n", node);
11953}
11954
11955/*
11956 * ecm_db_traverse_node_to_connection_list_and_decelerate()
11957 * traverse to_list of a node and calls ecm_db_connection_decelerate_and_defunct()
11958 * for each entry
11959 */
Murat Sezgine34b0172015-11-05 21:58:14 -080011960void ecm_db_traverse_node_to_connection_list_and_decelerate(
11961 struct ecm_db_node_instance *node)
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011962{
11963 struct ecm_db_connection_instance *ci = NULL;
11964
11965 /*
11966 * Iterate all to connections
11967 */
11968 ci = ecm_db_node_to_connections_get_and_ref_first(node);
11969 while (ci) {
11970 struct ecm_db_connection_instance *cin;
11971
Murat Sezgine34b0172015-11-05 21:58:14 -080011972 if (!ecm_db_should_keep_connection(ci, node->address)) {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080011973 DEBUG_TRACE("%p: defunct %d\n", ci, ci->serial);
Murat Sezgine34b0172015-11-05 21:58:14 -080011974 ecm_db_connection_decelerate_and_defunct(ci);
11975 } else {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080011976 DEBUG_TRACE("%p: keeping connection %d\n", ci, ci->serial);
Murat Sezgine34b0172015-11-05 21:58:14 -080011977 }
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011978
11979 cin = ecm_db_node_to_connection_get_and_ref_next(ci);
11980 ecm_db_connection_deref(ci);
11981 ci = cin;
11982 }
11983 DEBUG_INFO("%p: Defuncting node's to connection list complete\n", node);
11984}
11985
11986/*
11987 * ecm_db_traverse_node_from_nat_connection_list_and_decelerate()
11988 * traverse from_nat_list of a node and calls ecm_db_connection_decelerate_and_defunct()
11989 * for each entry
11990 */
Murat Sezgine34b0172015-11-05 21:58:14 -080011991void ecm_db_traverse_node_from_nat_connection_list_and_decelerate(
11992 struct ecm_db_node_instance *node)
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011993{
11994 struct ecm_db_connection_instance *ci = NULL;
11995
11996 /*
11997 * Iterate all from nat connections
11998 */
11999 ci = ecm_db_node_from_nat_connections_get_and_ref_first(node);
12000 while (ci) {
12001 struct ecm_db_connection_instance *cin;
12002
Murat Sezgine34b0172015-11-05 21:58:14 -080012003 if (!ecm_db_should_keep_connection(ci, node->address)) {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080012004 DEBUG_TRACE("%p: defunct %d\n", ci, ci->serial);
Murat Sezgine34b0172015-11-05 21:58:14 -080012005 ecm_db_connection_decelerate_and_defunct(ci);
12006 } else {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080012007 DEBUG_TRACE("%p: keeping connection %d\n", ci, ci->serial);
Murat Sezgine34b0172015-11-05 21:58:14 -080012008 }
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012009
12010 cin = ecm_db_node_from_nat_connection_get_and_ref_next(ci);
12011 ecm_db_connection_deref(ci);
12012 ci = cin;
12013 }
12014 DEBUG_INFO("%p: Defuncting node's from nat connection list complete\n", node);
12015}
12016
12017/*
12018 * ecm_db_traverse_node_to_nat_connection_list_and_decelerate()
12019 * traverse to_nat_list of a node and calls ecm_db_connection_decelerate_and_defunct()
12020 * for each entry
12021 */
Murat Sezgine34b0172015-11-05 21:58:14 -080012022void ecm_db_traverse_node_to_nat_connection_list_and_decelerate(
12023 struct ecm_db_node_instance *node)
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012024{
12025 struct ecm_db_connection_instance *ci = NULL;
12026
12027 /*
12028 * Iterate all to nat connections
12029 */
12030 ci = ecm_db_node_to_nat_connections_get_and_ref_first(node);
12031 while (ci) {
12032 struct ecm_db_connection_instance *cin;
12033
Murat Sezgine34b0172015-11-05 21:58:14 -080012034 if (!ecm_db_should_keep_connection(ci, node->address)) {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080012035 DEBUG_TRACE("%p: defunct %d\n", ci, ci->serial);
Murat Sezgine34b0172015-11-05 21:58:14 -080012036 ecm_db_connection_decelerate_and_defunct(ci);
12037 } else {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080012038 DEBUG_TRACE("%p: keeping connection %d\n", ci, ci->serial);
Murat Sezgine34b0172015-11-05 21:58:14 -080012039 }
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012040
12041 cin = ecm_db_node_to_nat_connection_get_and_ref_next(ci);
12042 ecm_db_connection_deref(ci);
12043 ci = cin;
12044 }
12045 DEBUG_INFO("%p: Defuncting to node's nat connection list complete\n", node);
12046}
Murat Sezgin8c345822015-05-27 15:35:38 -070012047#endif
Murat Sezgin1134fb82015-10-06 14:03:49 -070012048
12049/*
12050 * ecm_db_connection_ipv6_from_ct_get_and_ref()
12051 * Return, if any, a connection given a ct
12052 */
12053struct ecm_db_connection_instance *ecm_db_connection_ipv6_from_ct_get_and_ref(struct nf_conn *ct)
12054{
12055 struct nf_conntrack_tuple orig_tuple;
12056 struct nf_conntrack_tuple reply_tuple;
12057 ip_addr_t host1_addr;
12058 ip_addr_t host2_addr;
12059 int host1_port;
12060 int host2_port;
12061 int protocol;
12062
12063 /*
12064 * Look up the associated connection for this conntrack connection
12065 */
12066 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
12067 reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
12068 ECM_NIN6_ADDR_TO_IP_ADDR(host1_addr, orig_tuple.src.u3.in6);
12069 ECM_NIN6_ADDR_TO_IP_ADDR(host2_addr, reply_tuple.src.u3.in6);
12070 protocol = orig_tuple.dst.protonum;
12071 if (protocol == IPPROTO_TCP) {
12072 host1_port = ntohs(orig_tuple.src.u.tcp.port);
12073 host2_port = ntohs(reply_tuple.src.u.tcp.port);
12074 } else if (protocol == IPPROTO_UDP) {
12075 host1_port = ntohs(orig_tuple.src.u.udp.port);
12076 host2_port = ntohs(reply_tuple.src.u.udp.port);
12077 } else if ((protocol == IPPROTO_IPIP)) {
12078 host1_port = 0;
12079 host2_port = 0;
12080 } else {
12081 host1_port = -protocol;
12082 host2_port = -protocol;
12083 }
12084
12085 DEBUG_TRACE("%p: lookup src: " ECM_IP_ADDR_OCTAL_FMT ":%d, "
12086 "dest: " ECM_IP_ADDR_OCTAL_FMT ":%d, "
12087 "protocol %d\n",
12088 ct,
12089 ECM_IP_ADDR_TO_OCTAL(host1_addr),
12090 host1_port,
12091 ECM_IP_ADDR_TO_OCTAL(host2_addr),
12092 host2_port,
12093 protocol);
12094
12095 return ecm_db_connection_find_and_ref(host1_addr,
12096 host2_addr,
12097 protocol,
12098 host1_port,
12099 host2_port);
12100}
12101
12102/*
12103 * ecm_db_connection_ipv4_from_ct_get_and_ref()
12104 * Return, if any, a connection given a ct
12105 */
12106struct ecm_db_connection_instance *ecm_db_connection_ipv4_from_ct_get_and_ref(struct nf_conn *ct)
12107{
12108 struct nf_conntrack_tuple orig_tuple;
12109 struct nf_conntrack_tuple reply_tuple;
12110 ip_addr_t host1_addr;
12111 ip_addr_t host2_addr;
12112 int host1_port;
12113 int host2_port;
12114 int protocol;
12115
12116 /*
12117 * Look up the associated connection for this conntrack connection
12118 */
12119 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
12120 reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
12121 ECM_NIN4_ADDR_TO_IP_ADDR(host1_addr, orig_tuple.src.u3.ip);
12122 ECM_NIN4_ADDR_TO_IP_ADDR(host2_addr, reply_tuple.src.u3.ip);
12123 protocol = orig_tuple.dst.protonum;
12124 if (protocol == IPPROTO_TCP) {
12125 host1_port = ntohs(orig_tuple.src.u.tcp.port);
12126 host2_port = ntohs(reply_tuple.src.u.tcp.port);
12127 } else if (protocol == IPPROTO_UDP) {
12128 host1_port = ntohs(orig_tuple.src.u.udp.port);
12129 host2_port = ntohs(reply_tuple.src.u.udp.port);
12130 } else if ((protocol == IPPROTO_IPV6) || (protocol == IPPROTO_ESP)) {
12131 host1_port = 0;
12132 host2_port = 0;
12133 } else {
12134 host1_port = -protocol;
12135 host2_port = -protocol;
12136 }
12137
12138 DEBUG_TRACE("%p: lookup src: " ECM_IP_ADDR_DOT_FMT ":%d, "
12139 "dest: " ECM_IP_ADDR_DOT_FMT ":%d, "
12140 "protocol %d\n",
12141 ct,
12142 ECM_IP_ADDR_TO_DOT(host1_addr),
12143 host1_port,
12144 ECM_IP_ADDR_TO_DOT(host2_addr),
12145 host2_port,
12146 protocol);
12147
12148 return ecm_db_connection_find_and_ref(host1_addr,
12149 host2_addr,
12150 protocol,
12151 host1_port,
12152 host2_port);
12153}
12154 /*
12155 * ecm_db_iproute_connection_cmp()
12156 * This is the "iterate" function passed to the nf_ct_iterate_cleanup()
12157 * function.
12158 */
12159static int ecm_db_iproute_connection_cmp(struct nf_conn *i, void *data)
12160{
12161 struct ecm_db_connection_instance *ci;
12162
12163 /*
12164 * Go through the conntarck entries and if they are found in ECM db,
12165 * decelerate and defunct the connection.
12166 */
12167 ci = ecm_db_connection_ipv4_from_ct_get_and_ref(i);
12168 if (ci) {
Murat Sezgin1be32822016-01-12 17:21:36 -080012169 ecm_db_connection_make_defunct(ci);
Murat Sezgin1134fb82015-10-06 14:03:49 -070012170 ecm_db_connection_deref(ci);
12171 }
12172
12173 return 0;
12174}
12175
12176/*
12177 * ecm_db_iproute_table_update_event()
12178 * This is a call back for "routing table update event for IPv4"
12179 */
12180static int ecm_db_iproute_table_update_event(struct notifier_block *nb,
12181 unsigned long event,
12182 void *ptr)
12183{
12184 DEBUG_TRACE("iproute table update event\n");
12185
12186#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 11, 0))
12187 nf_ct_iterate_cleanup(&init_net, ecm_db_iproute_connection_cmp, 0);
12188#else
12189 nf_ct_iterate_cleanup(&init_net, ecm_db_iproute_connection_cmp, 0, 0, 0);
12190#endif
12191 return NOTIFY_DONE;
12192}
12193
12194static struct notifier_block ecm_db_iproute_table_update_nb = {
12195 .notifier_call = ecm_db_iproute_table_update_event,
12196};
12197
12198 /*
12199 * ecm_db_ip6route_connection_cmp()
12200 * This is the "iterate" function passed to the nf_ct_iterate_cleanup()
12201 * function.
12202 */
12203static int ecm_db_ip6route_connection_cmp(struct nf_conn *i, void *data)
12204{
12205 struct ecm_db_connection_instance *ci;
12206
12207 /*
12208 * Go through the conntarck entries and if they are found in ECM db,
12209 * decelerate and defunct the connection.
12210 */
12211 ci = ecm_db_connection_ipv6_from_ct_get_and_ref(i);
12212 if (ci) {
Murat Sezgin1be32822016-01-12 17:21:36 -080012213 ecm_db_connection_make_defunct(ci);
Murat Sezgin1134fb82015-10-06 14:03:49 -070012214 ecm_db_connection_deref(ci);
12215 }
12216
12217 return 0;
12218}
12219
12220/*
12221 * ecm_db_ip6route_table_update_event()
12222 * This is a call back for "routing table update event for IPv6"
12223 */
12224static int ecm_db_ip6route_table_update_event(struct notifier_block *nb,
12225 unsigned long event,
12226 void *ptr)
12227{
12228 DEBUG_TRACE("ip6route table update event\n");
12229
12230#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 11, 0))
12231 nf_ct_iterate_cleanup(&init_net, ecm_db_ip6route_connection_cmp, 0);
12232#else
12233 nf_ct_iterate_cleanup(&init_net, ecm_db_ip6route_connection_cmp, 0, 0, 0);
12234#endif
12235 return NOTIFY_DONE;
12236}
12237
12238static struct notifier_block ecm_db_ip6route_table_update_nb = {
12239 .notifier_call = ecm_db_ip6route_table_update_event,
12240};
12241
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012242/*
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012243 * ecm_db_init()
Ben Menchaca84f36632014-02-28 20:57:38 +000012244 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070012245int ecm_db_init(struct dentry *dentry)
Ben Menchaca84f36632014-02-28 20:57:38 +000012246{
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012247 DEBUG_INFO("ECM Module init\n");
Ben Menchaca84f36632014-02-28 20:57:38 +000012248
Murat Sezgin908ecb32015-05-10 20:54:36 -070012249 ecm_db_dentry = debugfs_create_dir("ecm_db", dentry);
12250 if (!ecm_db_dentry) {
12251 DEBUG_ERROR("Failed to create ecm db directory in debugfs\n");
12252 return -1;
12253 }
Ben Menchaca84f36632014-02-28 20:57:38 +000012254
12255 /*
Gareth Williams54d15d92015-04-24 19:28:27 +010012256 * Get a random seed for jhash()
12257 */
12258 get_random_bytes(&ecm_db_jhash_rnd, sizeof(ecm_db_jhash_rnd));
Murat Sezgin18ed5d32016-04-13 15:43:17 -070012259 printk(KERN_INFO "ECM database jhash random seed: 0x%x\n", ecm_db_jhash_rnd);
Gareth Williams54d15d92015-04-24 19:28:27 +010012260
Murat Sezgin908ecb32015-05-10 20:54:36 -070012261 if (!debugfs_create_u32("connection_count", S_IRUGO, ecm_db_dentry,
12262 (u32 *)&ecm_db_connection_count)) {
12263 DEBUG_ERROR("Failed to create ecm db connection count file in debugfs\n");
12264 goto init_cleanup;
Ben Menchaca84f36632014-02-28 20:57:38 +000012265 }
12266
Murat Sezgin908ecb32015-05-10 20:54:36 -070012267 if (!debugfs_create_u32("host_count", S_IRUGO, ecm_db_dentry,
12268 (u32 *)&ecm_db_host_count)) {
12269 DEBUG_ERROR("Failed to create ecm db host count file in debugfs\n");
12270 goto init_cleanup;
Ben Menchaca84f36632014-02-28 20:57:38 +000012271 }
12272
Murat Sezgin908ecb32015-05-10 20:54:36 -070012273 if (!debugfs_create_u32("mapping_count", S_IRUGO, ecm_db_dentry,
12274 (u32 *)&ecm_db_mapping_count)) {
12275 DEBUG_ERROR("Failed to create ecm db mapping count file in debugfs\n");
12276 goto init_cleanup;
12277 }
12278
12279 if (!debugfs_create_u32("node_count", S_IRUGO, ecm_db_dentry,
12280 (u32 *)&ecm_db_node_count)) {
12281 DEBUG_ERROR("Failed to create ecm db node count file in debugfs\n");
12282 goto init_cleanup;
12283 }
12284
12285 if (!debugfs_create_u32("iface_count", S_IRUGO, ecm_db_dentry,
12286 (u32 *)&ecm_db_iface_count)) {
12287 DEBUG_ERROR("Failed to create ecm db iface count file in debugfs\n");
12288 goto init_cleanup;
12289 }
12290
12291 if (!debugfs_create_file("defunct_all", S_IRUGO | S_IWUSR, ecm_db_dentry,
12292 NULL, &ecm_db_defunct_all_fops)) {
12293 DEBUG_ERROR("Failed to create ecm db defunct_all file in debugfs\n");
12294 goto init_cleanup;
12295 }
12296
12297 if (!debugfs_create_file("connection_count_simple", S_IRUGO, ecm_db_dentry,
12298 NULL, &ecm_db_connection_count_simple_fops)) {
12299 DEBUG_ERROR("Failed to create ecm db connection count simple file in debugfs\n");
12300 goto init_cleanup;
Ben Menchaca84f36632014-02-28 20:57:38 +000012301 }
12302
Murat Sezgina89f7c02016-10-19 11:06:56 -070012303 ecm_db_connection_table = vzalloc(sizeof(struct ecm_db_connection_instance *) * ECM_DB_CONNECTION_HASH_SLOTS);
12304 if (!ecm_db_connection_table) {
12305 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_connection_table\n");
12306 goto init_cleanup;
12307 }
12308
12309 ecm_db_connection_table_lengths = vzalloc(sizeof(int) * ECM_DB_CONNECTION_HASH_SLOTS);
12310 if (!ecm_db_connection_table_lengths) {
12311 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_connection_table_lengths\n");
12312 goto init_cleanup_1;
12313 }
12314
12315 ecm_db_connection_serial_table = vzalloc(sizeof(struct ecm_db_connection_instance *) * ECM_DB_CONNECTION_SERIAL_HASH_SLOTS);
12316 if (!ecm_db_connection_serial_table) {
12317 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_connection_serial_table\n");
12318 goto init_cleanup_2;
12319 }
12320
12321 ecm_db_connection_serial_table_lengths = vzalloc(sizeof(int) * ECM_DB_CONNECTION_SERIAL_HASH_SLOTS);
12322 if (!ecm_db_connection_serial_table_lengths) {
12323 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_connection_serial_table_lengths\n");
12324 goto init_cleanup_3;
12325 }
12326
12327 ecm_db_mapping_table = vzalloc(sizeof(struct ecm_db_mapping_instance *) * ECM_DB_MAPPING_HASH_SLOTS);
12328 if (!ecm_db_mapping_table) {
12329 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_mapping_table\n");
12330 goto init_cleanup_4;
12331 }
12332
12333 ecm_db_mapping_table_lengths = vzalloc(sizeof(int) * ECM_DB_MAPPING_HASH_SLOTS);
12334 if (!ecm_db_mapping_table_lengths) {
12335 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_mapping_table_lengths\n");
12336 goto init_cleanup_5;
12337 }
12338
12339 ecm_db_host_table = vzalloc(sizeof(struct ecm_db_host_instance *) * ECM_DB_HOST_HASH_SLOTS);
12340 if (!ecm_db_host_table) {
12341 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_host_table\n");
12342 goto init_cleanup_6;
12343 }
12344
12345 ecm_db_host_table_lengths = vzalloc(sizeof(int) * ECM_DB_HOST_HASH_SLOTS);
12346 if (!ecm_db_host_table_lengths) {
12347 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_host_table_lengths\n");
12348 goto init_cleanup_7;
12349 }
12350
12351 ecm_db_node_table = vzalloc(sizeof(struct ecm_db_node_instance *) * ECM_DB_NODE_HASH_SLOTS);
12352 if (!ecm_db_node_table) {
12353 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_node_table\n");
12354 goto init_cleanup_8;
12355 }
12356
12357 ecm_db_node_table_lengths = vzalloc(sizeof(int) * ECM_DB_NODE_HASH_SLOTS);
12358 if (!ecm_db_node_table_lengths) {
12359 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_node_table_lengths\n");
12360 goto init_cleanup_9;
12361 }
12362
Ben Menchaca84f36632014-02-28 20:57:38 +000012363 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000012364 * Set a timer to manage cleanup of expired connections
12365 */
12366 init_timer(&ecm_db_timer);
12367 ecm_db_timer.function = ecm_db_timer_callback;
12368 ecm_db_timer.data = 0;
12369 ecm_db_timer.expires = jiffies + HZ;
12370 add_timer(&ecm_db_timer);
12371
12372 /*
12373 * Initialise timer groups with time values
12374 */
12375 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT].time = ECM_DB_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT;
12376 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT;
12377 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT].time = ECM_DB_CONNECTION_GENERIC_TIMEOUT;
12378 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT;
12379 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT].time = ECM_DB_CONNECTION_IGMP_TIMEOUT;
12380 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT;
12381 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT].time = ECM_DB_CONNECTION_UDP_TIMEOUT;
12382 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT;
12383 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT].time = ECM_DB_CONNECTION_UDP_TIMEOUT;
12384 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT;
12385 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT].time = ECM_DB_CONNECTION_ICMP_TIMEOUT;
12386 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT;
12387 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT].time = ECM_DB_CONNECTION_TCP_SHORT_TIMEOUT;
12388 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT;
12389 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT].time = ECM_DB_CONNECTION_TCP_RST_TIMEOUT;
12390 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT;
12391 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT].time = ECM_DB_CONNECTION_TCP_LONG_TIMEOUT;
12392 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT;
12393 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT].time = ECM_DB_CONNECTION_PPTP_DATA_TIMEOUT;
12394 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT;
12395 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT].time = ECM_DB_CONNECTION_RTCP_TIMEOUT;
12396 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT;
12397 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT].time = ECM_DB_CONNECTION_TCP_LONG_TIMEOUT;
12398 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT;
12399 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT].time = ECM_DB_CONNECTION_RTSP_FAST_TIMEOUT;
12400 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT;
12401 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT].time = ECM_DB_CONNECTION_RTSP_SLOW_TIMEOUT;
12402 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT;
12403 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT].time = ECM_DB_CONNECTION_DNS_TIMEOUT;
12404 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT;
12405 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT].time = ECM_DB_CONNECTION_FTP_TIMEOUT;
12406 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT;
12407 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT].time = ECM_DB_CONNECTION_BITTORRENT_TIMEOUT;
12408 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT;
12409
12410 /*
12411 * H323 timeout value is 8 hours (8h * 60m * 60s == 28800 seconds).
12412 */
12413 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT].time = ECM_DB_CONNECTION_H323_TIMEOUT;
12414 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT;
12415
12416 /*
12417 * IKE Timeout (seconds) = 15 hours
12418 */
12419 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT].time = ECM_DB_CONNECTION_IKE_TIMEOUT;
12420 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT;
12421
12422 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT].time = ECM_DB_CONNECTION_ESP_TIMEOUT;
12423 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT;
12424 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT].time = ECM_DB_CONNECTION_ESP_PENDING_TIMEOUT;
12425 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT;
12426
12427 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT].time = ECM_DB_CONNECTION_SDP_TIMEOUT;
12428 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT;
12429 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT].time = ECM_DB_CONNECTION_SIP_TIMEOUT;
12430 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT;
12431
12432 /*
12433 * Reset connection by protocol counters
12434 */
12435 memset(ecm_db_connection_count_by_protocol, 0, sizeof(ecm_db_connection_count_by_protocol));
12436
Gareth Williamsb39e7c22015-03-25 10:15:33 +000012437#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +010012438 /*
12439 * Reset classifier type assignment lists
12440 */
12441 memset(ecm_db_connection_classifier_type_assignments, 0, sizeof(ecm_db_connection_classifier_type_assignments));
Gareth Williamsb39e7c22015-03-25 10:15:33 +000012442#endif
Murat Sezgin1134fb82015-10-06 14:03:49 -070012443 /*
12444 * register for route table modification events
12445 */
12446 ip_rt_register_notifier(&ecm_db_iproute_table_update_nb);
12447 rt6_register_notifier(&ecm_db_ip6route_table_update_nb);
12448
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012449 return 0;
Ben Menchaca84f36632014-02-28 20:57:38 +000012450
Murat Sezgina89f7c02016-10-19 11:06:56 -070012451init_cleanup_9:
12452 vfree(ecm_db_node_table);
12453init_cleanup_8:
12454 vfree(ecm_db_host_table_lengths);
12455init_cleanup_7:
12456 vfree(ecm_db_host_table);
12457init_cleanup_6:
12458 vfree(ecm_db_mapping_table_lengths);
12459init_cleanup_5:
12460 vfree(ecm_db_mapping_table);
12461init_cleanup_4:
12462 vfree(ecm_db_connection_serial_table_lengths);
12463init_cleanup_3:
12464 vfree(ecm_db_connection_serial_table);
12465init_cleanup_2:
12466 vfree(ecm_db_connection_table_lengths);
12467init_cleanup_1:
12468 vfree(ecm_db_connection_table);
Murat Sezgin908ecb32015-05-10 20:54:36 -070012469init_cleanup:
Murat Sezgin908ecb32015-05-10 20:54:36 -070012470 debugfs_remove_recursive(ecm_db_dentry);
12471 return -1;
Ben Menchaca84f36632014-02-28 20:57:38 +000012472}
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012473EXPORT_SYMBOL(ecm_db_init);
Ben Menchaca84f36632014-02-28 20:57:38 +000012474
12475/*
12476 * ecm_db_exit()
12477 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012478void ecm_db_exit(void)
Ben Menchaca84f36632014-02-28 20:57:38 +000012479{
12480 DEBUG_INFO("ECM DB Module exit\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012481
12482 spin_lock_bh(&ecm_db_lock);
12483 ecm_db_terminate_pending = true;
12484 spin_unlock_bh(&ecm_db_lock);
12485
12486 ecm_db_connection_defunct_all();
12487
12488 /*
12489 * Destroy garbage timer
12490 * Timer must be cancelled outside of holding db lock - if the
12491 * timer callback runs on another CPU we would deadlock
12492 * as we would wait for the callback to finish and it would wait
12493 * indefinately for the lock to be released!
12494 */
12495 del_timer_sync(&ecm_db_timer);
Murat Sezgin1f381852014-11-20 09:51:07 -080012496
Murat Sezgin908ecb32015-05-10 20:54:36 -070012497 /*
Murat Sezgina89f7c02016-10-19 11:06:56 -070012498 * Free the tables.
12499 */
12500 vfree(ecm_db_node_table);
12501 vfree(ecm_db_host_table_lengths);
12502 vfree(ecm_db_host_table);
12503 vfree(ecm_db_mapping_table_lengths);
12504 vfree(ecm_db_mapping_table);
12505 vfree(ecm_db_connection_serial_table_lengths);
12506 vfree(ecm_db_connection_serial_table);
12507 vfree(ecm_db_connection_table_lengths);
12508 vfree(ecm_db_connection_table);
12509
12510 /*
Murat Sezgin908ecb32015-05-10 20:54:36 -070012511 * Remove the debugfs files recursively.
12512 */
12513 if (ecm_db_dentry) {
12514 debugfs_remove_recursive(ecm_db_dentry);
Murat Sezgin1f381852014-11-20 09:51:07 -080012515 }
Murat Sezgin1134fb82015-10-06 14:03:49 -070012516
12517 /*
12518 * unregister for route table update events
12519 */
12520 ip_rt_unregister_notifier(&ecm_db_iproute_table_update_nb);
12521 rt6_unregister_notifier(&ecm_db_ip6route_table_update_nb);
Ben Menchaca84f36632014-02-28 20:57:38 +000012522}
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012523EXPORT_SYMBOL(ecm_db_exit);