blob: 0c63a74838cb49f78f86cfd9a003ad92a4c5782f [file] [log] [blame]
Ben Menchaca84f36632014-02-28 20:57:38 +00001/*
2 **************************************************************************
Murat Sezgin9304d472017-04-14 10:16:52 -07003 * Copyright (c) 2014-2017, 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/*
Murat Sezgin66fe22f2017-08-24 13:54:57 -070086 * Check the configured HZ value.
87 */
88#if HZ > 100000
89#error "Bad HZ value"
90#endif
91
92/*
Ben Menchaca84f36632014-02-28 20:57:38 +000093 * Global lists.
94 * All instances are inserted into global list - this allows easy iteration of all instances of a particular type.
95 * The list is doubly linked for fast removal. The list is in no particular order.
96 */
97struct ecm_db_connection_instance *ecm_db_connections = NULL;
98struct ecm_db_mapping_instance *ecm_db_mappings = NULL;
99struct ecm_db_host_instance *ecm_db_hosts = NULL;
100struct ecm_db_node_instance *ecm_db_nodes = NULL;
101struct ecm_db_iface_instance *ecm_db_interfaces = NULL;
102
103/*
104 * Connection hash table
105 */
106#define ECM_DB_CONNECTION_HASH_SLOTS 32768
Murat Sezgina89f7c02016-10-19 11:06:56 -0700107static struct ecm_db_connection_instance **ecm_db_connection_table;
Ben Menchaca84f36632014-02-28 20:57:38 +0000108 /* Slots of the connection hash table */
Murat Sezgina89f7c02016-10-19 11:06:56 -0700109static int *ecm_db_connection_table_lengths;
Ben Menchaca84f36632014-02-28 20:57:38 +0000110 /* Tracks how long each chain is */
111static int ecm_db_connection_count = 0; /* Number of connections allocated */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100112static int ecm_db_connection_serial = 0; /* Serial number - ensures each connection has a unique serial number.
Ben Menchaca84f36632014-02-28 20:57:38 +0000113 * Serial numbers are used mainly by classifiers that keep their own state
114 * and can 'link' their state to the right connection using a serial number.
Ben Menchaca84f36632014-02-28 20:57:38 +0000115 * The serial number is also used as a soft linkage to other subsystems such as NA.
116 */
117typedef uint32_t ecm_db_connection_hash_t;
118
119/*
120 * Connection serial number hash table
121 */
122#define ECM_DB_CONNECTION_SERIAL_HASH_SLOTS 32768
Murat Sezgina89f7c02016-10-19 11:06:56 -0700123static struct ecm_db_connection_instance **ecm_db_connection_serial_table;
Ben Menchaca84f36632014-02-28 20:57:38 +0000124 /* Slots of the connection serial hash table */
Murat Sezgina89f7c02016-10-19 11:06:56 -0700125static int *ecm_db_connection_serial_table_lengths;
Ben Menchaca84f36632014-02-28 20:57:38 +0000126 /* Tracks how long each chain is */
127typedef uint32_t ecm_db_connection_serial_hash_t;
128
129/*
130 * Mapping hash table
131 */
132#define ECM_DB_MAPPING_HASH_SLOTS 32768
Murat Sezgina89f7c02016-10-19 11:06:56 -0700133static struct ecm_db_mapping_instance **ecm_db_mapping_table;
Ben Menchaca84f36632014-02-28 20:57:38 +0000134 /* Slots of the mapping hash table */
Murat Sezgina89f7c02016-10-19 11:06:56 -0700135static int *ecm_db_mapping_table_lengths;
Ben Menchaca84f36632014-02-28 20:57:38 +0000136 /* Tracks how long each chain is */
137static int ecm_db_mapping_count = 0; /* Number of mappings allocated */
138typedef uint32_t ecm_db_mapping_hash_t;
139
140/*
141 * Host hash table
142 */
143#define ECM_DB_HOST_HASH_SLOTS 32768
Murat Sezgina89f7c02016-10-19 11:06:56 -0700144static struct ecm_db_host_instance **ecm_db_host_table;
Ben Menchaca84f36632014-02-28 20:57:38 +0000145 /* Slots of the host hash table */
Murat Sezgina89f7c02016-10-19 11:06:56 -0700146static int *ecm_db_host_table_lengths;
Ben Menchaca84f36632014-02-28 20:57:38 +0000147 /* Tracks how long each chain is */
148static int ecm_db_host_count = 0; /* Number of hosts allocated */
149typedef uint32_t ecm_db_host_hash_t;
150
151/*
152 * Node hash table
153 */
154#define ECM_DB_NODE_HASH_SLOTS 32768
Murat Sezgina89f7c02016-10-19 11:06:56 -0700155static struct ecm_db_node_instance **ecm_db_node_table;
Ben Menchaca84f36632014-02-28 20:57:38 +0000156 /* Slots of the node hash table */
Murat Sezgina89f7c02016-10-19 11:06:56 -0700157static int *ecm_db_node_table_lengths;
Ben Menchaca84f36632014-02-28 20:57:38 +0000158 /* Tracks how long each chain is */
159static int ecm_db_node_count = 0; /* Number of nodes allocated */
160typedef uint32_t ecm_db_node_hash_t;
161
162/*
163 * Interface hash table
164 */
165#define ECM_DB_IFACE_HASH_SLOTS 8
166static struct ecm_db_iface_instance *ecm_db_iface_table[ECM_DB_IFACE_HASH_SLOTS];
167 /* Slots of the interface hash table */
168static int ecm_db_iface_table_lengths[ECM_DB_IFACE_HASH_SLOTS];
169 /* Tracks how long each chain is */
170static int ecm_db_iface_count = 0; /* Number of interfaces allocated */
171typedef uint32_t ecm_db_iface_hash_t;
172
Murat Sezgin91c5d712015-06-12 15:16:22 -0700173#define ECM_DB_IFACE_ID_HASH_SLOTS 8
174static struct ecm_db_iface_instance *ecm_db_iface_id_table[ECM_DB_IFACE_ID_HASH_SLOTS];
175 /* Slots of the interface id hash table */
176static int ecm_db_iface_id_table_lengths[ECM_DB_IFACE_ID_HASH_SLOTS];
177 /* Tracks how long each chain is */
178typedef uint32_t ecm_db_iface_id_hash_t;
179
Ben Menchaca84f36632014-02-28 20:57:38 +0000180/*
181 * Listeners
182 */
183static int ecm_db_listeners_count = 0; /* Number of listeners allocated */
184static struct ecm_db_listener_instance *ecm_db_listeners = NULL;
185 /* Event listeners */
186
Gareth Williamsf98d4192015-03-11 16:55:41 +0000187#ifdef ECM_STATE_OUTPUT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000188/*
Gareth Williamsd5618a82015-05-20 11:13:32 +0100189 * ecm_db_iface_state_get_method_t
190 * Used to obtain interface state
Ben Menchaca84f36632014-02-28 20:57:38 +0000191 */
Gareth Williamsd5618a82015-05-20 11:13:32 +0100192typedef 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 +0000193#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000194
195/*
196 * struct ecm_db_iface_instance
197 */
198struct ecm_db_iface_instance {
199 struct ecm_db_iface_instance *next; /* Next instance in global list */
200 struct ecm_db_iface_instance *prev; /* Previous instance in global list */
201 struct ecm_db_iface_instance *hash_next; /* Next Interface in the chain of Interfaces */
202 struct ecm_db_iface_instance *hash_prev; /* previous Interface in the chain of Interfaces */
203 ecm_db_iface_type_t type; /* RO: Type of interface */
Ben Menchaca84f36632014-02-28 20:57:38 +0000204 uint32_t time_added; /* RO: DB time stamp when the Interface was added into the database */
205
206 int32_t interface_identifier; /* RO: The operating system dependent identifier of this interface */
Murat Sezgin91c5d712015-06-12 15:16:22 -0700207 int32_t ae_interface_identifier; /* RO: The accel engine identifier of this interface */
Ben Menchaca84f36632014-02-28 20:57:38 +0000208 char name[IFNAMSIZ]; /* Name of interface */
209 int32_t mtu; /* Interface MTU */
210
Murat Sezgin91c5d712015-06-12 15:16:22 -0700211 struct ecm_db_iface_instance *iface_id_hash_next; /* Next interface in the chain of interface id table */
212 struct ecm_db_iface_instance *iface_id_hash_prev; /* Previous interface in the chain of interface id table */
213 ecm_db_iface_id_hash_t iface_id_hash_index; /* Hash index value of chains */
214
Gareth Williams85331c92015-03-11 20:39:18 +0000215#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000216 uint64_t from_data_total; /* Total of data sent by this Interface */
217 uint64_t to_data_total; /* Total of data sent to this Interface */
218 uint64_t from_packet_total; /* Total of packets sent by this Interface */
219 uint64_t to_packet_total; /* Total of packets sent to this Interface */
220 uint64_t from_data_total_dropped;
221 uint64_t to_data_total_dropped;
222 uint64_t from_packet_total_dropped;
223 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000224#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000225
Gareth Williamsb5903892015-03-20 15:13:07 +0000226#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000227 /*
228 * For convenience interfaces keep lists of connections that have been established
229 * from them and to them.
230 * In fact the same connection could be listed as from & to on the same interface (think: WLAN<>WLAN AP function)
231 * Interfaces keep this information for rapid iteration of connections e.g. when an interface 'goes down' we
Murat Sezgin91c5d712015-06-12 15:16:22 -0700232 * can defunct all associated connections or destroy any accel engine rules.
Ben Menchaca84f36632014-02-28 20:57:38 +0000233 */
234 struct ecm_db_connection_instance *from_connections; /* list of connections made from this interface */
235 struct ecm_db_connection_instance *to_connections; /* list of connections made to this interface */
236
237 struct ecm_db_connection_instance *from_nat_connections; /* list of NAT connections made from this interface */
238 struct ecm_db_connection_instance *to_nat_connections; /* list of NAT connections made to this interface */
239
240 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000241 * Normally only the node refers to the interfaces which it is reachable upon.
242 * The interface also keeps a list of all nodes that can be reached.
243 */
244 struct ecm_db_node_instance *nodes; /* Nodes associated with this Interface */
245 int node_count; /* Number of Nodes in the nodes list */
246#endif
247
248 /*
Ben Menchaca84f36632014-02-28 20:57:38 +0000249 * Interface specific information.
250 * type identifies which information is applicable.
251 */
252 union {
253 struct ecm_db_interface_info_ethernet ethernet; /* type == ECM_DB_IFACE_TYPE_ETHERNET */
Murat Sezgin37fb3952015-03-10 16:45:13 -0700254#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000255 struct ecm_db_interface_info_vlan vlan; /* type == ECM_DB_IFACE_TYPE_VLAN */
Murat Sezgin37fb3952015-03-10 16:45:13 -0700256#endif
Murat Sezgin910c9662015-03-11 16:15:06 -0700257#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000258 struct ecm_db_interface_info_lag lag; /* type == ECM_DB_IFACE_TYPE_LAG */
Murat Sezgin910c9662015-03-11 16:15:06 -0700259#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000260 struct ecm_db_interface_info_bridge bridge; /* type == ECM_DB_IFACE_TYPE_BRIDGE */
ratheesh kannotha32fdd12015-09-09 08:02:58 +0530261#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000262 struct ecm_db_interface_info_pppoe pppoe; /* type == ECM_DB_IFACE_TYPE_PPPOE */
Murat Sezginaad635c2015-03-06 16:11:41 -0800263#endif
ratheesh kannotha32fdd12015-09-09 08:02:58 +0530264#ifdef ECM_INTERFACE_L2TPV2_ENABLE
265 struct ecm_db_interface_info_pppol2tpv2 pppol2tpv2; /* type == ECM_DB_IFACE_TYPE_PPPOL2TPV2 */
266#endif
Shyam Sunder23f2e542015-09-28 14:56:49 +0530267#ifdef ECM_INTERFACE_PPTP_ENABLE
268 struct ecm_db_interface_info_pptp pptp; /* type == ECM_DB_IFACE_TYPE_PPTP */
269#endif
ratheesh kannothcfdcb332015-12-24 07:19:18 +0530270#ifdef ECM_INTERFACE_MAP_T_ENABLE
271 struct ecm_db_interface_info_map_t map_t; /* type == ECM_DB_IFACE_TYPE_MAP_T */
272#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000273 struct ecm_db_interface_info_unknown unknown; /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
274 struct ecm_db_interface_info_loopback loopback; /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
Murat Sezgin69a27532015-03-12 14:09:40 -0700275#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000276 struct ecm_db_interface_info_ipsec_tunnel ipsec_tunnel; /* type == ECM_DB_IFACE_TYPE_IPSEC_TUNNEL */
Murat Sezgin69a27532015-03-12 14:09:40 -0700277#endif
Murat Sezginbde55f92015-03-11 16:44:11 -0700278#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000279 struct ecm_db_interface_info_sit sit; /* type == ECM_DB_IFACE_TYPE_SIT (6-in-4) */
Murat Sezginbde55f92015-03-11 16:44:11 -0700280#endif
Murat Sezginc1402562015-03-12 12:32:20 -0700281#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +0000282#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000283 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 -0700284#endif
Gareth Williams8ac34292015-03-17 14:06:58 +0000285#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000286 } type_info;
287
Gareth Williamsf98d4192015-03-11 16:55:41 +0000288#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +0100289 ecm_db_iface_state_get_method_t state_get; /* Type specific method to return state */
Gareth Williamsf98d4192015-03-11 16:55:41 +0000290#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000291
292 ecm_db_iface_final_callback_t final; /* Callback to owner when object is destroyed */
293 void *arg; /* Argument returned to owner in callbacks */
294 uint32_t flags;
295 int refs; /* Integer to trap we never go negative */
296 ecm_db_iface_hash_t hash_index;
297#if (DEBUG_LEVEL > 0)
298 uint16_t magic;
299#endif
300};
301
302/*
303 * Interface flags
304 */
305#define ECM_DB_IFACE_FLAGS_INSERTED 1 /* Interface is inserted into connection database tables */
306
307/*
308 * struct ecm_db_node_instance
309 */
310struct ecm_db_node_instance {
311 struct ecm_db_node_instance *next; /* Next instance in global list */
312 struct ecm_db_node_instance *prev; /* Previous instance in global list */
Gareth Williams90f2a282014-08-27 15:56:25 +0100313 struct ecm_db_node_instance *hash_next; /* Next node in the chain of nodes */
314 struct ecm_db_node_instance *hash_prev; /* previous node in the chain of nodes */
Ben Menchaca84f36632014-02-28 20:57:38 +0000315 uint8_t address[ETH_ALEN]; /* RO: MAC Address of this node */
Gareth Williams90f2a282014-08-27 15:56:25 +0100316
Gareth Williamsb5903892015-03-20 15:13:07 +0000317#ifdef ECM_DB_XREF_ENABLE
Gareth Williams90f2a282014-08-27 15:56:25 +0100318 /*
319 * For convenience nodes keep lists of connections that have been established from them and to them.
320 * In fact the same connection could be listed as from & to on the same interface (think: WLAN<>WLAN AP function)
321 * Nodes keep this information for rapid iteration of connections e.g. when a node 'goes down' we
Murat Sezgin91c5d712015-06-12 15:16:22 -0700322 * can defunct all associated connections or destroy any accel engine rules.
Gareth Williams90f2a282014-08-27 15:56:25 +0100323 */
324 struct ecm_db_connection_instance *from_connections; /* list of connections made from this node */
325 struct ecm_db_connection_instance *to_connections; /* list of connections made to this node */
326 int from_connections_count; /* Number of connections in the from_connections list */
327 int to_connections_count; /* Number of connections in the to_connections list */
328
329 struct ecm_db_connection_instance *from_nat_connections; /* list of NAT connections made from this node */
330 struct ecm_db_connection_instance *to_nat_connections; /* list of NAT connections made to this node */
331 int from_nat_connections_count; /* Number of connections in the from_nat_connections list */
332 int to_nat_connections_count; /* Number of connections in the to_nat_connections list */
333
Gareth Williamsb5903892015-03-20 15:13:07 +0000334 /*
335 * Nodes reachable from an interface are stored in a linked list maintained by that interface.
336 * This is so, given an interface, you can examine all nodes reachable from it.
337 */
338 struct ecm_db_node_instance *node_next; /* The next node within the same iface nodes list */
339 struct ecm_db_node_instance *node_prev; /* The previous node within the same iface nodes list */
340#endif
341
Ben Menchaca84f36632014-02-28 20:57:38 +0000342 uint32_t time_added; /* RO: DB time stamp when the node was added into the database */
343
Gareth Williams85331c92015-03-11 20:39:18 +0000344#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000345 uint64_t from_data_total; /* Total of data sent by this node */
346 uint64_t to_data_total; /* Total of data sent to this node */
347 uint64_t from_packet_total; /* Total of packets sent by this node */
348 uint64_t to_packet_total; /* Total of packets sent to this node */
349 uint64_t from_data_total_dropped;
350 uint64_t to_data_total_dropped;
351 uint64_t from_packet_total_dropped;
352 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000353#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000354
355 struct ecm_db_iface_instance *iface; /* The interface to which this node relates */
Ben Menchaca84f36632014-02-28 20:57:38 +0000356
357 ecm_db_node_final_callback_t final; /* Callback to owner when object is destroyed */
358 void *arg; /* Argument returned to owner in callbacks */
359 uint8_t flags;
360 int refs; /* Integer to trap we never go negative */
361 ecm_db_node_hash_t hash_index;
362#if (DEBUG_LEVEL > 0)
363 uint16_t magic;
364#endif
365};
366
367/*
368 * Node flags
369 */
370#define ECM_DB_NODE_FLAGS_INSERTED 1 /* Node is inserted into connection database tables */
371
372/*
373 * struct ecm_db_host_instance
374 */
375struct ecm_db_host_instance {
376 struct ecm_db_host_instance *next; /* Next instance in global list */
377 struct ecm_db_host_instance *prev; /* Previous instance in global list */
378 struct ecm_db_host_instance *hash_next; /* Next host in the chain of hosts */
379 struct ecm_db_host_instance *hash_prev; /* previous host in the chain of hosts */
380 ip_addr_t address; /* RO: IPv4/v6 Address of this host */
381 bool on_link; /* RO: false when this host is reached via a gateway */
Gareth Williamsb5903892015-03-20 15:13:07 +0000382 uint32_t time_added; /* RO: DB time stamp when the host was added into the database */
383
384#ifdef ECM_DB_XREF_ENABLE
385 /*
386 * Normally the mapping refers to the host it requires.
387 * However the host also keeps a list of all mappings that are associated with it.
388 */
Ben Menchaca84f36632014-02-28 20:57:38 +0000389 struct ecm_db_mapping_instance *mappings; /* Mappings made on this host */
390 int mapping_count; /* Number of mappings in the mapping list */
Gareth Williamsb5903892015-03-20 15:13:07 +0000391#endif
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530392
Gareth Williams85331c92015-03-11 20:39:18 +0000393#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000394 uint64_t from_data_total; /* Total of data sent by this host */
395 uint64_t to_data_total; /* Total of data sent to this host */
396 uint64_t from_packet_total; /* Total of packets sent by this host */
397 uint64_t to_packet_total; /* Total of packets sent to this host */
398 uint64_t from_data_total_dropped;
399 uint64_t to_data_total_dropped;
400 uint64_t from_packet_total_dropped;
401 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000402#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000403
404 ecm_db_host_final_callback_t final; /* Callback to owner when object is destroyed */
405 void *arg; /* Argument returned to owner in callbacks */
406 uint32_t flags;
407 int refs; /* Integer to trap we never go negative */
408 ecm_db_host_hash_t hash_index;
409#if (DEBUG_LEVEL > 0)
410 uint16_t magic;
411#endif
412};
413
414/*
415 * Host flags
416 */
417#define ECM_DB_HOST_FLAGS_INSERTED 1 /* Host is inserted into connection database tables */
418
419/*
420 * struct ecm_db_mapping_instance
421 */
422struct ecm_db_mapping_instance {
423 struct ecm_db_mapping_instance *next; /* Next instance in global list */
424 struct ecm_db_mapping_instance *prev; /* Previous instance in global list */
425
426 struct ecm_db_mapping_instance *hash_next; /* Next mapping in the chain of mappings */
427 struct ecm_db_mapping_instance *hash_prev; /* previous mapping in the chain of mappings */
428
429 uint32_t time_added; /* RO: DB time stamp when the connection was added into the database */
430 struct ecm_db_host_instance *host; /* The host to which this mapping relates */
431 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 +0000432
Gareth Williamsb5903892015-03-20 15:13:07 +0000433#ifdef ECM_DB_XREF_ENABLE
434 /*
435 * For convenience mappings keep lists of connections that have been established from them and to them.
436 * In fact the same connection could be listed as from & to on the same interface (think: WLAN<>WLAN AP function)
437 * Mappings keep this information for rapid iteration of connections e.g. given a mapping we
Murat Sezgin91c5d712015-06-12 15:16:22 -0700438 * can defunct all associated connections or destroy any accel engine rules.
Gareth Williamsb5903892015-03-20 15:13:07 +0000439 */
Ben Menchaca84f36632014-02-28 20:57:38 +0000440 struct ecm_db_connection_instance *from_connections; /* list of connections made from this host mapping */
441 struct ecm_db_connection_instance *to_connections; /* list of connections made to this host mapping */
442
443 struct ecm_db_connection_instance *from_nat_connections; /* list of NAT connections made from this host mapping */
444 struct ecm_db_connection_instance *to_nat_connections; /* list of NAT connections made to this host mapping */
445
446 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000447 * While a mapping refers to the host it requires.
448 * The host also keeps a list of all mappings that are associated with it, this is that list linkage.
449 */
450 struct ecm_db_mapping_instance *mapping_next; /* Next mapping in the list of mappings for the host */
451 struct ecm_db_mapping_instance *mapping_prev; /* previous mapping in the list of mappings for the host */
452#endif
453
454 /*
Ben Menchaca84f36632014-02-28 20:57:38 +0000455 * Connection counts
456 */
457 int tcp_from;
458 int tcp_to;
459 int udp_from;
460 int udp_to;
461 int tcp_nat_from;
462 int tcp_nat_to;
463 int udp_nat_from;
464 int udp_nat_to;
465
466 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000467 * Connection counts
Ben Menchaca84f36632014-02-28 20:57:38 +0000468 */
Gareth Williamsb5903892015-03-20 15:13:07 +0000469 int from; /* Number of connections made from */
470 int to; /* Number of connections made to */
471 int nat_from; /* Number of connections made from (nat) */
472 int nat_to; /* Number of connections made to (nat) */
Ben Menchaca84f36632014-02-28 20:57:38 +0000473
Gareth Williams85331c92015-03-11 20:39:18 +0000474#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000475 /*
476 * Data totals
477 */
478 uint64_t from_data_total; /* Total of data sent by this mapping */
479 uint64_t to_data_total; /* Total of data sent to this mapping */
480 uint64_t from_packet_total; /* Total of packets sent by this mapping */
481 uint64_t to_packet_total; /* Total of packets sent to this mapping */
482 uint64_t from_data_total_dropped;
483 uint64_t to_data_total_dropped;
484 uint64_t from_packet_total_dropped;
485 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000486#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000487
488 ecm_db_mapping_final_callback_t final; /* Callback to owner when object is destroyed */
489 void *arg; /* Argument returned to owner in callbacks */
490 uint32_t flags;
491 int refs; /* Integer to trap we never go negative */
492 ecm_db_mapping_hash_t hash_index;
493#if (DEBUG_LEVEL > 0)
494 uint16_t magic;
495#endif
496};
497
498/*
499 * Mapping flags
500 */
501#define ECM_DB_MAPPING_FLAGS_INSERTED 1 /* Mapping is inserted into connection database tables */
502
503/*
504 * struct ecm_db_timer_group
505 * A timer group - all group members within the same group have the same TTL reset value.
506 *
507 * Expiry of entries occurs from tail to head.
508 */
509struct ecm_db_timer_group {
510 struct ecm_db_timer_group_entry *head; /* Most recently used entry in this timer group */
511 struct ecm_db_timer_group_entry *tail; /* Least recently used entry in this timer group. */
512 uint32_t time; /* Time in seconds a group entry will be given to live when 'touched' */
513 ecm_db_timer_group_t tg; /* RO: The group id */
514#if (DEBUG_LEVEL > 0)
515 uint16_t magic;
516#endif
517};
518
519/*
520 * Timers and cleanup
521 */
522static uint32_t ecm_db_time = 0; /* Time in seconds since start */
523static struct ecm_db_timer_group ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_MAX];
524 /* Timer groups */
525static struct timer_list ecm_db_timer; /* Timer to drive timer groups */
526
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000527#ifdef ECM_DB_CTA_TRACK_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000528/*
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000529 * Classifier TYPE assignment lists.
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100530 *
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000531 * For each type of classifier a list is kept of all connections assigned a classifier of that type.
532 * This permits a classifier type to rapidly retrieve all connections with classifiers assigned to it of that type.
533 *
534 * NOTE: This is in addition to the basic functionality whereby a connection keeps a list of classifier instances
535 * that are assigned to it in descending order of priority.
536 */
537
538/*
539 * struct ecm_db_connection_classifier_type_assignment
540 * List linkage
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100541 */
542struct ecm_db_connection_classifier_type_assignment {
543 struct ecm_db_connection_instance *next; /* Next connection assigned to a classifier of this type */
544 struct ecm_db_connection_instance *prev; /* Previous connection assigned to a classifier of this type */
545 int iteration_count; /* >0 if something is examining this list entry and it may not be unlinked. The connection will persist. */
546 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 */
547#if (DEBUG_LEVEL > 0)
548 uint16_t magic;
549#endif
550};
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000551
552/*
553 * struct ecm_db_connection_classifier_type_assignment_list
554 * A list, one for each classifier type.
555 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100556struct ecm_db_connection_classifier_type_assignment_list {
557 struct ecm_db_connection_instance *type_assignments_list;
558 /* Lists of connections assigned to this type of classifier */
559 int32_t type_assignment_count; /* Number of connections in the list */
560} ecm_db_connection_classifier_type_assignments[ECM_CLASSIFIER_TYPES];
561 /* Each classifier type has a list of connections that are assigned to classifier instances of that type */
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000562#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100563
564/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000565 * struct ecm_db_connection_instance
566 */
567struct ecm_db_connection_instance {
568 struct ecm_db_connection_instance *next; /* Next instance in global list */
569 struct ecm_db_connection_instance *prev; /* Previous instance in global list */
570
571 struct ecm_db_connection_instance *hash_next; /* Next connection in chain */
572 struct ecm_db_connection_instance *hash_prev; /* Previous connection in chain */
573 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 +0530574
Ben Menchaca84f36632014-02-28 20:57:38 +0000575 struct ecm_db_connection_instance *serial_hash_next; /* Next connection in serial hash chain */
576 struct ecm_db_connection_instance *serial_hash_prev; /* Previous connection in serial hash chain */
577 ecm_db_connection_hash_t serial_hash_index; /* The hash table slot whose chain of connections this is inserted into */
578
579 uint32_t time_added; /* RO: DB time stamp when the connection was added into the database */
580
Gareth Williams3e5b37f2015-05-13 10:04:12 +0100581 int ip_version; /* RO: The version of IP protocol this connection was established for */
Ben Menchaca84f36632014-02-28 20:57:38 +0000582 int protocol; /* RO: Protocol of the connection */
583 ecm_db_direction_t direction; /* RO: 'Direction' of connection establishment. */
584 bool is_routed; /* RO: True when connection is routed, false when not */
585
586 /*
587 * Connection endpoint mapping
588 */
589 struct ecm_db_mapping_instance *mapping_from; /* The connection was established from this mapping */
590 struct ecm_db_mapping_instance *mapping_to; /* The connection was established to this mapping */
Ben Menchaca84f36632014-02-28 20:57:38 +0000591
592 /*
593 * Connection endpoint mapping for NAT purposes
594 * NOTE: For non-NAT connections these would be identical to the endpoint mappings.
595 */
596 struct ecm_db_mapping_instance *mapping_nat_from; /* The connection was established from this mapping */
597 struct ecm_db_mapping_instance *mapping_nat_to; /* The connection was established to this mapping */
Gareth Williamsb5903892015-03-20 15:13:07 +0000598
599 /*
600 * From / To Node (NAT and non-NAT).
601 * Connections keep references to the nodes upon which they operate.
602 * Gut feeling would tell us this is unusual since it should be the case that
603 * the HOST refer to the node, e.g. IP address to a MAC address.
604 * However there are some 'interesting' usage models where the same IP address may appear
605 * from different nodes / MAC addresses because of this the unique element here is the connection
606 * and so we record the node information directly here.
607 */
608 struct ecm_db_node_instance *from_node; /* Node from which this connection was established */
609 struct ecm_db_node_instance *to_node; /* Node to which this connection was established */
610 struct ecm_db_node_instance *from_nat_node; /* Node from which this connection was established */
611 struct ecm_db_node_instance *to_nat_node; /* Node to which this connection was established */
612
613#ifdef ECM_DB_XREF_ENABLE
614 /*
615 * The connection has references to the mappings (both nat and non-nat) as required above.
616 * Also mappings keep lists of connections made to/from them so that they may be iterated
617 * to determine associated connections in each direction/situation (e.g. "defuncting all connections made to/from a mapping").
618 */
619 struct ecm_db_connection_instance *from_next; /* Next connection made from the same mapping */
620 struct ecm_db_connection_instance *from_prev; /* Previous connection made from the same mapping */
621 struct ecm_db_connection_instance *to_next; /* Next connection made to the same mapping */
622 struct ecm_db_connection_instance *to_prev; /* Previous connection made to the same mapping */
623
Ben Menchaca84f36632014-02-28 20:57:38 +0000624 struct ecm_db_connection_instance *from_nat_next; /* Next connection made from the same mapping */
625 struct ecm_db_connection_instance *from_nat_prev; /* Previous connection made from the same mapping */
626 struct ecm_db_connection_instance *to_nat_next; /* Next connection made to the same mapping */
627 struct ecm_db_connection_instance *to_nat_prev; /* Previous connection made to the same mapping */
628
629 /*
630 * Connection endpoint interface
Gareth Williamsb5903892015-03-20 15:13:07 +0000631 * GGG TODO Deprecated - use interface lists instead.
632 * To be removed when interface heirarchies are implemented to provide the same functionality.
Ben Menchaca84f36632014-02-28 20:57:38 +0000633 */
634 struct ecm_db_connection_instance *iface_from_next; /* Next connection made from the same interface */
635 struct ecm_db_connection_instance *iface_from_prev; /* Previous connection made from the same interface */
636 struct ecm_db_connection_instance *iface_to_next; /* Next connection made to the same interface */
637 struct ecm_db_connection_instance *iface_to_prev; /* Previous connection made to the same interface */
638
639 /*
640 * Connection endpoint interface for NAT purposes
641 * NOTE: For non-NAT connections these would be identical to the endpoint interface.
Gareth Williamsb5903892015-03-20 15:13:07 +0000642 * GGG TODO Deprecated - use interface lists instead.
643 * To be removed when interface heirarchies are implemented to provide the same functionality.
Ben Menchaca84f36632014-02-28 20:57:38 +0000644 */
645 struct ecm_db_connection_instance *iface_from_nat_next; /* Next connection made from the same interface */
646 struct ecm_db_connection_instance *iface_from_nat_prev; /* Previous connection made from the same interface */
647 struct ecm_db_connection_instance *iface_to_nat_next; /* Next connection made to the same interface */
648 struct ecm_db_connection_instance *iface_to_nat_prev; /* Previous connection made to the same interface */
649
650 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000651 * As well as keeping a reference to the node which this connection uses the nodes
652 * also keep lists of connections made from/to them.
653 */
654 struct ecm_db_connection_instance *node_from_next; /* Next connection in the nodes from_connections list */
655 struct ecm_db_connection_instance *node_from_prev; /* Prev connection in the nodes from_connections list */
656 struct ecm_db_connection_instance *node_to_next; /* Next connection in the nodes to_connections list */
657 struct ecm_db_connection_instance *node_to_prev; /* Prev connection in the nodes to_connections list */
658
659 struct ecm_db_connection_instance *node_from_nat_next; /* Next connection in the nodes from_nat_connections list */
660 struct ecm_db_connection_instance *node_from_nat_prev; /* Prev connection in the nodes from_nat_connections list */
661 struct ecm_db_connection_instance *node_to_nat_next; /* Next connection in the nodes to_nat_connections list */
662 struct ecm_db_connection_instance *node_to_nat_prev; /* Prev connection in the nodes to_nat_connections list */
663#endif
664
665 /*
Ben Menchaca84f36632014-02-28 20:57:38 +0000666 * From / To interfaces list
667 */
668 struct ecm_db_iface_instance *from_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
669 /* The outermost to innnermost interface this connection is using in the from path.
670 * Relationships are recorded from [ECM_DB_IFACE_HEIRARCHY_MAX - 1] to [0]
671 */
672 int32_t from_interface_first; /* The index of the first interface in the list */
673 bool from_interface_set; /* True when a list has been set - even if there is NO list, it's still deliberately set that way. */
674 struct ecm_db_iface_instance *to_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
675 /* The outermost to innnermost interface this connection is using in the to path */
676 int32_t to_interface_first; /* The index of the first interface in the list */
677 bool to_interface_set; /* True when a list has been set - even if there is NO list, it's still deliberately set that way. */
678
679 /*
680 * From / To NAT interfaces list
Gareth Williams90f2a282014-08-27 15:56:25 +0100681 * GGG TODO Not sure if NAT interface lists are necessary or appropriate or practical.
682 * Needs to be assessed if it gives any clear benefit and possibly remove these if not.
Ben Menchaca84f36632014-02-28 20:57:38 +0000683 */
684 struct ecm_db_iface_instance *from_nat_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
685 /* The outermost to innnermost interface this connection is using in the from path.
686 * Relationships are recorded from [ECM_DB_IFACE_HEIRARCHY_MAX - 1] to [0]
687 */
688 int32_t from_nat_interface_first; /* The index of the first interface in the list */
689 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. */
690 struct ecm_db_iface_instance *to_nat_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
691 /* The outermost to innnermost interface this connection is using in the to path */
692 int32_t to_nat_interface_first; /* The index of the first interface in the list */
693 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. */
694
Shyam Sunder1f037262015-05-18 20:04:13 +0530695#ifdef ECM_MULTICAST_ENABLE
696 /*
697 * Destination Multicast interfaces list
698 */
Shyam Sunderbf40d0e2015-06-23 15:56:37 +0530699 struct ecm_db_iface_instance *to_mcast_interfaces;
700 /* The outermost to innnermost interfaces this connection is using in multicast path.
701 * The size of the buffer allocated for the to_mcast_interfaces heirarchies is as large as
702 * sizeof(struct ecm_db_iface_instance *) * ECM_DB_MULTICAST_IF_MAX * ECM_DB_IFACE_HEIRARCHY_MAX. */
Shyam Sunder1f037262015-05-18 20:04:13 +0530703 int32_t to_mcast_interface_first[ECM_DB_MULTICAST_IF_MAX];
704 /* The indexes of the first interfaces in the destinaiton interface list */
705 struct ecm_db_multicast_tuple_instance *ti; /* Multicast Connection instance */
706 bool to_mcast_interfaces_set; /* Flag to indicate if the destination interface list is currently empty or not */
707#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000708 /*
709 * Time values in seconds
710 */
711 struct ecm_db_timer_group_entry defunct_timer; /* Used to defunct the connection on inactivity */
712
713 /*
714 * Byte and packet counts
715 */
716 uint64_t from_data_total; /* Totals of data as sent by the 'from' side of this connection */
717 uint64_t to_data_total; /* Totals of data as sent by the 'to' side of this connection */
718 uint64_t from_packet_total; /* Totals of packets as sent by the 'from' side of this connection */
719 uint64_t to_packet_total; /* Totals of packets as sent by the 'to' side of this connection */
720 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 */
721 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 */
722 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 */
723 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 */
724
725 /*
726 * Classifiers attached to this connection
727 */
Ben Menchaca84f36632014-02-28 20:57:38 +0000728 struct ecm_classifier_instance *assignments; /* A list of all classifiers that are still assigned to this connection.
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000729 * When a connection is created, one instance of every type of classifier is assigned to the connection.
Ben Menchaca84f36632014-02-28 20:57:38 +0000730 * Classifiers are added in ascending order of priority - so the most important processes a packet last.
731 * Classifiers may drop out of this list (become unassigned) at any time.
732 */
733 struct ecm_classifier_instance *assignments_by_type[ECM_CLASSIFIER_TYPES];
734 /* All assignments are also recorded in this array, since there can be only one of each type, this array allows
735 * rapid retrieval of a classifier type, saving having to iterate the assignments list.
736 */
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000737
738#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100739 struct ecm_db_connection_classifier_type_assignment type_assignment[ECM_CLASSIFIER_TYPES];
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000740 /*
741 * Each classifier TYPE has a list of connections that are assigned to it.
742 * This permits a classifier TYPE to rapidly retrieve all connections associated with it.
743 */
744#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100745
Tushar Mathurd38cacd2015-07-28 12:19:10 +0530746 /*
747 * Re-generation.
748 * When system or classifier state changes, affected connections may need to have their state re-generated.
749 * This ensures that a connection does not continue to operate on stale state which could affect the sanity of acceleration rules.
750 * A connection needs to be re-generated when its regen_required is > 0.
751 * When a re-generation is completed successfully the counter is decremented.
752 * The counter ensures that any further changes of state while re-generation is under way is not missed.
753 * While a connection needs re-generation (regen_required > 0), acceleration should not be permitted.
754 * It may not always be practical to flag individual connections for re-generation (time consuming with large numbers of connections).
755 * The "generation" is a numerical counter comparison against the global "ecm_db_connection_generation".
756 * This ecm_db_connection_generation can be incremented causing a numerical difference between the connections counter and this global.
757 * This is enough to flag that a re-generation is needed.
758 * Further, it is possible that re-generation may be required DURING a rule construction. Since constructing a rule
759 * can require lengthy non-atomic processes there needs to be a way to ensure that changes during construction of a rule are caught.
760 * The regen_occurances is a counter that is incremented whenever regen_required is also incremented.
761 * However it is never decremented. This permits the caller to obtain this count before a non-atomic procedure and then afterwards.
762 * If there is any change in the counter value there is a change of generation! And the operation should be aborted.
763 */
764 bool regen_in_progress; /* The connection is under regeneration right now and is used to provide atomic re-generation in SMP */
765 uint16_t regen_required; /* The connection needs to be re-generated when > 0 */
766 uint16_t regen_occurances; /* Total number of regens required */
767 uint16_t generation; /* Used to detect when a re-evaluation of this connection is necessary by comparing with ecm_db_connection_generation */
768 uint32_t regen_success; /* Tracks how many times re-generation was successfully completed */
769 uint32_t regen_fail; /* Tracks how many times re-generation failed */
770
Ben Menchaca84f36632014-02-28 20:57:38 +0000771 struct ecm_front_end_connection_instance *feci; /* Front end instance specific to this connection */
772
Murat Sezgin7f6cdf62014-09-11 13:41:06 -0700773 ecm_db_connection_defunct_callback_t defunct; /* Callback to be called when connection has become defunct */
Ben Menchaca84f36632014-02-28 20:57:38 +0000774 ecm_db_connection_final_callback_t final; /* Callback to owner when object is destroyed */
775 void *arg; /* Argument returned to owner in callbacks */
776
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100777 uint32_t serial; /* RO: Serial number for the connection - unique for run lifetime */
Ben Menchaca84f36632014-02-28 20:57:38 +0000778 uint32_t flags;
779 int refs; /* Integer to trap we never go negative */
780#if (DEBUG_LEVEL > 0)
781 uint16_t magic;
782#endif
783};
784
785/*
786 * Connection flags
787 */
788#define ECM_DB_CONNECTION_FLAGS_INSERTED 1 /* Connection is inserted into connection database tables */
789
790/*
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530791 * struct ecm_db_listener_instance
Ben Menchaca84f36632014-02-28 20:57:38 +0000792 * listener instances
793 */
794struct ecm_db_listener_instance {
795 struct ecm_db_listener_instance *next;
796 struct ecm_db_listener_instance *event_next;
797 uint32_t flags;
798 void *arg;
799 int refs; /* Integer to trap we never go negative */
800 ecm_db_mapping_final_callback_t final; /* Final callback for this instance */
801
802 ecm_db_iface_listener_added_callback_t iface_added;
803 ecm_db_iface_listener_removed_callback_t iface_removed;
804 ecm_db_node_listener_added_callback_t node_added;
805 ecm_db_node_listener_removed_callback_t node_removed;
806 ecm_db_host_listener_added_callback_t host_added;
807 ecm_db_host_listener_removed_callback_t host_removed;
808 ecm_db_mapping_listener_added_callback_t mapping_added;
809 ecm_db_mapping_listener_removed_callback_t mapping_removed;
810 ecm_db_connection_listener_added_callback_t connection_added;
811 ecm_db_connection_listener_removed_callback_t connection_removed;
812#if (DEBUG_LEVEL > 0)
813 uint16_t magic;
814#endif
815};
816
817/*
818 * Listener flags
819 */
Gareth Williamsb5903892015-03-20 15:13:07 +0000820#define ECM_DB_LISTENER_FLAGS_INSERTED 1 /* Is inserted into database */
Ben Menchaca84f36632014-02-28 20:57:38 +0000821
Shyam Sunder1f037262015-05-18 20:04:13 +0530822#ifdef ECM_MULTICAST_ENABLE
823/*
824 * struct ecm_db_multicast_tuple_instance
825 * Tuple information for an accelerated multicast connection.
826 * This tuple information is further used to find an attached
827 * connection for the multicast flow.
828 */
829struct ecm_db_multicast_tuple_instance {
830 struct ecm_db_multicast_tuple_instance *next; /* Next instance in global list */
831 struct ecm_db_multicast_tuple_instance *prev; /* Previous instance in global list */
Shyam Sunder3af86a52015-08-28 18:04:10 +0530832 struct ecm_db_connection_instance *ci; /* Pointer to the DB Connection Instance */
Shyam Sunder1f037262015-05-18 20:04:13 +0530833 uint16_t src_port; /* RO: IPv4/v6 Source Port */
834 uint16_t dst_port; /* RO: IPv4/v6 Destination Port */
835 ip_addr_t src_ip; /* RO: IPv4/v6 Source Address */
836 ip_addr_t grp_ip; /* RO: IPv4/v6 Multicast Group Address */
837 uint32_t flags; /* Flags for this instance node */
838 uint32_t hash_index; /* Hash index of this node */
839 int proto; /* RO: Protocol */
840 int refs; /* Integer to trap we never go negative */
841#if (DEBUG_LEVEL > 0)
842 uint16_t magic; /* Magic value for debug */
843#endif
844};
845
846#define ECM_DB_MULTICAST_TUPLE_INSTANCE_HASH_SLOTS 16
847typedef uint32_t ecm_db_multicast_tuple_instance_hash_t;
848
849/*
850 * Multicast connection tuple table
851 * This table is used to lookup a complete tuple for multicast connections
852 * using the multicast group address
853 */
854static struct ecm_db_multicast_tuple_instance *ecm_db_multicast_tuple_instance_table[ECM_DB_MULTICAST_TUPLE_INSTANCE_HASH_SLOTS];
855#endif
856
Ben Menchaca84f36632014-02-28 20:57:38 +0000857/*
858 * Simple stats
859 */
Gareth Williamsf98d4192015-03-11 16:55:41 +0000860#define ECM_DB_PROTOCOL_COUNT 256
861static 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 +0000862
863/*
864 * Locking of the database - concurrency control
865 */
Murat Sezgin908ecb32015-05-10 20:54:36 -0700866static DEFINE_SPINLOCK(ecm_db_lock); /* Protect the table from SMP access. */
Ben Menchaca84f36632014-02-28 20:57:38 +0000867
868/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +0530869 * Connection state validity
870 * 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 +0000871 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +0530872static 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 +0000873
874/*
Murat Sezgin908ecb32015-05-10 20:54:36 -0700875 * Debugfs dentry object.
Ben Menchaca84f36632014-02-28 20:57:38 +0000876 */
Murat Sezgin908ecb32015-05-10 20:54:36 -0700877static struct dentry *ecm_db_dentry;
Ben Menchaca84f36632014-02-28 20:57:38 +0000878
879/*
880 * Management thread control
881 */
882static bool ecm_db_terminate_pending = false; /* When true the user has requested termination */
Ben Menchaca84f36632014-02-28 20:57:38 +0000883
884/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000885 * ecm_db_interface_type_names[]
886 * Array that maps the interface type to a string
887 */
888static char *ecm_db_interface_type_names[ECM_DB_IFACE_TYPE_COUNT] = {
889 "ETHERNET",
890 "PPPoE",
891 "LINK-AGGREGATION",
892 "VLAN",
893 "BRIDGE",
894 "LOOPBACK",
895 "IPSEC_TUNNEL",
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530896 "UNKNOWN",
Murat Sezginb3cc8792014-06-06 19:16:51 -0700897 "SIT",
898 "TUNIPIP6",
Shyam Sunder23f2e542015-09-28 14:56:49 +0530899 "PPPoL2TPV2",
900 "PPTP"
Ben Menchaca84f36632014-02-28 20:57:38 +0000901};
902
903/*
Gareth Williams54d15d92015-04-24 19:28:27 +0100904 * Random seed used during hash calculations
905 */
906static uint32_t ecm_db_jhash_rnd __read_mostly;
907
908/*
Murat Sezgince820c02017-09-29 09:32:44 -0700909 * Max work count for IPv6 route change event handler.
910 */
911#define ECM_DB_IP6ROUTE_MAX_WORK_COUNT 16
912
913/*
914 * IPv6 rount change event work counter.
915 */
916static atomic_t ecm_db_ip6route_work_count;
917
918/*
Gareth Williamsf28ba5f2015-02-13 11:07:28 +0000919 * ecm_db_connection_count_get()
920 * Return the connection count
921 */
922int ecm_db_connection_count_get(void)
923{
924 int count;
925
926 spin_lock_bh(&ecm_db_lock);
927 count = ecm_db_connection_count;
928 spin_unlock_bh(&ecm_db_lock);
929 return count;
930}
931EXPORT_SYMBOL(ecm_db_connection_count_get);
932
933/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000934 * ecm_db_interface_type_to_string()
935 * Return a string buffer containing the type name of the interface
936 */
937char *ecm_db_interface_type_to_string(ecm_db_iface_type_t type)
938{
939 DEBUG_ASSERT((type >= 0) && (type < ECM_DB_IFACE_TYPE_COUNT), "Invalid type: %d\n", type);
940 return ecm_db_interface_type_names[(int)type];
941}
942EXPORT_SYMBOL(ecm_db_interface_type_to_string);
943
944/*
Gareth Williamsf98d4192015-03-11 16:55:41 +0000945 * ecm_db_connection_count_by_protocol_get()
946 * Return # connections for the given protocol
947 */
948int ecm_db_connection_count_by_protocol_get(int protocol)
949{
950 int count;
951
952 DEBUG_ASSERT((protocol >= 0) && (protocol < ECM_DB_PROTOCOL_COUNT), "Bad protocol: %d\n", protocol);
953 spin_lock_bh(&ecm_db_lock);
954 count = ecm_db_connection_count_by_protocol[protocol];
955 spin_unlock_bh(&ecm_db_lock);
956 return count;
957}
958EXPORT_SYMBOL(ecm_db_connection_count_by_protocol_get);
959
960/*
Murat Sezgin91c5d712015-06-12 15:16:22 -0700961 * ecm_db_iface_ae_interface_identifier_get()
962 * Return the accel engine interface number of this ecm interface
Ben Menchaca84f36632014-02-28 20:57:38 +0000963 */
Murat Sezgin91c5d712015-06-12 15:16:22 -0700964int32_t ecm_db_iface_ae_interface_identifier_get(struct ecm_db_iface_instance *ii)
Ben Menchaca84f36632014-02-28 20:57:38 +0000965{
966 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
Murat Sezgin91c5d712015-06-12 15:16:22 -0700967 return ii->ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +0000968}
Murat Sezgin91c5d712015-06-12 15:16:22 -0700969EXPORT_SYMBOL(ecm_db_iface_ae_interface_identifier_get);
Ben Menchaca84f36632014-02-28 20:57:38 +0000970
971/*
Murat Sezgin5f2947a2016-06-28 12:09:33 -0700972 * ecm_db_iface_ae_interface_identifier_set()
973 * Sets accel engine interface number of this ecm interface
974 */
975void ecm_db_iface_ae_interface_identifier_set(struct ecm_db_iface_instance *ii, uint32_t num)
976{
977 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
978 ii->ae_interface_identifier = num;
979}
980EXPORT_SYMBOL(ecm_db_iface_ae_interface_identifier_set);
981
982/*
Kiran Kumar C. S. K451b62e2014-05-19 20:34:06 +0530983 * ecm_db_iface_interface_identifier_get()
984 * Return the interface number of this ecm interface
985 */
986int32_t ecm_db_iface_interface_identifier_get(struct ecm_db_iface_instance *ii)
987{
988 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
989 return ii->interface_identifier;
990}
991EXPORT_SYMBOL(ecm_db_iface_interface_identifier_get);
992
993/*
Murat Sezgin3aea6c92015-11-13 13:14:12 -0800994 * ecm_db_iface_interface_name_get()
995 * Return the interface name of this ecm interface
996 *
997 * name_buffer should be at least of size IFNAMSIZ
998 */
999void ecm_db_iface_interface_name_get(struct ecm_db_iface_instance *ii, char *name_buffer)
1000{
1001 DEBUG_CHECK_MAGIC(ii,
1002 ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
1003 strlcpy(name_buffer, ii->name, IFNAMSIZ);
1004}
1005EXPORT_SYMBOL(ecm_db_iface_interface_name_get);
1006
1007/*
Ben Menchaca84f36632014-02-28 20:57:38 +00001008 * ecm_db_iface_mtu_reset()
1009 * Reset the mtu
1010 */
1011int32_t ecm_db_iface_mtu_reset(struct ecm_db_iface_instance *ii, int32_t mtu)
1012{
1013 int32_t mtu_old;
1014 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
1015 spin_lock_bh(&ecm_db_lock);
1016 mtu_old = ii->mtu;
1017 ii->mtu = mtu;
1018 spin_unlock_bh(&ecm_db_lock);
1019 DEBUG_INFO("%p: Mtu change from %d to %d\n", ii, mtu_old, mtu);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301020
Ben Menchaca84f36632014-02-28 20:57:38 +00001021 return mtu_old;
1022}
1023EXPORT_SYMBOL(ecm_db_iface_mtu_reset);
1024
1025/*
1026 * ecm_db_connection_front_end_get_and_ref()
1027 * Return ref to the front end instance of the connection
1028 */
1029struct ecm_front_end_connection_instance *ecm_db_connection_front_end_get_and_ref(struct ecm_db_connection_instance *ci)
1030{
1031 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1032 ci->feci->ref(ci->feci);
1033 return ci->feci;
1034}
1035EXPORT_SYMBOL(ecm_db_connection_front_end_get_and_ref);
1036
1037/*
1038 * ecm_db_connection_defunct_callback()
1039 * Invoked by the expiration of the defunct_timer contained in a connection instance
1040 */
1041static void ecm_db_connection_defunct_callback(void *arg)
1042{
1043 struct ecm_db_connection_instance *ci = (struct ecm_db_connection_instance *)arg;
1044 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1045
1046 DEBUG_INFO("%p: defunct timer expired\n", ci);
Gareth Williams2bfb0b82015-01-15 16:31:15 +00001047
1048 if (ci->defunct) {
1049 ci->defunct(ci->feci);
1050 }
1051
Ben Menchaca84f36632014-02-28 20:57:38 +00001052 ecm_db_connection_deref(ci);
1053}
1054
1055/*
Murat Sezgin66fe22f2017-08-24 13:54:57 -07001056 * ecm_db_connection_elapsed_defunct_timer()
1057 * Returns the elapsed time of defunct timer.
1058 * If the timer is already expired and not removed from the database, the
1059 * function returns a negative value. The caller MUST handle this return value.
1060 */
1061int ecm_db_connection_elapsed_defunct_timer(struct ecm_db_connection_instance *ci)
1062{
1063 long int expires_in;
1064 int elapsed;
1065
1066 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1067
1068 /*
1069 * Do some sanity checks.
1070 * If it is not in a timer group, which means already expired, or the
1071 * connection has not been fully created yet. Just return 0.
1072 */
1073 spin_lock_bh(&ecm_db_lock);
1074 if (ci->defunct_timer.group == ECM_DB_TIMER_GROUPS_MAX) {
1075 spin_unlock_bh(&ecm_db_lock);
1076 return -1;
1077 }
1078
1079 /*
1080 * Already expired, but not removed from the database completely.
1081 */
1082 expires_in = (long int)(ci->defunct_timer.timeout - ecm_db_time);
1083 if (expires_in < 0) {
1084 spin_unlock_bh(&ecm_db_lock);
1085 return -1;
1086 }
1087
1088 elapsed = ecm_db_timer_groups[ci->defunct_timer.group].time - expires_in;
1089 spin_unlock_bh(&ecm_db_lock);
1090
1091 return elapsed;
1092}
1093EXPORT_SYMBOL(ecm_db_connection_elapsed_defunct_timer);
1094
1095/*
Ben Menchaca84f36632014-02-28 20:57:38 +00001096 * ecm_db_connection_defunct_timer_reset()
1097 * 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.
1098 */
1099bool ecm_db_connection_defunct_timer_reset(struct ecm_db_connection_instance *ci, ecm_db_timer_group_t tg)
1100{
1101 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1102 return ecm_db_timer_group_entry_reset(&ci->defunct_timer, tg);
1103}
1104EXPORT_SYMBOL(ecm_db_connection_defunct_timer_reset);
1105
1106/*
1107 * ecm_db_connection_defunct_timer_touch()
1108 * Update the connections defunct timer to stop it timing out. Returns false if the connection defunct timer has expired.
1109 */
1110bool ecm_db_connection_defunct_timer_touch(struct ecm_db_connection_instance *ci)
1111{
1112 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1113 return ecm_db_timer_group_entry_touch(&ci->defunct_timer);
1114}
1115EXPORT_SYMBOL(ecm_db_connection_defunct_timer_touch);
1116
1117/*
1118 * ecm_db_connection_timer_group_get()
1119 * Return the timer group id
1120 */
1121ecm_db_timer_group_t ecm_db_connection_timer_group_get(struct ecm_db_connection_instance *ci)
1122{
1123 ecm_db_timer_group_t tg;
1124 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1125
1126 spin_lock_bh(&ecm_db_lock);
1127 tg = ci->defunct_timer.group;
1128 spin_unlock_bh(&ecm_db_lock);
1129 return tg;
1130}
1131EXPORT_SYMBOL(ecm_db_connection_timer_group_get);
1132
1133/*
1134 * ecm_db_connection_make_defunct()
1135 * Make connection defunct.
1136 */
1137void ecm_db_connection_make_defunct(struct ecm_db_connection_instance *ci)
1138{
Murat Sezgin56fa15a2017-08-25 17:45:38 -07001139 struct ecm_front_end_connection_instance *feci;
1140 ecm_front_end_acceleration_mode_t accel_mode;
1141
Ben Menchaca84f36632014-02-28 20:57:38 +00001142 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07001143
1144 if (ci->defunct) {
1145 ci->defunct(ci->feci);
1146 }
1147
Murat Sezgin56fa15a2017-08-25 17:45:38 -07001148 feci = ecm_db_connection_front_end_get_and_ref(ci);
1149 accel_mode = feci->accel_state_get(feci);
1150 feci->deref(feci);
1151
1152 /*
1153 * It is possible that the defunct process fails and re-try is in progress.
1154 * In that case, the connection's defunct timer is reset to defunct re-try
1155 * timeout value and the connection waits for the next defunct call. So, we
1156 * should remove the timer from the timer group, if the re-acceleration for this
1157 * connection is not possible which means "decel pending" or one of the
1158 * "accel fail" modes. Otherwise, the timer will be removed and re-try will not happen.
1159 */
1160 if (ECM_FRONT_END_ACCELERATION_NOT_POSSIBLE(accel_mode)) {
1161 if (ecm_db_timer_group_entry_remove(&ci->defunct_timer)) {
1162 ecm_db_connection_deref(ci);
1163 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001164 }
1165}
1166EXPORT_SYMBOL(ecm_db_connection_make_defunct);
1167
1168/*
1169 * ecm_db_connection_data_totals_update()
1170 * Update the total data (and packets) sent/received by the given host
1171 */
1172void ecm_db_connection_data_totals_update(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
1173{
Murat Sezginf6814bc2015-08-20 11:31:41 -07001174 int32_t i;
1175
Ben Menchaca84f36632014-02-28 20:57:38 +00001176 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
1177
1178 spin_lock_bh(&ecm_db_lock);
1179
1180 if (is_from) {
1181 /*
1182 * Update totals sent by the FROM side of connection
1183 */
1184 ci->from_data_total += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001185 ci->from_packet_total += packets;
1186#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001187 ci->mapping_from->from_data_total += size;
1188 ci->mapping_from->host->from_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001189 ci->from_node->from_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001190 ci->mapping_from->from_packet_total += packets;
1191 ci->mapping_from->host->from_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001192 ci->from_node->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001193
1194 /*
1195 * Data from the host is essentially TO the interface on which the host is reachable
1196 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001197 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1198 ci->from_interfaces[i]->to_data_total += size;
1199 ci->from_interfaces[i]->to_packet_total += packets;
1200 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001201
1202 /*
1203 * Update totals sent TO the other side of the connection
1204 */
1205 ci->mapping_to->to_data_total += size;
1206 ci->mapping_to->host->to_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001207 ci->to_node->to_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001208 ci->mapping_to->to_packet_total += packets;
1209 ci->mapping_to->host->to_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001210 ci->to_node->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001211
1212 /*
1213 * Sending to the other side means FROM the interface we reach that host
1214 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001215 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1216 ci->to_interfaces[i]->from_data_total += size;
1217 ci->to_interfaces[i]->from_packet_total += packets;
1218 }
Gareth Williams85331c92015-03-11 20:39:18 +00001219#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001220 spin_unlock_bh(&ecm_db_lock);
1221 return;
1222 }
1223
1224 /*
1225 * Update totals sent by the TO side of this connection
1226 */
1227 ci->to_data_total += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001228 ci->to_packet_total += packets;
1229#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001230 ci->mapping_to->from_data_total += size;
1231 ci->mapping_to->host->from_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001232 ci->to_node->from_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001233 ci->mapping_to->from_packet_total += packets;
1234 ci->mapping_to->host->from_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001235 ci->to_node->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001236
1237 /*
1238 * Data from the host is essentially TO the interface on which the host is reachable
1239 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001240 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1241 ci->to_interfaces[i]->to_data_total += size;
1242 ci->to_interfaces[i]->to_packet_total += packets;
1243 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001244
1245 /*
1246 * Update totals sent TO the other side of the connection
1247 */
1248 ci->mapping_from->to_data_total += size;
1249 ci->mapping_from->host->to_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001250 ci->from_node->to_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001251 ci->mapping_from->to_packet_total += packets;
1252 ci->mapping_from->host->to_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001253 ci->from_node->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001254
1255 /*
1256 * Sending to the other side means FROM the interface we reach that host
1257 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001258 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1259 ci->from_interfaces[i]->from_data_total += size;
1260 ci->from_interfaces[i]->from_packet_total += packets;
1261 }
Gareth Williams85331c92015-03-11 20:39:18 +00001262#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001263 spin_unlock_bh(&ecm_db_lock);
1264}
1265EXPORT_SYMBOL(ecm_db_connection_data_totals_update);
1266
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301267#ifdef ECM_MULTICAST_ENABLE
1268/*
1269 * ecm_db_multicast_connection_data_totals_update()
1270 * Update the total bytes and packets sent/received by the multicast connection
1271 * TODO: This function is almost similar to unicast connection_data_totals_update() except few
1272 * lines of code. The next merge should have a common logic for both unicast and multicast.
1273 */
1274void ecm_db_multicast_connection_data_totals_update(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
1275{
Murat Sezginf6814bc2015-08-20 11:31:41 -07001276 int32_t i;
1277
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301278 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
1279
1280 spin_lock_bh(&ecm_db_lock);
1281
1282 if (is_from) {
1283 /*
1284 * Update totals sent by the FROM side of connection
1285 */
1286 ci->from_data_total += size;
1287 ci->from_packet_total += packets;
1288#ifdef ECM_DB_ADVANCED_STATS_ENABLE
1289 ci->mapping_from->from_data_total += size;
1290 ci->mapping_from->host->from_data_total += size;
1291 ci->from_node->from_data_total += size;
1292 ci->mapping_from->from_packet_total += packets;
1293 ci->mapping_from->host->from_packet_total += packets;
1294 ci->from_node->from_packet_total += packets;
1295
1296 /*
1297 * Data from the host is essentially TO the interface on which the host is reachable
1298 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001299 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1300 ci->from_interfaces[i]->to_data_total += size;
1301 ci->from_interfaces[i]->to_packet_total += packets;
1302 }
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301303
1304 /*
1305 * Update totals sent TO the other side of the connection
1306 */
1307 ci->mapping_to->to_data_total += size;
1308 ci->mapping_to->host->to_data_total += size;
1309 ci->to_node->to_data_total += size;
1310 ci->mapping_to->to_packet_total += packets;
1311 ci->mapping_to->host->to_packet_total += packets;
1312 ci->to_node->to_packet_total += packets;
1313#endif
1314 spin_unlock_bh(&ecm_db_lock);
1315 return;
1316 }
1317
1318 /*
1319 * Update totals sent by the TO side of this connection
1320 */
1321 ci->to_data_total += size;
1322 ci->to_packet_total += packets;
1323#ifdef ECM_DB_ADVANCED_STATS_ENABLE
1324 ci->mapping_to->from_data_total += size;
1325 ci->mapping_to->host->from_data_total += size;
1326 ci->to_node->from_data_total += size;
1327 ci->mapping_to->from_packet_total += packets;
1328 ci->mapping_to->host->from_packet_total += packets;
1329 ci->to_node->from_packet_total += packets;
1330
1331 /*
1332 * Update totals sent TO the other side of the connection
1333 */
1334 ci->mapping_from->to_data_total += size;
1335 ci->mapping_from->host->to_data_total += size;
1336 ci->from_node->to_data_total += size;
1337 ci->mapping_from->to_packet_total += packets;
1338 ci->mapping_from->host->to_packet_total += packets;
1339 ci->from_node->to_packet_total += packets;
1340
1341 /*
1342 * Sending to the other side means FROM the interface we reach that host
1343 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001344 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1345 ci->from_interfaces[i]->from_data_total += size;
1346 ci->from_interfaces[i]->from_packet_total += packets;
1347 }
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301348#endif
1349 spin_unlock_bh(&ecm_db_lock);
1350}
1351EXPORT_SYMBOL(ecm_db_multicast_connection_data_totals_update);
1352
1353/*
1354 * ecm_db_multicast_connection_interface_heirarchy_stats_update()
1355 * Traverse through the multicast destination interface heirarchy and update the stats (data and packets).
1356 */
1357void ecm_db_multicast_connection_interface_heirarchy_stats_update(struct ecm_db_connection_instance *ci, uint64_t size, uint64_t packets)
1358{
1359 struct ecm_db_iface_instance *to_mc_ifaces;
1360 struct ecm_db_iface_instance *ii;
1361 struct ecm_db_iface_instance **ifaces;
1362 struct ecm_db_iface_instance *ii_temp;
1363 int32_t *to_mc_ifaces_first;
1364 int heirarchy_index;
1365 int ret;
1366
1367 ret = ecm_db_multicast_connection_to_interfaces_get_and_ref_all(ci, &to_mc_ifaces, &to_mc_ifaces_first);
1368 if (ret == 0) {
1369 DEBUG_WARN("%p: no interfaces in to_multicast_interfaces list!\n", ci);
1370 return;
1371 }
1372
1373 spin_lock_bh(&ecm_db_lock);
1374 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
1375
1376 if (to_mc_ifaces_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
1377 ii_temp = ecm_db_multicast_if_heirarchy_get(to_mc_ifaces, heirarchy_index);
1378 ii_temp = ecm_db_multicast_if_instance_get_at_index(ii_temp, ECM_DB_IFACE_HEIRARCHY_MAX - 1);
1379 ifaces = (struct ecm_db_iface_instance **)ii_temp;
1380 ii = *ifaces;
1381 ii->to_data_total += size;
1382 ii->to_packet_total += packets;
1383 }
1384 }
1385 spin_unlock_bh(&ecm_db_lock);
1386
1387 ecm_db_multicast_connection_to_interfaces_deref_all(to_mc_ifaces, to_mc_ifaces_first);
1388}
1389EXPORT_SYMBOL(ecm_db_multicast_connection_interface_heirarchy_stats_update);
1390#endif
1391
Ben Menchaca84f36632014-02-28 20:57:38 +00001392/*
1393 * ecm_db_connection_data_totals_update_dropped()
1394 * Update the total data (and packets) sent by the given host but which we dropped
1395 */
1396void ecm_db_connection_data_totals_update_dropped(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
1397{
Murat Sezginf6814bc2015-08-20 11:31:41 -07001398 int32_t i;
1399
Ben Menchaca84f36632014-02-28 20:57:38 +00001400 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
1401
1402 if (is_from) {
1403 /*
1404 * Update dropped totals sent by the FROM side
1405 */
1406 spin_lock_bh(&ecm_db_lock);
1407 ci->from_data_total_dropped += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001408 ci->from_packet_total_dropped += packets;
1409#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001410 ci->mapping_from->from_data_total_dropped += size;
1411 ci->mapping_from->host->from_data_total_dropped += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001412 ci->from_node->from_data_total_dropped += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001413 ci->mapping_from->from_packet_total_dropped += packets;
1414 ci->mapping_from->host->from_packet_total_dropped += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001415 ci->from_node->from_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001416
1417 /*
1418 * Data from the host is essentially TO the interface on which the host is reachable
1419 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001420 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1421 ci->from_interfaces[i]->to_data_total_dropped += size;
1422 ci->from_interfaces[i]->to_packet_total_dropped += packets;
1423 }
Gareth Williams85331c92015-03-11 20:39:18 +00001424#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001425 spin_unlock_bh(&ecm_db_lock);
1426 return;
1427 }
1428
1429 /*
1430 * Update dropped totals sent by the TO side of this connection
1431 */
1432 spin_lock_bh(&ecm_db_lock);
1433 ci->to_data_total_dropped += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001434 ci->to_packet_total_dropped += packets;
1435#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001436 ci->mapping_to->from_data_total_dropped += size;
1437 ci->mapping_to->host->from_data_total_dropped += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001438 ci->to_node->from_data_total_dropped += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001439 ci->mapping_to->from_packet_total_dropped += packets;
1440 ci->mapping_to->host->from_packet_total_dropped += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001441 ci->to_node->from_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001442
1443 /*
1444 * Data from the host is essentially TO the interface on which the host is reachable
1445 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001446 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1447 ci->to_interfaces[i]->to_data_total_dropped += size;
1448 ci->to_interfaces[i]->to_packet_total_dropped += packets;
1449 }
Gareth Williams85331c92015-03-11 20:39:18 +00001450#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001451 spin_unlock_bh(&ecm_db_lock);
1452}
1453EXPORT_SYMBOL(ecm_db_connection_data_totals_update_dropped);
1454
1455/*
1456 * ecm_db_connection_data_stats_get()
1457 * Return data stats for the instance
1458 */
1459void ecm_db_connection_data_stats_get(struct ecm_db_connection_instance *ci, uint64_t *from_data_total, uint64_t *to_data_total,
1460 uint64_t *from_packet_total, uint64_t *to_packet_total,
1461 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1462 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1463{
1464 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1465
1466 spin_lock_bh(&ecm_db_lock);
1467 if (from_data_total) {
1468 *from_data_total = ci->from_data_total;
1469 }
1470 if (to_data_total) {
1471 *to_data_total = ci->to_data_total;
1472 }
1473 if (from_packet_total) {
1474 *from_packet_total = ci->from_packet_total;
1475 }
1476 if (to_packet_total) {
1477 *to_packet_total = ci->to_packet_total;
1478 }
1479 if (from_data_total_dropped) {
1480 *from_data_total_dropped = ci->from_data_total_dropped;
1481 }
1482 if (to_data_total_dropped) {
1483 *to_data_total_dropped = ci->to_data_total_dropped;
1484 }
1485 if (from_packet_total_dropped) {
1486 *from_packet_total_dropped = ci->from_packet_total_dropped;
1487 }
1488 if (to_packet_total_dropped) {
1489 *to_packet_total_dropped = ci->to_packet_total_dropped;
1490 }
1491 spin_unlock_bh(&ecm_db_lock);
1492}
1493EXPORT_SYMBOL(ecm_db_connection_data_stats_get);
1494
Gareth Williams85331c92015-03-11 20:39:18 +00001495#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001496/*
1497 * ecm_db_mapping_data_stats_get()
1498 * Return data stats for the instance
1499 */
1500void ecm_db_mapping_data_stats_get(struct ecm_db_mapping_instance *mi, uint64_t *from_data_total, uint64_t *to_data_total,
1501 uint64_t *from_packet_total, uint64_t *to_packet_total,
1502 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1503 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1504{
1505 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
1506 spin_lock_bh(&ecm_db_lock);
1507 if (from_data_total) {
1508 *from_data_total = mi->from_data_total;
1509 }
1510 if (to_data_total) {
1511 *to_data_total = mi->to_data_total;
1512 }
1513 if (from_packet_total) {
1514 *from_packet_total = mi->from_packet_total;
1515 }
1516 if (to_packet_total) {
1517 *to_packet_total = mi->to_packet_total;
1518 }
1519 if (from_data_total_dropped) {
1520 *from_data_total_dropped = mi->from_data_total_dropped;
1521 }
1522 if (to_data_total_dropped) {
1523 *to_data_total_dropped = mi->to_data_total_dropped;
1524 }
1525 if (from_packet_total_dropped) {
1526 *from_packet_total_dropped = mi->from_packet_total_dropped;
1527 }
1528 if (to_packet_total_dropped) {
1529 *to_packet_total_dropped = mi->to_packet_total_dropped;
1530 }
1531 spin_unlock_bh(&ecm_db_lock);
1532}
1533EXPORT_SYMBOL(ecm_db_mapping_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001534#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001535
Gareth Williams85331c92015-03-11 20:39:18 +00001536#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001537/*
1538 * ecm_db_host_data_stats_get()
1539 * Return data stats for the instance
1540 */
1541void ecm_db_host_data_stats_get(struct ecm_db_host_instance *hi, uint64_t *from_data_total, uint64_t *to_data_total,
1542 uint64_t *from_packet_total, uint64_t *to_packet_total,
1543 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1544 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1545{
1546 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
1547 spin_lock_bh(&ecm_db_lock);
1548 if (from_data_total) {
1549 *from_data_total = hi->from_data_total;
1550 }
1551 if (to_data_total) {
1552 *to_data_total = hi->to_data_total;
1553 }
1554 if (from_packet_total) {
1555 *from_packet_total = hi->from_packet_total;
1556 }
1557 if (to_packet_total) {
1558 *to_packet_total = hi->to_packet_total;
1559 }
1560 if (from_data_total_dropped) {
1561 *from_data_total_dropped = hi->from_data_total_dropped;
1562 }
1563 if (to_data_total_dropped) {
1564 *to_data_total_dropped = hi->to_data_total_dropped;
1565 }
1566 if (from_packet_total_dropped) {
1567 *from_packet_total_dropped = hi->from_packet_total_dropped;
1568 }
1569 if (to_packet_total_dropped) {
1570 *to_packet_total_dropped = hi->to_packet_total_dropped;
1571 }
1572 spin_unlock_bh(&ecm_db_lock);
1573}
1574EXPORT_SYMBOL(ecm_db_host_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001575#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001576
Gareth Williams85331c92015-03-11 20:39:18 +00001577#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001578/*
1579 * ecm_db_node_data_stats_get()
1580 * Return data stats for the instance
1581 */
1582void ecm_db_node_data_stats_get(struct ecm_db_node_instance *ni, uint64_t *from_data_total, uint64_t *to_data_total,
1583 uint64_t *from_packet_total, uint64_t *to_packet_total,
1584 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1585 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1586{
1587 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
1588 spin_lock_bh(&ecm_db_lock);
1589 if (from_data_total) {
1590 *from_data_total = ni->from_data_total;
1591 }
1592 if (to_data_total) {
1593 *to_data_total = ni->to_data_total;
1594 }
1595 if (from_packet_total) {
1596 *from_packet_total = ni->from_packet_total;
1597 }
1598 if (to_packet_total) {
1599 *to_packet_total = ni->to_packet_total;
1600 }
1601 if (from_data_total_dropped) {
1602 *from_data_total_dropped = ni->from_data_total_dropped;
1603 }
1604 if (to_data_total_dropped) {
1605 *to_data_total_dropped = ni->to_data_total_dropped;
1606 }
1607 if (from_packet_total_dropped) {
1608 *from_packet_total_dropped = ni->from_packet_total_dropped;
1609 }
1610 if (to_packet_total_dropped) {
1611 *to_packet_total_dropped = ni->to_packet_total_dropped;
1612 }
1613 spin_unlock_bh(&ecm_db_lock);
1614}
1615EXPORT_SYMBOL(ecm_db_node_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001616#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001617
Gareth Williams85331c92015-03-11 20:39:18 +00001618#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001619/*
1620 * ecm_db_iface_data_stats_get()
1621 * Return data stats for the instance
1622 */
1623void ecm_db_iface_data_stats_get(struct ecm_db_iface_instance *ii, uint64_t *from_data_total, uint64_t *to_data_total,
1624 uint64_t *from_packet_total, uint64_t *to_packet_total,
1625 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1626 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1627{
1628 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
1629 spin_lock_bh(&ecm_db_lock);
1630 if (from_data_total) {
1631 *from_data_total = ii->from_data_total;
1632 }
1633 if (to_data_total) {
1634 *to_data_total = ii->to_data_total;
1635 }
1636 if (from_packet_total) {
1637 *from_packet_total = ii->from_packet_total;
1638 }
1639 if (to_packet_total) {
1640 *to_packet_total = ii->to_packet_total;
1641 }
1642 if (from_data_total_dropped) {
1643 *from_data_total_dropped = ii->from_data_total_dropped;
1644 }
1645 if (to_data_total_dropped) {
1646 *to_data_total_dropped = ii->to_data_total_dropped;
1647 }
1648 if (from_packet_total_dropped) {
1649 *from_packet_total_dropped = ii->from_packet_total_dropped;
1650 }
1651 if (to_packet_total_dropped) {
1652 *to_packet_total_dropped = ii->to_packet_total_dropped;
1653 }
1654 spin_unlock_bh(&ecm_db_lock);
1655}
1656EXPORT_SYMBOL(ecm_db_iface_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001657#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001658
1659/*
1660 * ecm_db_connection_serial_get()
1661 * Return serial
1662 */
1663uint32_t ecm_db_connection_serial_get(struct ecm_db_connection_instance *ci)
1664{
1665 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1666 return ci->serial;
1667}
1668EXPORT_SYMBOL(ecm_db_connection_serial_get);
1669
1670/*
1671 * ecm_db_connection_from_address_get()
1672 * Return ip address address
1673 */
1674void ecm_db_connection_from_address_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1675{
1676 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1677 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1678 DEBUG_CHECK_MAGIC(ci->mapping_from->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from->host);
1679 ECM_IP_ADDR_COPY(addr, ci->mapping_from->host->address);
1680}
1681EXPORT_SYMBOL(ecm_db_connection_from_address_get);
1682
1683/*
1684 * ecm_db_connection_from_address_nat_get()
1685 * Return NAT ip address address
1686 */
1687void ecm_db_connection_from_address_nat_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1688{
1689 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1690 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1691 DEBUG_CHECK_MAGIC(ci->mapping_from->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from->host);
1692 ECM_IP_ADDR_COPY(addr, ci->mapping_nat_from->host->address);
1693}
1694EXPORT_SYMBOL(ecm_db_connection_from_address_nat_get);
1695
1696/*
1697 * ecm_db_connection_to_address_get()
1698 * Return ip address address
1699 */
1700void ecm_db_connection_to_address_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1701{
1702 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1703 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1704 DEBUG_CHECK_MAGIC(ci->mapping_to->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to->host);
1705 ECM_IP_ADDR_COPY(addr, ci->mapping_to->host->address);
1706}
1707EXPORT_SYMBOL(ecm_db_connection_to_address_get);
1708
1709/*
1710 * ecm_db_connection_to_address_nat_get()
1711 * Return NAT ip address address
1712 */
1713void ecm_db_connection_to_address_nat_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1714{
1715 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1716 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1717 DEBUG_CHECK_MAGIC(ci->mapping_to->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to->host);
1718 ECM_IP_ADDR_COPY(addr, ci->mapping_nat_to->host->address);
1719}
1720EXPORT_SYMBOL(ecm_db_connection_to_address_nat_get);
1721
1722/*
1723 * ecm_db_connection_to_port_get()
1724 * Return port
1725 */
1726int ecm_db_connection_to_port_get(struct ecm_db_connection_instance *ci)
1727{
1728 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1729 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1730 return ci->mapping_to->port;
1731}
1732EXPORT_SYMBOL(ecm_db_connection_to_port_get);
1733
1734/*
1735 * ecm_db_connection_to_port_nat_get()
1736 * Return port
1737 */
1738int ecm_db_connection_to_port_nat_get(struct ecm_db_connection_instance *ci)
1739{
1740 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1741 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1742 return ci->mapping_nat_to->port;
1743}
1744EXPORT_SYMBOL(ecm_db_connection_to_port_nat_get);
1745
1746/*
1747 * ecm_db_connection_from_port_get()
1748 * Return port
1749 */
1750int ecm_db_connection_from_port_get(struct ecm_db_connection_instance *ci)
1751{
1752 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1753 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1754 return ci->mapping_from->port;
1755}
1756EXPORT_SYMBOL(ecm_db_connection_from_port_get);
1757
1758/*
1759 * ecm_db_connection_from_port_nat_get()
1760 * Return port
1761 */
1762int ecm_db_connection_from_port_nat_get(struct ecm_db_connection_instance *ci)
1763{
1764 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1765 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1766 return ci->mapping_nat_from->port;
1767}
1768EXPORT_SYMBOL(ecm_db_connection_from_port_nat_get);
1769
1770/*
1771 * ecm_db_connection_to_node_address_get()
1772 * Return address of the node used when sending packets to the 'to' side.
1773 */
1774void ecm_db_connection_to_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1775{
1776 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001777 memcpy(address_buffer, ci->to_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001778}
1779EXPORT_SYMBOL(ecm_db_connection_to_node_address_get);
1780
1781/*
1782 * ecm_db_connection_from_node_address_get()
1783 * Return address of the node used when sending packets to the 'from' side.
1784 */
1785void ecm_db_connection_from_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1786{
1787 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001788 memcpy(address_buffer, ci->from_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001789}
1790EXPORT_SYMBOL(ecm_db_connection_from_node_address_get);
1791
1792/*
1793 * ecm_db_connection_to_nat_node_address_get()
1794 * Return address of the node used when sending packets to the 'to' NAT side.
1795 */
1796void ecm_db_connection_to_nat_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1797{
1798 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001799 memcpy(address_buffer, ci->to_nat_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001800}
1801EXPORT_SYMBOL(ecm_db_connection_to_nat_node_address_get);
1802
1803/*
1804 * ecm_db_connection_from_nat_node_address_get()
1805 * Return address of the node used when sending packets to the 'from' NAT side.
1806 */
1807void ecm_db_connection_from_nat_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1808{
1809 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001810 memcpy(address_buffer, ci->from_nat_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001811}
1812EXPORT_SYMBOL(ecm_db_connection_from_nat_node_address_get);
1813
1814/*
1815 * ecm_db_connection_to_iface_name_get()
1816 * Return name of interface on which the 'to' side may be reached
1817 */
1818void ecm_db_connection_to_iface_name_get(struct ecm_db_connection_instance *ci, char *name_buffer)
1819{
1820 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001821 strcpy(name_buffer, ci->to_node->iface->name);
Ben Menchaca84f36632014-02-28 20:57:38 +00001822}
1823EXPORT_SYMBOL(ecm_db_connection_to_iface_name_get);
1824
1825/*
1826 * ecm_db_connection_from_iface_name_get()
1827 * Return name of interface on which the 'from' side may be reached
1828 */
1829void ecm_db_connection_from_iface_name_get(struct ecm_db_connection_instance *ci, char *name_buffer)
1830{
1831 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001832 strcpy(name_buffer, ci->from_node->iface->name);
Ben Menchaca84f36632014-02-28 20:57:38 +00001833}
1834EXPORT_SYMBOL(ecm_db_connection_from_iface_name_get);
1835
1836/*
1837 * ecm_db_connection_to_iface_mtu_get()
1838 * Return MTU of interface on which the 'to' side may be reached
1839 */
1840int ecm_db_connection_to_iface_mtu_get(struct ecm_db_connection_instance *ci)
1841{
1842 int mtu;
1843 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1844 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001845 mtu = ci->to_node->iface->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00001846 spin_unlock_bh(&ecm_db_lock);
1847 return mtu;
1848}
1849EXPORT_SYMBOL(ecm_db_connection_to_iface_mtu_get);
1850
1851/*
1852 * ecm_db_connection_to_iface_type_get()
1853 * Return type of interface on which the 'to' side may be reached
1854 */
1855ecm_db_iface_type_t ecm_db_connection_to_iface_type_get(struct ecm_db_connection_instance *ci)
1856{
1857 ecm_db_iface_type_t type;
1858
1859 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1860 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001861 type = ci->to_node->iface->type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001862 spin_unlock_bh(&ecm_db_lock);
1863 return type;
1864}
1865EXPORT_SYMBOL(ecm_db_connection_to_iface_type_get);
1866
1867/*
1868 * ecm_db_connection_from_iface_mtu_get()
1869 * Return MTU of interface on which the 'from' side may be reached
1870 */
1871int ecm_db_connection_from_iface_mtu_get(struct ecm_db_connection_instance *ci)
1872{
1873 int mtu;
1874 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1875 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001876 mtu = ci->from_node->iface->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00001877 spin_unlock_bh(&ecm_db_lock);
1878 return mtu;
1879}
1880EXPORT_SYMBOL(ecm_db_connection_from_iface_mtu_get);
1881
1882/*
1883 * ecm_db_connection_from_iface_type_get()
1884 * Return type of interface on which the 'from' side may be reached
1885 */
1886ecm_db_iface_type_t ecm_db_connection_from_iface_type_get(struct ecm_db_connection_instance *ci)
1887{
1888 ecm_db_iface_type_t type;
1889
1890 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1891 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001892 type = ci->from_node->iface->type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001893 spin_unlock_bh(&ecm_db_lock);
1894 return type;
1895}
1896EXPORT_SYMBOL(ecm_db_connection_from_iface_type_get);
1897
1898/*
1899 * ecm_db_connection_iface_type_get()
1900 * Return type of interface
1901 */
1902ecm_db_iface_type_t ecm_db_connection_iface_type_get(struct ecm_db_iface_instance *ii)
1903{
1904 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
1905 return ii->type;
1906}
1907EXPORT_SYMBOL(ecm_db_connection_iface_type_get);
1908
1909/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301910 * ecm_db_connection_regeneration_occurrances_get()
1911 * Get the number of regeneration occurrances that have occurred since the connection was created.
Ben Menchaca84f36632014-02-28 20:57:38 +00001912 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301913uint16_t ecm_db_connection_regeneration_occurrances_get(struct ecm_db_connection_instance *ci)
1914{
1915 uint16_t occurances;
1916 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1917
1918 spin_lock_bh(&ecm_db_lock);
1919 occurances = ci->regen_occurances;
1920 spin_unlock_bh(&ecm_db_lock);
1921 return occurances;
1922}
1923EXPORT_SYMBOL(ecm_db_connection_regeneration_occurrances_get);
1924
1925/*
1926 * ecm_db_conection_regeneration_completed()
1927 * Re-generation was completed successfully
1928 */
1929void ecm_db_conection_regeneration_completed(struct ecm_db_connection_instance *ci)
Ben Menchaca84f36632014-02-28 20:57:38 +00001930{
1931 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1932
1933 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301934
1935 DEBUG_ASSERT(ci->regen_in_progress, "%p: Bad call", ci);
1936 DEBUG_ASSERT(ci->regen_required > 0, "%p: Bad call", ci);
1937
1938 /*
1939 * Decrement the required counter by 1.
1940 * This may mean that regeneration is still required due to another change occuring _during_ re-generation.
1941 */
1942 ci->regen_required--;
1943 ci->regen_in_progress = false;
1944 ci->regen_success++;
1945 spin_unlock_bh(&ecm_db_lock);
1946}
1947EXPORT_SYMBOL(ecm_db_conection_regeneration_completed);
1948
1949/*
1950 * ecm_db_conection_regeneration_failed()
1951 * Re-generation failed
1952 */
1953void ecm_db_conection_regeneration_failed(struct ecm_db_connection_instance *ci)
1954{
1955 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1956
1957 spin_lock_bh(&ecm_db_lock);
1958
1959 DEBUG_ASSERT(ci->regen_in_progress, "%p: Bad call", ci);
1960 DEBUG_ASSERT(ci->regen_required > 0, "%p: Bad call", ci);
1961
1962 /*
1963 * Re-generation is no longer in progress BUT we leave the regen
1964 * counter as it is so as to indicate re-generation is still needed
1965 */
1966 ci->regen_in_progress = false;
1967 ci->regen_fail++;
1968 spin_unlock_bh(&ecm_db_lock);
1969}
1970EXPORT_SYMBOL(ecm_db_conection_regeneration_failed);
1971
1972/*
1973 * ecm_db_connection_regeneration_required_check()
1974 * Returns true if the connection needs to be re-generated.
1975 *
1976 * If re-generation is needed this will mark the connection to indicate that re-generation is needed AND in progress.
1977 * If the return code is TRUE the caller MUST handle the re-generation.
1978 * Upon re-generation completion you must call ecm_db_conection_regeneration_completed() or ecm_db_conection_regeneration_failed().
1979 */
1980bool ecm_db_connection_regeneration_required_check(struct ecm_db_connection_instance *ci)
1981{
1982 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1983
1984 /*
1985 * Check the global generation counter for changes
1986 */
1987 spin_lock_bh(&ecm_db_lock);
1988 if (ci->generation != ecm_db_connection_generation) {
1989 /*
1990 * Re-generation is needed
1991 */
1992 ci->regen_occurances++;
1993 ci->regen_required++;
1994
1995 /*
1996 * Record that we have seen this change
1997 */
1998 ci->generation = ecm_db_connection_generation;
1999 }
2000
2001 /*
2002 * If re-generation is in progress then something is handling re-generation already
2003 * so we tell the caller that it cannot handle re-generation.
2004 */
2005 if (ci->regen_in_progress) {
Ben Menchaca84f36632014-02-28 20:57:38 +00002006 spin_unlock_bh(&ecm_db_lock);
2007 return false;
2008 }
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302009
2010 /*
2011 * Is re-generation required?
2012 */
2013 if (ci->regen_required == 0) {
2014 spin_unlock_bh(&ecm_db_lock);
2015 return false;
2016 }
2017
2018 /*
2019 * Flag that re-generation is in progress and tell the caller to handle re-generation
2020 */
2021 ci->regen_in_progress = true;
Ben Menchaca84f36632014-02-28 20:57:38 +00002022 spin_unlock_bh(&ecm_db_lock);
2023 return true;
2024}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302025EXPORT_SYMBOL(ecm_db_connection_regeneration_required_check);
Ben Menchaca84f36632014-02-28 20:57:38 +00002026
2027/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302028 * ecm_db_connection_regeneration_required_peek()
2029 * Returns true if the connection needs to be regenerated.
Ben Menchaca84f36632014-02-28 20:57:38 +00002030 *
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302031 * NOTE: The caller MUST NOT handle re-generation, the caller may use this indication
2032 * to determine the sanity of the connection state and whether acceleration is permitted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002033 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302034bool ecm_db_connection_regeneration_required_peek(struct ecm_db_connection_instance *ci)
Ben Menchaca84f36632014-02-28 20:57:38 +00002035{
2036 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2037
2038 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302039
2040 /*
2041 * Check the global generation counter for changes (record any change now)
2042 */
2043 if (ci->generation != ecm_db_connection_generation) {
2044 /*
2045 * Re-generation is needed, flag the connection as needing re-generation now.
2046 */
2047 ci->regen_occurances++;
2048 ci->regen_required++;
2049
2050 /*
2051 * Record that we have seen this change
2052 */
2053 ci->generation = ecm_db_connection_generation;
2054 }
2055 if (ci->regen_required == 0) {
Ben Menchaca84f36632014-02-28 20:57:38 +00002056 spin_unlock_bh(&ecm_db_lock);
2057 return false;
2058 }
2059 spin_unlock_bh(&ecm_db_lock);
2060 return true;
2061}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302062EXPORT_SYMBOL(ecm_db_connection_regeneration_required_peek);
Ben Menchaca84f36632014-02-28 20:57:38 +00002063
2064/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302065 * ecm_db_connection_regeneration_needed()
2066 * Cause a specific connection to require re-generation
2067 *
2068 * NOTE: This only flags that re-generation is needed.
2069 * The connection will typically be re-generated when ecm_db_connection_regeneration_required_check() is invoked.
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01002070 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302071void ecm_db_connection_regeneration_needed(struct ecm_db_connection_instance *ci)
Ben Menchaca84f36632014-02-28 20:57:38 +00002072{
2073 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2074
2075 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302076 ci->regen_occurances++;
2077 ci->regen_required++;
Ben Menchaca84f36632014-02-28 20:57:38 +00002078 spin_unlock_bh(&ecm_db_lock);
2079}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302080EXPORT_SYMBOL(ecm_db_connection_regeneration_needed);
Ben Menchaca84f36632014-02-28 20:57:38 +00002081
2082/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302083 * ecm_db_regeneration_needed()
2084 * Bump the global generation index to cause a re-generation of all connections state.
Ben Menchaca84f36632014-02-28 20:57:38 +00002085 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302086void ecm_db_regeneration_needed(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002087{
2088 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302089 ecm_db_connection_generation++;
Ben Menchaca84f36632014-02-28 20:57:38 +00002090 spin_unlock_bh(&ecm_db_lock);
2091}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05302092EXPORT_SYMBOL(ecm_db_regeneration_needed);
Ben Menchaca84f36632014-02-28 20:57:38 +00002093
2094/*
Xiaoping Faned6d37e2015-09-17 14:13:47 -07002095 * ecm_db_connection_regenerate()
2096 * Re-generate a specific connection
2097 */
2098void ecm_db_connection_regenerate(struct ecm_db_connection_instance *ci)
2099{
2100 struct ecm_front_end_connection_instance *feci;
2101
2102 DEBUG_TRACE("Regenerate connection: %p\n", ci);
2103
2104 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2105
2106 /*
2107 * Notify front end to regenerate a connection.
2108 */
2109 feci = ecm_db_connection_front_end_get_and_ref(ci);
2110 feci->regenerate(feci, ci);
2111 feci->deref(feci);
2112}
2113EXPORT_SYMBOL(ecm_db_connection_regenerate);
2114
2115/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002116 * ecm_db_connection_direction_get()
2117 * Return direction of the connection.
2118 *
2119 * NOTE: an EGRESS connection means that packets being sent to mapping_to should have qos applied.
2120 * INGRESS means that packets being sent to mapping_from should have qos applied.
2121 */
2122ecm_db_direction_t ecm_db_connection_direction_get(struct ecm_db_connection_instance *ci)
2123{
2124 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2125 return ci->direction;
2126}
2127EXPORT_SYMBOL(ecm_db_connection_direction_get);
2128
2129/*
2130 * ecm_db_mapping_port_count_get()
2131 * Return port count stats for a mapping.
2132 */
2133void ecm_db_mapping_port_count_get(struct ecm_db_mapping_instance *mi,
2134 int *tcp_from, int *tcp_to, int *udp_from, int *udp_to, int *from, int *to,
2135 int *tcp_nat_from, int *tcp_nat_to, int *udp_nat_from, int *udp_nat_to, int *nat_from, int *nat_to)
2136{
2137 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2138
2139 spin_lock_bh(&ecm_db_lock);
2140
2141 *tcp_from = mi->tcp_from;
2142 *tcp_to = mi->tcp_to;
2143 *udp_from = mi->udp_from;
2144 *udp_to = mi->udp_to;
2145 *from = mi->from;
2146 *to = mi->to;
2147
2148 *tcp_nat_from = mi->tcp_nat_from;
2149 *tcp_nat_to = mi->tcp_nat_to;
2150 *udp_nat_from = mi->udp_nat_from;
2151 *udp_nat_to = mi->udp_nat_to;
2152 *nat_from = mi->nat_from;
2153 *nat_to = mi->nat_to;
2154
2155 spin_unlock_bh(&ecm_db_lock);
2156}
2157EXPORT_SYMBOL(ecm_db_mapping_port_count_get);
2158
2159/*
2160 * ecm_db_connection_is_routed_get()
2161 * Return whether connection is a routed path or not
2162 */
2163bool ecm_db_connection_is_routed_get(struct ecm_db_connection_instance *ci)
2164{
2165 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2166 return ci->is_routed;
2167}
2168EXPORT_SYMBOL(ecm_db_connection_is_routed_get);
2169
2170/*
2171 * ecm_db_connection_protocol_get()
2172 * Return protocol of connection
2173 */
2174int ecm_db_connection_protocol_get(struct ecm_db_connection_instance *ci)
2175{
2176 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2177 return ci->protocol;
2178}
2179EXPORT_SYMBOL(ecm_db_connection_protocol_get);
2180
2181/*
Gareth Williams3e5b37f2015-05-13 10:04:12 +01002182 * ecm_db_connection_ip_version_get()
2183 * Return IP version of connection
2184 */
2185int ecm_db_connection_ip_version_get(struct ecm_db_connection_instance *ci)
2186{
2187 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2188 return ci->ip_version;
2189}
2190EXPORT_SYMBOL(ecm_db_connection_ip_version_get);
2191
2192/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002193 * ecm_db_host_address_get()
2194 * Return address of host
2195 */
2196void ecm_db_host_address_get(struct ecm_db_host_instance *hi, ip_addr_t addr)
2197{
2198 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
2199 ECM_IP_ADDR_COPY(addr, hi->address);
2200}
2201EXPORT_SYMBOL(ecm_db_host_address_get);
2202
2203/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002204 * ecm_db_host_on_link_get()
2205 * Return on link status of host
2206 */
2207bool ecm_db_host_on_link_get(struct ecm_db_host_instance *hi)
2208{
2209 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
2210 return hi->on_link;
2211}
2212EXPORT_SYMBOL(ecm_db_host_on_link_get);
2213
2214/*
2215 * ecm_db_mapping_adress_get()
2216 * Return address
2217 */
2218void ecm_db_mapping_adress_get(struct ecm_db_mapping_instance *mi, ip_addr_t addr)
2219{
2220 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2221 ECM_IP_ADDR_COPY(addr, mi->host->address);
2222}
2223EXPORT_SYMBOL(ecm_db_mapping_adress_get);
2224
2225/*
2226 * ecm_db_mapping_port_get()
2227 * Return port
2228 */
2229int ecm_db_mapping_port_get(struct ecm_db_mapping_instance *mi)
2230{
2231 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2232 return mi->port;
2233}
2234EXPORT_SYMBOL(ecm_db_mapping_port_get);
2235
2236/*
2237 * ecm_db_node_adress_get()
2238 * Return address
2239 */
2240void ecm_db_node_adress_get(struct ecm_db_node_instance *ni, uint8_t *address_buffer)
2241{
2242 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
2243 memcpy(address_buffer, ni->address, ETH_ALEN);
2244}
2245EXPORT_SYMBOL(ecm_db_node_adress_get);
2246
2247/*
2248 * _ecm_db_timer_group_entry_remove()
2249 * Remove the entry from its timer group, returns false if the entry has already expired.
2250 */
2251static bool _ecm_db_timer_group_entry_remove(struct ecm_db_timer_group_entry *tge)
2252{
2253 struct ecm_db_timer_group *timer_group;
2254
2255 /*
2256 * If not in a timer group then it is already removed
2257 */
2258 if (tge->group == ECM_DB_TIMER_GROUPS_MAX) {
2259 return false;
2260 }
2261
2262 /*
2263 * Remove the connection from its current group
2264 */
2265 timer_group = &ecm_db_timer_groups[tge->group];
2266
2267 /*
2268 * Somewhere in the list?
2269 */
2270 if (tge->prev) {
2271 tge->prev->next = tge->next;
2272 } else {
2273 /*
2274 * First in the group
2275 */
2276 DEBUG_ASSERT(timer_group->head == tge, "%p: bad head, expecting %p, got %p\n", timer_group, tge, timer_group->head);
2277 timer_group->head = tge->next;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302278 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002279
2280 if (tge->next) {
2281 tge->next->prev = tge->prev;
2282 } else {
2283 /*
2284 * No next so this must be the last item - we need to adjust the tail pointer
2285 */
2286 DEBUG_ASSERT(timer_group->tail == tge, "%p: bad tail, expecting %p got %p\n", timer_group, tge, timer_group->tail);
2287 timer_group->tail = tge->prev;
2288 }
2289
2290 /*
2291 * No longer a part of a timer group
2292 */
2293 tge->group = ECM_DB_TIMER_GROUPS_MAX;
2294 return true;
2295}
2296
2297/*
2298 * ecm_db_timer_group_entry_remove()
2299 * Remove the connection from its timer group, returns false if the entry has already expired.
2300 */
2301bool ecm_db_timer_group_entry_remove(struct ecm_db_timer_group_entry *tge)
2302{
2303 bool res;
2304 spin_lock_bh(&ecm_db_lock);
2305 res = _ecm_db_timer_group_entry_remove(tge);
2306 spin_unlock_bh(&ecm_db_lock);
2307 return res;
2308}
2309EXPORT_SYMBOL(ecm_db_timer_group_entry_remove);
2310
2311/*
2312 * _ecm_db_timer_group_entry_set()
2313 * Set the timer group to which this entry will be a member
2314 */
2315void _ecm_db_timer_group_entry_set(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
2316{
2317 struct ecm_db_timer_group *timer_group;
2318
2319 DEBUG_ASSERT(tge->group == ECM_DB_TIMER_GROUPS_MAX, "%p: already set\n", tge);
2320
2321 /*
2322 * Set group
2323 */
2324 tge->group = tg;
2325 timer_group = &ecm_db_timer_groups[tge->group];
2326 tge->timeout = timer_group->time + ecm_db_time;
2327
2328 /*
2329 * Insert into a timer group at the head (as this is now touched)
2330 */
2331 tge->prev = NULL;
2332 tge->next = timer_group->head;
2333 if (!timer_group->head) {
2334 /*
2335 * As there is no head there is also no tail so we need to set that
2336 */
2337 timer_group->tail = tge;
2338 } else {
2339 /*
2340 * As there is a head already there must be a tail. Since we insert before
2341 * the current head we don't adjust the tail.
2342 */
2343 timer_group->head->prev = tge;
2344 }
2345 timer_group->head = tge;
2346}
2347
2348/*
2349 * ecm_db_timer_group_entry_reset()
2350 * Re-set the timer group to which this entry will be a member.
2351 *
2352 * Returns false if the timer cannot be reset because it has expired
2353 */
2354bool ecm_db_timer_group_entry_reset(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
2355{
2356 spin_lock_bh(&ecm_db_lock);
2357
2358 /*
2359 * Remove it from its current group, if any
2360 */
2361 if (!_ecm_db_timer_group_entry_remove(tge)) {
2362 spin_unlock_bh(&ecm_db_lock);
2363 return false;
2364 }
2365
2366 /*
2367 * Set new group
2368 */
2369 _ecm_db_timer_group_entry_set(tge, tg);
2370 spin_unlock_bh(&ecm_db_lock);
2371 return true;
2372}
2373EXPORT_SYMBOL(ecm_db_timer_group_entry_reset);
2374
2375/*
2376 * ecm_db_timer_group_entry_set()
2377 * Set the timer group to which this entry will be a member
2378 */
2379void ecm_db_timer_group_entry_set(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
2380{
2381 spin_lock_bh(&ecm_db_lock);
2382 _ecm_db_timer_group_entry_set(tge, tg);
2383 spin_unlock_bh(&ecm_db_lock);
2384}
2385EXPORT_SYMBOL(ecm_db_timer_group_entry_set);
2386
2387/*
2388 * ecm_db_timer_group_entry_init()
2389 * Initialise a timer entry ready for setting
2390 */
2391void ecm_db_timer_group_entry_init(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_entry_callback_t fn, void *arg)
2392{
2393 memset(tge, 0, sizeof(struct ecm_db_timer_group_entry));
2394 tge->group = ECM_DB_TIMER_GROUPS_MAX;
2395 tge->arg = arg;
2396 tge->fn = fn;
2397}
2398EXPORT_SYMBOL(ecm_db_timer_group_entry_init);
2399
2400/*
2401 * ecm_db_timer_group_entry_touch()
2402 * Update the timeout, if the timer is not running this has no effect.
2403 * It returns false if the timer is not running.
2404 */
2405bool ecm_db_timer_group_entry_touch(struct ecm_db_timer_group_entry *tge)
2406{
2407 struct ecm_db_timer_group *timer_group;
2408
2409 spin_lock_bh(&ecm_db_lock);
2410
2411 /*
2412 * If not in a timer group then do nothing
2413 */
2414 if (tge->group == ECM_DB_TIMER_GROUPS_MAX) {
2415 spin_unlock_bh(&ecm_db_lock);
2416 return false;
2417 }
2418
2419 /*
2420 * Update time to live
2421 */
2422 timer_group = &ecm_db_timer_groups[tge->group];
2423
2424 /*
2425 * Link out of its current position.
2426 */
2427 if (!tge->prev) {
2428 /*
2429 * Already at the head, just update the time
2430 */
2431 tge->timeout = timer_group->time + ecm_db_time;
2432 spin_unlock_bh(&ecm_db_lock);
2433 return true;
2434 }
2435
2436 /*
2437 * tge->prev is not null, so:
2438 * 1) it is in a timer list
2439 * 2) is not at the head of the list
2440 * 3) there is a head already (so more than one item on the list)
2441 * 4) there is a prev pointer.
2442 * Somewhere in the group list - unlink it.
2443 */
2444 tge->prev->next = tge->next;
2445
2446 if (tge->next) {
2447 tge->next->prev = tge->prev;
2448 } else {
2449 /*
2450 * Since there is no next this must be the tail
2451 */
2452 DEBUG_ASSERT(timer_group->tail == tge, "%p: bad tail, expecting %p got %p\n", timer_group, tge, timer_group->tail);
2453 timer_group->tail = tge->prev;
2454 }
2455
2456 /*
2457 * Link in to head.
2458 */
Sol Kavy213e45d2014-06-05 18:04:07 -07002459 tge->timeout = timer_group->time + ecm_db_time;
Ben Menchaca84f36632014-02-28 20:57:38 +00002460 tge->prev = NULL;
2461 tge->next = timer_group->head;
2462 timer_group->head->prev = tge;
2463 timer_group->head = tge;
2464 spin_unlock_bh(&ecm_db_lock);
2465 return true;
2466}
2467EXPORT_SYMBOL(ecm_db_timer_group_entry_touch);
2468
2469/*
2470 * _ecm_db_connection_ref()
2471 */
2472static void _ecm_db_connection_ref(struct ecm_db_connection_instance *ci)
2473{
2474 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2475 ci->refs++;
2476 DEBUG_TRACE("%p: connection ref %d\n", ci, ci->refs);
2477 DEBUG_ASSERT(ci->refs > 0, "%p: ref wrap\n", ci);
2478}
2479
2480/*
2481 * ecm_db_connection_ref()
2482 */
2483void ecm_db_connection_ref(struct ecm_db_connection_instance *ci)
2484{
2485 spin_lock_bh(&ecm_db_lock);
2486 _ecm_db_connection_ref(ci);
2487 spin_unlock_bh(&ecm_db_lock);
2488}
2489EXPORT_SYMBOL(ecm_db_connection_ref);
2490
2491/*
2492 * _ecm_db_mapping_ref()
2493 */
2494static void _ecm_db_mapping_ref(struct ecm_db_mapping_instance *mi)
2495{
2496 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
2497 mi->refs++;
2498 DEBUG_TRACE("%p: mapping ref %d\n", mi, mi->refs);
2499 DEBUG_ASSERT(mi->refs > 0, "%p: ref wrap\n", mi);
2500}
2501
2502/*
2503 * ecm_db_mapping_ref()
2504 */
2505void ecm_db_mapping_ref(struct ecm_db_mapping_instance *mi)
2506{
2507 spin_lock_bh(&ecm_db_lock);
2508 _ecm_db_mapping_ref(mi);
2509 spin_unlock_bh(&ecm_db_lock);
2510}
2511EXPORT_SYMBOL(ecm_db_mapping_ref);
2512
2513/*
2514 * _ecm_db_host_ref()
2515 */
2516static void _ecm_db_host_ref(struct ecm_db_host_instance *hi)
2517{
2518 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
2519 hi->refs++;
2520 DEBUG_TRACE("%p: host ref %d\n", hi, hi->refs);
2521 DEBUG_ASSERT(hi->refs > 0, "%p: ref wrap\n", hi);
2522}
2523
2524/*
2525 * ecm_db_host_ref()
2526 */
2527void ecm_db_host_ref(struct ecm_db_host_instance *hi)
2528{
2529 spin_lock_bh(&ecm_db_lock);
2530 _ecm_db_host_ref(hi);
2531 spin_unlock_bh(&ecm_db_lock);
2532}
2533EXPORT_SYMBOL(ecm_db_host_ref);
2534
2535/*
2536 * _ecm_db_node_ref()
2537 */
2538static void _ecm_db_node_ref(struct ecm_db_node_instance *ni)
2539{
2540 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
2541 ni->refs++;
2542 DEBUG_TRACE("%p: node ref %d\n", ni, ni->refs);
2543 DEBUG_ASSERT(ni->refs > 0, "%p: ref wrap\n", ni);
2544}
2545
2546/*
2547 * ecm_db_node_ref()
2548 */
2549void ecm_db_node_ref(struct ecm_db_node_instance *ni)
2550{
2551 spin_lock_bh(&ecm_db_lock);
2552 _ecm_db_node_ref(ni);
2553 spin_unlock_bh(&ecm_db_lock);
2554}
2555EXPORT_SYMBOL(ecm_db_node_ref);
2556
2557/*
2558 * _ecm_db_iface_ref()
2559 */
2560static void _ecm_db_iface_ref(struct ecm_db_iface_instance *ii)
2561{
2562 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
2563 ii->refs++;
2564 DEBUG_TRACE("%p: iface ref %d\n", ii, ii->refs);
2565 DEBUG_ASSERT(ii->refs > 0, "%p: ref wrap\n", ii);
2566}
2567
2568/*
2569 * ecm_db_iface_ref()
2570 */
2571void ecm_db_iface_ref(struct ecm_db_iface_instance *ii)
2572{
2573 spin_lock_bh(&ecm_db_lock);
2574 _ecm_db_iface_ref(ii);
2575 spin_unlock_bh(&ecm_db_lock);
2576}
2577EXPORT_SYMBOL(ecm_db_iface_ref);
2578
2579/*
2580 * _ecm_db_listener_ref()
2581 */
2582static void _ecm_db_listener_ref(struct ecm_db_listener_instance *li)
2583{
2584 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
2585 li->refs++;
2586 DEBUG_ASSERT(li->refs > 0, "%p: ref wrap\n", li);
2587}
2588
2589/*
2590 * ecm_db_listener_ref()
2591 */
2592void ecm_db_listener_ref(struct ecm_db_listener_instance *li)
2593{
2594 spin_lock_bh(&ecm_db_lock);
2595 _ecm_db_listener_ref(li);
2596 spin_unlock_bh(&ecm_db_lock);
2597}
2598EXPORT_SYMBOL(ecm_db_listener_ref);
2599
2600/*
2601 * ecm_db_connections_get_and_ref_first()
2602 * Obtain a ref to the first connection instance, if any
2603 */
Gareth Williamsf98d4192015-03-11 16:55:41 +00002604struct ecm_db_connection_instance *ecm_db_connections_get_and_ref_first(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002605{
2606 struct ecm_db_connection_instance *ci;
2607 spin_lock_bh(&ecm_db_lock);
2608 ci = ecm_db_connections;
2609 if (ci) {
2610 _ecm_db_connection_ref(ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302611 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002612 spin_unlock_bh(&ecm_db_lock);
2613 return ci;
2614}
2615EXPORT_SYMBOL(ecm_db_connections_get_and_ref_first);
2616
2617/*
2618 * ecm_db_connection_get_and_ref_next()
2619 * Return the next connection in the list given a connection
2620 */
2621struct ecm_db_connection_instance *ecm_db_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
2622{
2623 struct ecm_db_connection_instance *cin;
2624 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2625 spin_lock_bh(&ecm_db_lock);
2626 cin = ci->next;
2627 if (cin) {
2628 _ecm_db_connection_ref(cin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302629 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002630 spin_unlock_bh(&ecm_db_lock);
2631 return cin;
2632}
2633EXPORT_SYMBOL(ecm_db_connection_get_and_ref_next);
2634
2635/*
2636 * ecm_db_mappings_get_and_ref_first()
2637 * Obtain a ref to the first mapping instance, if any
2638 */
2639struct ecm_db_mapping_instance *ecm_db_mappings_get_and_ref_first(void)
2640{
2641 struct ecm_db_mapping_instance *mi;
2642 spin_lock_bh(&ecm_db_lock);
2643 mi = ecm_db_mappings;
2644 if (mi) {
2645 _ecm_db_mapping_ref(mi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302646 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002647 spin_unlock_bh(&ecm_db_lock);
2648 return mi;
2649}
2650EXPORT_SYMBOL(ecm_db_mappings_get_and_ref_first);
2651
2652/*
2653 * ecm_db_mapping_get_and_ref_next()
2654 * Return the next mapping in the list given a mapping
2655 */
2656struct ecm_db_mapping_instance *ecm_db_mapping_get_and_ref_next(struct ecm_db_mapping_instance *mi)
2657{
2658 struct ecm_db_mapping_instance *min;
2659 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2660 spin_lock_bh(&ecm_db_lock);
2661 min = mi->next;
2662 if (min) {
2663 _ecm_db_mapping_ref(min);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302664 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002665 spin_unlock_bh(&ecm_db_lock);
2666 return min;
2667}
2668EXPORT_SYMBOL(ecm_db_mapping_get_and_ref_next);
2669
2670/*
2671 * ecm_db_hosts_get_and_ref_first()
2672 * Obtain a ref to the first host instance, if any
2673 */
2674struct ecm_db_host_instance *ecm_db_hosts_get_and_ref_first(void)
2675{
2676 struct ecm_db_host_instance *hi;
2677 spin_lock_bh(&ecm_db_lock);
2678 hi = ecm_db_hosts;
2679 if (hi) {
2680 _ecm_db_host_ref(hi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302681 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002682 spin_unlock_bh(&ecm_db_lock);
2683 return hi;
2684}
2685EXPORT_SYMBOL(ecm_db_hosts_get_and_ref_first);
2686
2687/*
2688 * ecm_db_host_get_and_ref_next()
2689 * Return the next host in the list given a host
2690 */
2691struct ecm_db_host_instance *ecm_db_host_get_and_ref_next(struct ecm_db_host_instance *hi)
2692{
2693 struct ecm_db_host_instance *hin;
2694 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
2695 spin_lock_bh(&ecm_db_lock);
2696 hin = hi->next;
2697 if (hin) {
2698 _ecm_db_host_ref(hin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302699 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002700 spin_unlock_bh(&ecm_db_lock);
2701 return hin;
2702}
2703EXPORT_SYMBOL(ecm_db_host_get_and_ref_next);
2704
2705/*
2706 * ecm_db_listeners_get_and_ref_first()
2707 * Obtain a ref to the first listener instance, if any
2708 */
2709static struct ecm_db_listener_instance *ecm_db_listeners_get_and_ref_first(void)
2710{
2711 struct ecm_db_listener_instance *li;
2712 spin_lock_bh(&ecm_db_lock);
2713 li = ecm_db_listeners;
2714 if (li) {
2715 _ecm_db_listener_ref(li);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302716 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002717 spin_unlock_bh(&ecm_db_lock);
2718 return li;
2719}
2720
2721/*
2722 * ecm_db_listener_get_and_ref_next()
2723 * Return the next listener in the list given a listener
2724 */
2725static struct ecm_db_listener_instance *ecm_db_listener_get_and_ref_next(struct ecm_db_listener_instance *li)
2726{
2727 struct ecm_db_listener_instance *lin;
2728 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
2729 spin_lock_bh(&ecm_db_lock);
2730 lin = li->next;
2731 if (lin) {
2732 _ecm_db_listener_ref(lin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302733 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002734 spin_unlock_bh(&ecm_db_lock);
2735 return lin;
2736}
2737
2738/*
2739 * ecm_db_nodes_get_and_ref_first()
2740 * Obtain a ref to the first node instance, if any
2741 */
2742struct ecm_db_node_instance *ecm_db_nodes_get_and_ref_first(void)
2743{
2744 struct ecm_db_node_instance *ni;
2745 spin_lock_bh(&ecm_db_lock);
2746 ni = ecm_db_nodes;
2747 if (ni) {
2748 _ecm_db_node_ref(ni);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302749 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002750 spin_unlock_bh(&ecm_db_lock);
2751 return ni;
2752}
2753EXPORT_SYMBOL(ecm_db_nodes_get_and_ref_first);
2754
2755/*
2756 * ecm_db_node_get_and_ref_next()
2757 * Return the next node in the list given a node
2758 */
2759struct ecm_db_node_instance *ecm_db_node_get_and_ref_next(struct ecm_db_node_instance *ni)
2760{
2761 struct ecm_db_node_instance *nin;
2762 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
2763 spin_lock_bh(&ecm_db_lock);
2764 nin = ni->next;
2765 if (nin) {
2766 _ecm_db_node_ref(nin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302767 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002768 spin_unlock_bh(&ecm_db_lock);
2769 return nin;
2770}
2771EXPORT_SYMBOL(ecm_db_node_get_and_ref_next);
2772
2773/*
2774 * ecm_db_interfaces_get_and_ref_first()
2775 * Obtain a ref to the first iface instance, if any
2776 */
2777struct ecm_db_iface_instance *ecm_db_interfaces_get_and_ref_first(void)
2778{
2779 struct ecm_db_iface_instance *ii;
2780 spin_lock_bh(&ecm_db_lock);
2781 ii = ecm_db_interfaces;
2782 if (ii) {
2783 _ecm_db_iface_ref(ii);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302784 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002785 spin_unlock_bh(&ecm_db_lock);
2786 return ii;
2787}
2788EXPORT_SYMBOL(ecm_db_interfaces_get_and_ref_first);
2789
2790/*
2791 * ecm_db_interface_get_and_ref_next()
2792 * Return the next iface in the list given a iface
2793 */
2794struct ecm_db_iface_instance *ecm_db_interface_get_and_ref_next(struct ecm_db_iface_instance *ii)
2795{
2796 struct ecm_db_iface_instance *iin;
2797 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
2798 spin_lock_bh(&ecm_db_lock);
2799 iin = ii->next;
2800 if (iin) {
2801 _ecm_db_iface_ref(iin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302802 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002803 spin_unlock_bh(&ecm_db_lock);
2804 return iin;
2805}
2806EXPORT_SYMBOL(ecm_db_interface_get_and_ref_next);
2807
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002808#ifdef ECM_DB_CTA_TRACK_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002809/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01002810 * _ecm_db_classifier_type_assignment_remove()
2811 * Remove the connection from the classifier type assignment list (of the given type)
2812 */
2813static void _ecm_db_classifier_type_assignment_remove(struct ecm_db_connection_instance *ci, ecm_classifier_type_t ca_type)
2814{
2815 struct ecm_db_connection_classifier_type_assignment *ta;
2816 struct ecm_db_connection_classifier_type_assignment_list *tal;
2817
Murat Sezginc848bce2016-01-15 09:58:11 -08002818 DEBUG_ASSERT(spin_is_locked(&ecm_db_lock), "%p: lock is not held\n", ci);
2819
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01002820 DEBUG_TRACE("%p: Classifier type assignment remove: %d\n", ci, ca_type);
2821 ta = &ci->type_assignment[ca_type];
2822 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p\n", ta, ci);
2823 DEBUG_ASSERT(ta->iteration_count == 0, "%p: iteration count: %d, type: %d\n", ci, ta->iteration_count, ca_type);
2824
2825 if (ta->next) {
2826 struct ecm_db_connection_classifier_type_assignment *tan = &ta->next->type_assignment[ca_type];
2827 DEBUG_ASSERT(tan->prev == ci, "Bad list, expecting: %p, got: %p\n", ci, tan->prev);
2828 tan->prev = ta->prev;
2829 }
2830
2831 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
2832 if (ta->prev) {
2833 struct ecm_db_connection_classifier_type_assignment *tap = &ta->prev->type_assignment[ca_type];
2834 DEBUG_ASSERT(tap->next == ci, "Bad list, expecting: %p, got: %p\n", ci, tap->next);
2835 tap->next = ta->next;
2836 } else {
2837 /*
2838 * Set new head of list
2839 */
2840 DEBUG_ASSERT(tal->type_assignments_list == ci, "Bad head, expecting %p, got %p, type: %d\n", ci, tal->type_assignments_list, ca_type);
2841 tal->type_assignments_list = ta->next;
2842 }
2843 ta->next = NULL;
2844 ta->prev = NULL;
2845 ta->pending_unassign = false;
2846
2847 /*
2848 * Decrement assignment count
2849 */
2850 tal->type_assignment_count--;
2851 DEBUG_ASSERT(tal->type_assignment_count >= 0, "Bad type assignment count: %d, type: %d\n", tal->type_assignment_count, ca_type);
2852
2853 DEBUG_CLEAR_MAGIC(ta);
2854}
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002855#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01002856
2857/*
Shyam Sunder8793f612016-01-06 20:16:20 +05302858 * _ecm_db_connection_classifier_unassign()
2859 * Unassign a classifier and remove the classifier type
2860 *
2861 * The default classifier cannot be unassigned.
2862 */
2863static inline void _ecm_db_connection_classifier_unassign(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *cci, ecm_classifier_type_t ca_type)
2864{
2865#ifdef ECM_DB_CTA_TRACK_ENABLE
2866 struct ecm_db_connection_classifier_type_assignment *ta;
2867#endif
2868 DEBUG_ASSERT(spin_is_locked(&ecm_db_lock), "%p: lock is not held\n", ci);
2869
2870 /*
2871 * Clear the assignment.
2872 */
2873 ci->assignments_by_type[ca_type] = NULL;
2874
2875 /*
2876 * Link out of assignments list
2877 */
2878 if (cci->ca_prev) {
2879 cci->ca_prev->ca_next = cci->ca_next;
2880 } else {
2881 DEBUG_ASSERT(ci->assignments == cci, "%p: Bad assigmnment list, expecting: %p, got: %p", ci, cci, ci->assignments);
2882 ci->assignments = cci->ca_next;
2883 }
2884 if (cci->ca_next) {
2885 cci->ca_next->ca_prev = cci->ca_prev;
2886 }
2887
2888#ifdef ECM_DB_CTA_TRACK_ENABLE
2889 /*
2890 * Remove from the classifier type assignment list
2891 */
2892 ta = &ci->type_assignment[ca_type];
2893 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
2894 if (ta->iteration_count > 0) {
2895 /*
2896 * The list entry is being iterated outside of db lock being held.
2897 * We cannot remove this entry since it would mess up iteration.
2898 * Set the pending flag to be actioned another time
2899 */
2900 ta->pending_unassign = true;
2901 return;
2902 }
2903
2904 /*
2905 * Remove the list entry
2906 */
2907 DEBUG_INFO("%p: Remove type assignment: %d\n", ci, ca_type);
2908 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
2909#endif
2910 cci->deref(cci);
2911}
2912
Shyam Sunder317ca912016-01-22 16:51:28 +05302913#ifdef ECM_MULTICAST_ENABLE
2914/*
2915 * _ecm_db_multicast_tuple_instance_deref()
2916 * Deref the reference count or
2917 * Free the tuple_instance struct, when the multicast connection dies
2918 */
2919int _ecm_db_multicast_tuple_instance_deref(struct ecm_db_multicast_tuple_instance *ti)
2920{
2921 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
2922 ti->refs--;
2923 DEBUG_TRACE("%p: ti deref %d\n", ti, ti->refs);
2924 DEBUG_ASSERT(ti->refs >= 0, "%p: ref wrap\n", ti);
2925
2926 if (ti->refs > 0) {
2927 return ti->refs;
2928 }
2929
2930 if (ti->flags & ECM_DB_MULTICAST_TUPLE_INSTANCE_FLAGS_INSERTED) {
2931 if (!ti->prev) {
2932 DEBUG_ASSERT(ecm_db_multicast_tuple_instance_table[ti->hash_index] == ti, "%p: hash table bad\n", ti);
2933 ecm_db_multicast_tuple_instance_table[ti->hash_index] = ti->next;
2934 } else {
2935 ti->prev->next = ti->next;
2936 }
2937
2938 if (ti->next) {
2939 ti->next->prev = ti->prev;
2940 }
2941 }
2942
2943 DEBUG_CLEAR_MAGIC(ti);
2944 kfree(ti);
2945
2946 return 0;
2947}
2948#endif
2949
Shyam Sunder8793f612016-01-06 20:16:20 +05302950/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002951 * ecm_db_connection_deref()
2952 * Release reference to connection. Connection is removed from database on final deref and destroyed.
2953 */
2954int ecm_db_connection_deref(struct ecm_db_connection_instance *ci)
2955{
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002956#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002957 ecm_classifier_type_t ca_type;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002958#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002959 int32_t i;
2960
2961 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2962
2963 spin_lock_bh(&ecm_db_lock);
2964 ci->refs--;
2965 DEBUG_TRACE("%p: connection deref %d\n", ci, ci->refs);
2966 DEBUG_ASSERT(ci->refs >= 0, "%p: ref wrap\n", ci);
2967
2968 if (ci->refs > 0) {
2969 int refs = ci->refs;
2970 spin_unlock_bh(&ecm_db_lock);
2971 return refs;
2972 }
2973
Shyam Sunder317ca912016-01-22 16:51:28 +05302974#ifdef ECM_MULTICAST_ENABLE
2975 /*
2976 * For multicast connections, we need to deref the
2977 * associated tuple instance as well
2978 */
2979 if (ci->ti) {
2980 _ecm_db_multicast_tuple_instance_deref(ci->ti);
2981 }
2982#endif
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002983 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00002984 * Remove from database if inserted
2985 */
2986 if (!ci->flags & ECM_DB_CONNECTION_FLAGS_INSERTED) {
2987 spin_unlock_bh(&ecm_db_lock);
2988 } else {
2989 struct ecm_db_listener_instance *li;
Gareth Williamsb5903892015-03-20 15:13:07 +00002990#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002991 struct ecm_db_iface_instance *iface_from;
2992 struct ecm_db_iface_instance *iface_to;
2993 struct ecm_db_iface_instance *iface_nat_from;
2994 struct ecm_db_iface_instance *iface_nat_to;
Gareth Williamsb5903892015-03-20 15:13:07 +00002995#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002996
2997 /*
2998 * Remove it from the connection hash table
2999 */
3000 if (!ci->hash_prev) {
3001 DEBUG_ASSERT(ecm_db_connection_table[ci->hash_index] == ci, "%p: hash table bad\n", ci);
3002 ecm_db_connection_table[ci->hash_index] = ci->hash_next;
3003 } else {
3004 ci->hash_prev->hash_next = ci->hash_next;
3005 }
3006 if (ci->hash_next) {
3007 ci->hash_next->hash_prev = ci->hash_prev;
3008 }
3009 ecm_db_connection_table_lengths[ci->hash_index]--;
3010 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]);
3011
3012 /*
3013 * Remove it from the connection serial hash table
3014 */
3015 if (!ci->serial_hash_prev) {
3016 DEBUG_ASSERT(ecm_db_connection_serial_table[ci->serial_hash_index] == ci, "%p: hash table bad\n", ci);
3017 ecm_db_connection_serial_table[ci->serial_hash_index] = ci->serial_hash_next;
3018 } else {
3019 ci->serial_hash_prev->serial_hash_next = ci->serial_hash_next;
3020 }
3021 if (ci->serial_hash_next) {
3022 ci->serial_hash_next->serial_hash_prev = ci->serial_hash_prev;
3023 }
3024 ecm_db_connection_serial_table_lengths[ci->serial_hash_index]--;
3025 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]);
3026
3027 /*
3028 * Remove from the global list
3029 */
3030 if (!ci->prev) {
3031 DEBUG_ASSERT(ecm_db_connections == ci, "%p: conn table bad\n", ci);
3032 ecm_db_connections = ci->next;
3033 } else {
3034 ci->prev->next = ci->next;
3035 }
3036 if (ci->next) {
3037 ci->next->prev = ci->prev;
3038 }
3039
Gareth Williamsb5903892015-03-20 15:13:07 +00003040#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003041 /*
3042 * Remove connection from the "from" mapping connection list
3043 */
3044 if (!ci->from_prev) {
3045 DEBUG_ASSERT(ci->mapping_from->from_connections == ci, "%p: from conn table bad\n", ci);
3046 ci->mapping_from->from_connections = ci->from_next;
3047 } else {
3048 ci->from_prev->from_next = ci->from_next;
3049 }
3050 if (ci->from_next) {
3051 ci->from_next->from_prev = ci->from_prev;
3052 }
3053
3054 /*
3055 * Remove connection from the "to" mapping connection list
3056 */
3057 if (!ci->to_prev) {
3058 DEBUG_ASSERT(ci->mapping_to->to_connections == ci, "%p: to conn table bad\n", ci);
3059 ci->mapping_to->to_connections = ci->to_next;
3060 } else {
3061 ci->to_prev->to_next = ci->to_next;
3062 }
3063 if (ci->to_next) {
3064 ci->to_next->to_prev = ci->to_prev;
3065 }
3066
3067 /*
3068 * Remove connection from the "from" NAT mapping connection list
3069 */
3070 if (!ci->from_nat_prev) {
3071 DEBUG_ASSERT(ci->mapping_nat_from->from_nat_connections == ci, "%p: nat from conn table bad\n", ci);
3072 ci->mapping_nat_from->from_nat_connections = ci->from_nat_next;
3073 } else {
3074 ci->from_nat_prev->from_nat_next = ci->from_nat_next;
3075 }
3076 if (ci->from_nat_next) {
3077 ci->from_nat_next->from_nat_prev = ci->from_nat_prev;
3078 }
3079
3080 /*
3081 * Remove connection from the "to" NAT mapping connection list
3082 */
3083 if (!ci->to_nat_prev) {
3084 DEBUG_ASSERT(ci->mapping_nat_to->to_nat_connections == ci, "%p: nat to conn table bad\n", ci);
3085 ci->mapping_nat_to->to_nat_connections = ci->to_nat_next;
3086 } else {
3087 ci->to_nat_prev->to_nat_next = ci->to_nat_next;
3088 }
3089 if (ci->to_nat_next) {
3090 ci->to_nat_next->to_nat_prev = ci->to_nat_prev;
3091 }
3092
3093 /*
3094 * Remove connection from the "from" iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01003095 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00003096 */
Gareth Williams90f2a282014-08-27 15:56:25 +01003097 iface_from = ci->from_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00003098 if (!ci->iface_from_prev) {
3099 DEBUG_ASSERT(iface_from->from_connections == ci, "%p: iface from conn table bad\n", ci);
3100 iface_from->from_connections = ci->iface_from_next;
3101 } else {
3102 ci->iface_from_prev->iface_from_next = ci->iface_from_next;
3103 }
3104 if (ci->iface_from_next) {
3105 ci->iface_from_next->iface_from_prev = ci->iface_from_prev;
3106 }
3107
3108 /*
3109 * Remove connection from the "to" iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01003110 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00003111 */
Gareth Williams90f2a282014-08-27 15:56:25 +01003112 iface_to = ci->to_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00003113 if (!ci->iface_to_prev) {
3114 DEBUG_ASSERT(iface_to->to_connections == ci, "%p: to conn table bad\n", ci);
3115 iface_to->to_connections = ci->iface_to_next;
3116 } else {
3117 ci->iface_to_prev->iface_to_next = ci->iface_to_next;
3118 }
3119 if (ci->iface_to_next) {
3120 ci->iface_to_next->iface_to_prev = ci->iface_to_prev;
3121 }
3122
3123 /*
3124 * Remove connection from the "from" NAT iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01003125 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00003126 */
Gareth Williams90f2a282014-08-27 15:56:25 +01003127 iface_nat_from = ci->from_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00003128 if (!ci->iface_from_nat_prev) {
3129 DEBUG_ASSERT(iface_nat_from->from_nat_connections == ci, "%p: nat from conn table bad\n", ci);
3130 iface_nat_from->from_nat_connections = ci->iface_from_nat_next;
3131 } else {
3132 ci->iface_from_nat_prev->iface_from_nat_next = ci->iface_from_nat_next;
3133 }
3134 if (ci->iface_from_nat_next) {
3135 ci->iface_from_nat_next->iface_from_nat_prev = ci->iface_from_nat_prev;
3136 }
3137
3138 /*
3139 * Remove connection from the "to" NAT iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01003140 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00003141 */
Gareth Williams90f2a282014-08-27 15:56:25 +01003142 iface_nat_to = ci->to_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00003143 if (!ci->iface_to_nat_prev) {
3144 DEBUG_ASSERT(iface_nat_to->to_nat_connections == ci, "%p: nat to conn table bad\n", ci);
3145 iface_nat_to->to_nat_connections = ci->iface_to_nat_next;
3146 } else {
3147 ci->iface_to_nat_prev->iface_to_nat_next = ci->iface_to_nat_next;
3148 }
3149 if (ci->iface_to_nat_next) {
3150 ci->iface_to_nat_next->iface_to_nat_prev = ci->iface_to_nat_prev;
3151 }
3152
3153 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01003154 * Remove connection from its "from node" node connection list
3155 */
3156 if (!ci->node_from_prev) {
3157 DEBUG_ASSERT(ci->from_node->from_connections == ci, "%p: from node conn table bad, got: %p\n", ci, ci->from_node->from_connections);
3158 ci->from_node->from_connections = ci->node_from_next;
3159 } else {
3160 ci->node_from_prev->node_from_next = ci->node_from_next;
3161 }
3162 if (ci->node_from_next) {
3163 ci->node_from_next->node_from_prev = ci->node_from_prev;
3164 }
3165 ci->from_node->from_connections_count--;
3166 DEBUG_ASSERT(ci->from_node->from_connections_count >= 0, "%p: bad count\n", ci);
3167
3168 /*
3169 * Remove connection from its "to node" node connection list
3170 */
3171 if (!ci->node_to_prev) {
3172 DEBUG_ASSERT(ci->to_node->to_connections == ci, "%p: to node conn table bad, got: %p\n", ci, ci->to_node->to_connections);
3173 ci->to_node->to_connections = ci->node_to_next;
3174 } else {
3175 ci->node_to_prev->node_to_next = ci->node_to_next;
3176 }
3177 if (ci->node_to_next) {
3178 ci->node_to_next->node_to_prev = ci->node_to_prev;
3179 }
3180 ci->to_node->to_connections_count--;
3181 DEBUG_ASSERT(ci->to_node->to_connections_count >= 0, "%p: bad count\n", ci);
3182
3183 /*
3184 * Remove connection from its "from nat node" node connection list
3185 */
3186 if (!ci->node_from_nat_prev) {
3187 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);
3188 ci->from_nat_node->from_nat_connections = ci->node_from_nat_next;
3189 } else {
3190 ci->node_from_nat_prev->node_from_nat_next = ci->node_from_nat_next;
3191 }
3192 if (ci->node_from_nat_next) {
3193 ci->node_from_nat_next->node_from_nat_prev = ci->node_from_nat_prev;
3194 }
3195 ci->from_nat_node->from_nat_connections_count--;
3196 DEBUG_ASSERT(ci->from_nat_node->from_nat_connections_count >= 0, "%p: bad count\n", ci);
3197
3198 /*
3199 * Remove connection from its "to nat node" node connection list
3200 */
3201 if (!ci->node_to_nat_prev) {
3202 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);
3203 ci->to_nat_node->to_nat_connections = ci->node_to_nat_next;
3204 } else {
3205 ci->node_to_nat_prev->node_to_nat_next = ci->node_to_nat_next;
3206 }
3207 if (ci->node_to_nat_next) {
3208 ci->node_to_nat_next->node_to_nat_prev = ci->node_to_nat_prev;
3209 }
3210 ci->to_nat_node->to_nat_connections_count--;
3211 DEBUG_ASSERT(ci->to_nat_node->to_nat_connections_count >= 0, "%p: bad count\n", ci);
Gareth Williamsb5903892015-03-20 15:13:07 +00003212#endif
Gareth Williams90f2a282014-08-27 15:56:25 +01003213
3214 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00003215 * Update the counters in the mappings
3216 */
3217 if (ci->protocol == IPPROTO_UDP) {
3218 ci->mapping_from->udp_from--;
3219 ci->mapping_to->udp_to--;
3220 ci->mapping_nat_from->udp_nat_from--;
3221 ci->mapping_nat_to->udp_nat_to--;
3222 } else if (ci->protocol == IPPROTO_TCP) {
3223 ci->mapping_from->tcp_from--;
3224 ci->mapping_to->tcp_to--;
3225 ci->mapping_nat_from->tcp_nat_from--;
3226 ci->mapping_nat_to->tcp_nat_to--;
3227 }
3228
3229 ci->mapping_from->from--;
3230 ci->mapping_to->to--;
3231 ci->mapping_nat_from->nat_from--;
3232 ci->mapping_nat_to->nat_to--;
3233
3234 /*
3235 * Assert that the defunt timer has been detached
3236 */
3237 DEBUG_ASSERT(ci->defunct_timer.group == ECM_DB_TIMER_GROUPS_MAX, "%p: unexpected timer group %d\n", ci, ci->defunct_timer.group);
3238
3239 /*
3240 * Decrement protocol counter stats
3241 */
3242 ecm_db_connection_count_by_protocol[ci->protocol]--;
3243 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 +01003244
Ben Menchaca84f36632014-02-28 20:57:38 +00003245 spin_unlock_bh(&ecm_db_lock);
3246
3247 /*
3248 * Throw removed event to listeners
3249 */
3250 DEBUG_TRACE("%p: Throw connection removed event\n", ci);
3251 li = ecm_db_listeners_get_and_ref_first();
3252 while (li) {
3253 struct ecm_db_listener_instance *lin;
3254 if (li->connection_removed) {
3255 li->connection_removed(li->arg, ci);
3256 }
3257
3258 /*
3259 * Get next listener
3260 */
3261 lin = ecm_db_listener_get_and_ref_next(li);
3262 ecm_db_listener_deref(li);
3263 li = lin;
3264 }
3265 }
3266
Shyam Sunder8793f612016-01-06 20:16:20 +05303267#ifdef ECM_DB_CTA_TRACK_ENABLE
3268 /*
3269 * Unlink from the "assignments by classifier type" lists.
3270 *
3271 * This is done whether the connection is inserted into the database or not - this is because
3272 * classifier assignments take place before adding into the db.
3273 *
3274 * NOTE: We know that the ci is not being iterated in any of these lists because otherwise
3275 * ci would be being held as part of iteration and so we would not be here!
3276 * Equally we know that if the assignments_by_type[] element is non-null then it must also be in the relevant list too.
3277 *
3278 * Default classifier is not in the classifier type assignement list, so we should start the loop index
3279 * with the first assigned classifier type.
3280 */
3281 spin_lock_bh(&ecm_db_lock);
3282 for (ca_type = ECM_CLASSIFIER_TYPE_DEFAULT + 1; ca_type < ECM_CLASSIFIER_TYPES; ++ca_type) {
3283 struct ecm_classifier_instance *cci = ci->assignments_by_type[ca_type];
3284 if (!cci) {
3285 /*
3286 * No assignment of this type, so would not be in the classifier type assignments list
3287 */
3288 continue;
3289 }
3290 _ecm_db_connection_classifier_unassign(ci, cci, ca_type);
3291 }
3292 spin_unlock_bh(&ecm_db_lock);
3293#endif
3294
Ben Menchaca84f36632014-02-28 20:57:38 +00003295 /*
3296 * Throw final event
3297 */
3298 if (ci->final) {
3299 ci->final(ci->arg);
3300 }
3301
Murat Sezgina4b4b1f2016-01-19 12:21:55 -08003302 /*
3303 * Release instances to the objects referenced by the connection
3304 */
3305 while (ci->assignments) {
3306 struct ecm_classifier_instance *classi = ci->assignments;
3307 ci->assignments = classi->ca_next;
3308 classi->deref(classi);
3309 }
3310
Ben Menchaca84f36632014-02-28 20:57:38 +00003311 if (ci->mapping_from) {
3312 ecm_db_mapping_deref(ci->mapping_from);
3313 }
3314 if (ci->mapping_to) {
3315 ecm_db_mapping_deref(ci->mapping_to);
3316 }
3317 if (ci->mapping_nat_from) {
3318 ecm_db_mapping_deref(ci->mapping_nat_from);
3319 }
3320 if (ci->mapping_nat_to) {
3321 ecm_db_mapping_deref(ci->mapping_nat_to);
3322 }
3323 if (ci->feci) {
3324 ci->feci->deref(ci->feci);
3325 }
Gareth Williams90f2a282014-08-27 15:56:25 +01003326 if (ci->from_node) {
3327 ecm_db_node_deref(ci->from_node);
3328 }
3329 if (ci->to_node) {
3330 ecm_db_node_deref(ci->to_node);
3331 }
3332 if (ci->from_nat_node) {
3333 ecm_db_node_deref(ci->from_nat_node);
3334 }
3335 if (ci->to_nat_node) {
3336 ecm_db_node_deref(ci->to_nat_node);
3337 }
Shyam Sunder317ca912016-01-22 16:51:28 +05303338
Ben Menchaca84f36632014-02-28 20:57:38 +00003339 /*
3340 * Remove references to the interfaces in our heirarchy lists
3341 */
3342 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3343 DEBUG_TRACE("%p: from interface %d remove: %p\n", ci, i, ci->from_interfaces[i]);
3344 ecm_db_iface_deref(ci->from_interfaces[i]);
3345 }
3346 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3347 DEBUG_TRACE("%p: to interface %d remove: %p\n", ci, i, ci->to_interfaces[i]);
3348 ecm_db_iface_deref(ci->to_interfaces[i]);
3349 }
3350 for (i = ci->from_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3351 DEBUG_TRACE("%p: from nat interface %d remove: %p\n", ci, i, ci->from_nat_interfaces[i]);
3352 ecm_db_iface_deref(ci->from_nat_interfaces[i]);
3353 }
3354 for (i = ci->to_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3355 DEBUG_TRACE("%p: to nat interface %d remove: %p\n", ci, i, ci->to_nat_interfaces[i]);
3356 ecm_db_iface_deref(ci->to_nat_interfaces[i]);
3357 }
3358
Murat Sezginaa740112017-12-12 09:41:46 -08003359#ifdef ECM_MULTICAST_ENABLE
3360 /*
3361 * Remove references to the multicast interfaces of this connection.
3362 */
3363 ecm_db_multicast_connection_to_interfaces_clear(ci);
3364#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003365 /*
3366 * We can now destroy the instance
3367 */
3368 DEBUG_CLEAR_MAGIC(ci);
3369 kfree(ci);
3370
3371 /*
3372 * Decrease global connection count
3373 */
3374 spin_lock_bh(&ecm_db_lock);
3375 ecm_db_connection_count--;
3376 DEBUG_ASSERT(ecm_db_connection_count >= 0, "%p: connection count wrap\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00003377 spin_unlock_bh(&ecm_db_lock);
3378
Ben Menchaca84f36632014-02-28 20:57:38 +00003379 return 0;
3380}
3381EXPORT_SYMBOL(ecm_db_connection_deref);
3382
3383/*
3384 * ecm_db_mapping_deref()
3385 * Release ref to mapping, possibly removing it from the database and destroying it.
3386 */
3387int ecm_db_mapping_deref(struct ecm_db_mapping_instance *mi)
3388{
3389 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
3390
3391 spin_lock_bh(&ecm_db_lock);
3392 mi->refs--;
3393 DEBUG_TRACE("%p: mapping deref %d\n", mi, mi->refs);
3394 DEBUG_ASSERT(mi->refs >= 0, "%p: ref wrap\n", mi);
3395
3396 if (mi->refs > 0) {
3397 int refs = mi->refs;
3398 spin_unlock_bh(&ecm_db_lock);
3399 return refs;
3400 }
3401
Gareth Williamsb5903892015-03-20 15:13:07 +00003402 DEBUG_ASSERT(!mi->tcp_from && !mi->udp_from && !mi->from, "%p: from not zero: %d, %d, %d\n",
3403 mi, mi->tcp_from, mi->udp_from, mi->from);
3404 DEBUG_ASSERT(!mi->tcp_to && !mi->udp_to && !mi->to, "%p: to not zero: %d, %d, %d\n",
3405 mi, mi->tcp_to, mi->udp_to, mi->to);
3406 DEBUG_ASSERT(!mi->tcp_nat_from && !mi->udp_nat_from && !mi->nat_from, "%p: nat_from not zero: %d, %d, %d\n",
3407 mi, mi->tcp_nat_from, mi->udp_nat_from, mi->nat_from);
3408 DEBUG_ASSERT(!mi->tcp_nat_to && !mi->udp_nat_to && !mi->nat_to, "%p: nat_to not zero: %d, %d, %d\n",
3409 mi, mi->tcp_nat_to, mi->udp_nat_to, mi->nat_to);
3410
3411#ifdef ECM_DB_XREF_ENABLE
3412 DEBUG_ASSERT(!mi->from_connections, "%p: from not null: %p\n", mi, mi->from_connections);
3413 DEBUG_ASSERT(!mi->to_connections, "%p: to not null: %p\n", mi, mi->to_connections);
3414 DEBUG_ASSERT(!mi->from_nat_connections, "%p: nat_from not null: %p\n", mi, mi->from_nat_connections);
3415 DEBUG_ASSERT(!mi->to_nat_connections, "%p: nat_to not null: %p\n", mi, mi->to_nat_connections);
3416#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003417
3418 /*
3419 * Remove from database if inserted
3420 */
3421 if (!mi->flags & ECM_DB_MAPPING_FLAGS_INSERTED) {
3422 spin_unlock_bh(&ecm_db_lock);
3423 } else {
3424 struct ecm_db_listener_instance *li;
3425
3426 /*
3427 * Remove from the global list
3428 */
3429 if (!mi->prev) {
3430 DEBUG_ASSERT(ecm_db_mappings == mi, "%p: mapping table bad\n", mi);
3431 ecm_db_mappings = mi->next;
3432 } else {
3433 mi->prev->next = mi->next;
3434 }
3435 if (mi->next) {
3436 mi->next->prev = mi->prev;
3437 }
3438
3439 /*
3440 * Unlink it from the mapping hash table
3441 */
3442 if (!mi->hash_prev) {
3443 DEBUG_ASSERT(ecm_db_mapping_table[mi->hash_index] == mi, "%p: hash table bad\n", mi);
3444 ecm_db_mapping_table[mi->hash_index] = mi->hash_next;
3445 } else {
3446 mi->hash_prev->hash_next = mi->hash_next;
3447 }
3448 if (mi->hash_next) {
3449 mi->hash_next->hash_prev = mi->hash_prev;
3450 }
3451 mi->hash_next = NULL;
3452 mi->hash_prev = NULL;
3453 ecm_db_mapping_table_lengths[mi->hash_index]--;
3454 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]);
3455
Gareth Williamsb5903892015-03-20 15:13:07 +00003456#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003457 /*
3458 * Unlink it from the host mapping list
3459 */
3460 if (!mi->mapping_prev) {
3461 DEBUG_ASSERT(mi->host->mappings == mi, "%p: mapping table bad\n", mi);
3462 mi->host->mappings = mi->mapping_next;
3463 } else {
3464 mi->mapping_prev->mapping_next = mi->mapping_next;
3465 }
3466 if (mi->mapping_next) {
3467 mi->mapping_next->mapping_prev = mi->mapping_prev;
3468 }
3469 mi->mapping_next = NULL;
3470 mi->mapping_prev = NULL;
3471
3472 mi->host->mapping_count--;
Gareth Williamsb5903892015-03-20 15:13:07 +00003473#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003474 spin_unlock_bh(&ecm_db_lock);
3475
3476 /*
3477 * Throw removed event to listeners
3478 */
3479 DEBUG_TRACE("%p: Throw mapping removed event\n", mi);
3480 li = ecm_db_listeners_get_and_ref_first();
3481 while (li) {
3482 struct ecm_db_listener_instance *lin;
3483 if (li->mapping_removed) {
3484 li->mapping_removed(li->arg, mi);
3485 }
3486
3487 /*
3488 * Get next listener
3489 */
3490 lin = ecm_db_listener_get_and_ref_next(li);
3491 ecm_db_listener_deref(li);
3492 li = lin;
3493 }
3494 }
3495
3496 /*
3497 * Throw final event
3498 */
3499 if (mi->final) {
3500 mi->final(mi->arg);
3501 }
3502
3503 /*
3504 * Now release the host instance if the mapping had one
3505 */
3506 if (mi->host) {
3507 ecm_db_host_deref(mi->host);
3508 }
3509
3510 /*
3511 * We can now destroy the instance
3512 */
3513 DEBUG_CLEAR_MAGIC(mi);
3514 kfree(mi);
3515
3516 /*
3517 * Decrease global mapping count
3518 */
3519 spin_lock_bh(&ecm_db_lock);
3520 ecm_db_mapping_count--;
3521 DEBUG_ASSERT(ecm_db_mapping_count >= 0, "%p: mapping count wrap\n", mi);
Ben Menchaca84f36632014-02-28 20:57:38 +00003522 spin_unlock_bh(&ecm_db_lock);
3523
Ben Menchaca84f36632014-02-28 20:57:38 +00003524 return 0;
3525}
3526EXPORT_SYMBOL(ecm_db_mapping_deref);
3527
3528/*
3529 * ecm_db_host_deref()
3530 * Release a ref to a host instance, possibly causing removal from the database and destruction of the instance
3531 */
3532int ecm_db_host_deref(struct ecm_db_host_instance *hi)
3533{
3534 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
3535
3536 spin_lock_bh(&ecm_db_lock);
3537 hi->refs--;
3538 DEBUG_TRACE("%p: host deref %d\n", hi, hi->refs);
3539 DEBUG_ASSERT(hi->refs >= 0, "%p: ref wrap\n", hi);
3540
3541 if (hi->refs > 0) {
3542 int refs = hi->refs;
3543 spin_unlock_bh(&ecm_db_lock);
3544 return refs;
3545 }
3546
Gareth Williamsb5903892015-03-20 15:13:07 +00003547#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003548 DEBUG_ASSERT((hi->mappings == NULL) && (hi->mapping_count == 0), "%p: mappings not null\n", hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00003549#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003550
3551 /*
3552 * Remove from database if inserted
3553 */
3554 if (!hi->flags & ECM_DB_HOST_FLAGS_INSERTED) {
3555 spin_unlock_bh(&ecm_db_lock);
3556 } else {
3557 struct ecm_db_listener_instance *li;
3558
3559 /*
3560 * Remove from the global list
3561 */
3562 if (!hi->prev) {
3563 DEBUG_ASSERT(ecm_db_hosts == hi, "%p: host table bad\n", hi);
3564 ecm_db_hosts = hi->next;
3565 } else {
3566 hi->prev->next = hi->next;
3567 }
3568 if (hi->next) {
3569 hi->next->prev = hi->prev;
3570 }
3571
3572 /*
3573 * Unlink it from the host hash table
3574 */
3575 if (!hi->hash_prev) {
3576 DEBUG_ASSERT(ecm_db_host_table[hi->hash_index] == hi, "%p: hash table bad\n", hi);
3577 ecm_db_host_table[hi->hash_index] = hi->hash_next;
3578 } else {
3579 hi->hash_prev->hash_next = hi->hash_next;
3580 }
3581 if (hi->hash_next) {
3582 hi->hash_next->hash_prev = hi->hash_prev;
3583 }
3584 hi->hash_next = NULL;
3585 hi->hash_prev = NULL;
3586 ecm_db_host_table_lengths[hi->hash_index]--;
3587 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]);
3588
Ben Menchaca84f36632014-02-28 20:57:38 +00003589 spin_unlock_bh(&ecm_db_lock);
3590
3591 /*
3592 * Throw removed event to listeners
3593 */
3594 DEBUG_TRACE("%p: Throw host removed event\n", hi);
3595 li = ecm_db_listeners_get_and_ref_first();
3596 while (li) {
3597 struct ecm_db_listener_instance *lin;
3598 if (li->host_removed) {
3599 li->host_removed(li->arg, hi);
3600 }
3601
3602 /*
3603 * Get next listener
3604 */
3605 lin = ecm_db_listener_get_and_ref_next(li);
3606 ecm_db_listener_deref(li);
3607 li = lin;
3608 }
3609 }
3610
3611 /*
3612 * Throw final event
3613 */
3614 if (hi->final) {
3615 hi->final(hi->arg);
3616 }
3617
3618 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00003619 * We can now destroy the instance
3620 */
3621 DEBUG_CLEAR_MAGIC(hi);
3622 kfree(hi);
3623
3624 /*
3625 * Decrease global host count
3626 */
3627 spin_lock_bh(&ecm_db_lock);
3628 ecm_db_host_count--;
3629 DEBUG_ASSERT(ecm_db_host_count >= 0, "%p: host count wrap\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00003630 spin_unlock_bh(&ecm_db_lock);
3631
Ben Menchaca84f36632014-02-28 20:57:38 +00003632 return 0;
3633}
3634EXPORT_SYMBOL(ecm_db_host_deref);
3635
3636/*
3637 * ecm_db_node_deref()
3638 * Deref a node. Removing it on the last ref and destroying it.
3639 */
3640int ecm_db_node_deref(struct ecm_db_node_instance *ni)
3641{
3642 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
3643
3644 spin_lock_bh(&ecm_db_lock);
3645 ni->refs--;
3646 DEBUG_TRACE("%p: node deref %d\n", ni, ni->refs);
3647 DEBUG_ASSERT(ni->refs >= 0, "%p: ref wrap\n", ni);
3648
3649 if (ni->refs > 0) {
3650 int refs = ni->refs;
3651 spin_unlock_bh(&ecm_db_lock);
3652 return refs;
3653 }
3654
Gareth Williamsb5903892015-03-20 15:13:07 +00003655#ifdef ECM_DB_XREF_ENABLE
Gareth Williams90f2a282014-08-27 15:56:25 +01003656 DEBUG_ASSERT((ni->from_connections == NULL) && (ni->from_connections_count == 0), "%p: from_connections not null\n", ni);
3657 DEBUG_ASSERT((ni->to_connections == NULL) && (ni->to_connections_count == 0), "%p: to_connections not null\n", ni);
3658 DEBUG_ASSERT((ni->from_nat_connections == NULL) && (ni->from_nat_connections_count == 0), "%p: from_nat_connections not null\n", ni);
3659 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 +00003660#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003661
3662 /*
3663 * Remove from database if inserted
3664 */
3665 if (!ni->flags & ECM_DB_NODE_FLAGS_INSERTED) {
3666 spin_unlock_bh(&ecm_db_lock);
3667 } else {
3668 struct ecm_db_listener_instance *li;
3669
3670 /*
3671 * Remove from the global list
3672 */
3673 if (!ni->prev) {
3674 DEBUG_ASSERT(ecm_db_nodes == ni, "%p: node table bad\n", ni);
3675 ecm_db_nodes = ni->next;
3676 } else {
3677 ni->prev->next = ni->next;
3678 }
3679 if (ni->next) {
3680 ni->next->prev = ni->prev;
3681 }
3682
3683 /*
3684 * Link out of hash table
3685 */
3686 if (!ni->hash_prev) {
3687 DEBUG_ASSERT(ecm_db_node_table[ni->hash_index] == ni, "%p: hash table bad\n", ni);
3688 ecm_db_node_table[ni->hash_index] = ni->hash_next;
3689 } else {
3690 ni->hash_prev->hash_next = ni->hash_next;
3691 }
3692 if (ni->hash_next) {
3693 ni->hash_next->hash_prev = ni->hash_prev;
3694 }
3695 ni->hash_next = NULL;
3696 ni->hash_prev = NULL;
3697 ecm_db_node_table_lengths[ni->hash_index]--;
3698 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]);
3699
Gareth Williamsb5903892015-03-20 15:13:07 +00003700#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003701 /*
3702 * Unlink it from the iface node list
3703 */
3704 if (!ni->node_prev) {
3705 DEBUG_ASSERT(ni->iface->nodes == ni, "%p: nodes table bad\n", ni);
3706 ni->iface->nodes = ni->node_next;
3707 } else {
3708 ni->node_prev->node_next = ni->node_next;
3709 }
3710 if (ni->node_next) {
3711 ni->node_next->node_prev = ni->node_prev;
3712 }
3713 ni->node_next = NULL;
3714 ni->node_prev = NULL;
3715 ni->iface->node_count--;
Gareth Williamsb5903892015-03-20 15:13:07 +00003716#endif
3717
Ben Menchaca84f36632014-02-28 20:57:38 +00003718 spin_unlock_bh(&ecm_db_lock);
3719
3720 /*
3721 * Throw removed event to listeners
3722 */
3723 DEBUG_TRACE("%p: Throw node removed event\n", ni);
3724 li = ecm_db_listeners_get_and_ref_first();
3725 while (li) {
3726 struct ecm_db_listener_instance *lin;
3727 if (li->node_removed) {
3728 li->node_removed(li->arg, ni);
3729 }
3730
3731 /*
3732 * Get next listener
3733 */
3734 lin = ecm_db_listener_get_and_ref_next(li);
3735 ecm_db_listener_deref(li);
3736 li = lin;
3737 }
3738 }
3739
3740 /*
3741 * Throw final event
3742 */
3743 if (ni->final) {
3744 ni->final(ni->arg);
3745 }
3746
3747 /*
3748 * Now release the iface instance if the node had one
3749 */
3750 if (ni->iface) {
3751 ecm_db_iface_deref(ni->iface);
3752 }
3753
3754 /*
3755 * We can now destroy the instance
3756 */
3757 DEBUG_CLEAR_MAGIC(ni);
3758 kfree(ni);
3759
3760 /*
3761 * Decrease global node count
3762 */
3763 spin_lock_bh(&ecm_db_lock);
3764 ecm_db_node_count--;
3765 DEBUG_ASSERT(ecm_db_node_count >= 0, "%p: node count wrap\n", ni);
Ben Menchaca84f36632014-02-28 20:57:38 +00003766 spin_unlock_bh(&ecm_db_lock);
3767
Ben Menchaca84f36632014-02-28 20:57:38 +00003768 return 0;
3769}
3770EXPORT_SYMBOL(ecm_db_node_deref);
3771
3772/*
3773 * ecm_db_iface_deref()
3774 * Deref a interface instance, removing it from the database on the last ref release
3775 */
3776int ecm_db_iface_deref(struct ecm_db_iface_instance *ii)
3777{
3778 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
3779
3780 /*
3781 * Decrement reference count
3782 */
3783 spin_lock_bh(&ecm_db_lock);
3784 ii->refs--;
3785 DEBUG_TRACE("%p: iface deref %d\n", ii, ii->refs);
3786 DEBUG_ASSERT(ii->refs >= 0, "%p: ref wrap\n", ii);
3787
3788 if (ii->refs > 0) {
3789 int refs = ii->refs;
3790 spin_unlock_bh(&ecm_db_lock);
3791 return refs;
3792 }
3793
Gareth Williamsb5903892015-03-20 15:13:07 +00003794#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003795 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00003796#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003797
3798 /*
3799 * Remove from database if inserted
3800 */
3801 if (!ii->flags & ECM_DB_IFACE_FLAGS_INSERTED) {
3802 spin_unlock_bh(&ecm_db_lock);
3803 } else {
3804 struct ecm_db_listener_instance *li;
3805
3806 /*
3807 * Remove from the global list
3808 */
3809 if (!ii->prev) {
3810 DEBUG_ASSERT(ecm_db_interfaces == ii, "%p: interface table bad\n", ii);
3811 ecm_db_interfaces = ii->next;
3812 } else {
3813 ii->prev->next = ii->next;
3814 }
3815 if (ii->next) {
3816 ii->next->prev = ii->prev;
3817 }
3818
3819 /*
3820 * Link out of hash table
3821 */
3822 if (!ii->hash_prev) {
3823 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);
3824 ecm_db_iface_table[ii->hash_index] = ii->hash_next;
3825 } else {
3826 ii->hash_prev->hash_next = ii->hash_next;
3827 }
3828 if (ii->hash_next) {
3829 ii->hash_next->hash_prev = ii->hash_prev;
3830 }
3831 ii->hash_next = NULL;
3832 ii->hash_prev = NULL;
3833 ecm_db_iface_table_lengths[ii->hash_index]--;
3834 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 -07003835
3836 /*
3837 * Link out of interface identifier hash table
3838 */
3839 if (!ii->iface_id_hash_prev) {
3840 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);
3841 ecm_db_iface_id_table[ii->iface_id_hash_index] = ii->iface_id_hash_next;
3842 } else {
3843 ii->iface_id_hash_prev->iface_id_hash_next = ii->iface_id_hash_next;
3844 }
3845 if (ii->iface_id_hash_next) {
3846 ii->iface_id_hash_next->iface_id_hash_prev = ii->iface_id_hash_prev;
3847 }
3848 ii->iface_id_hash_next = NULL;
3849 ii->iface_id_hash_prev = NULL;
3850 ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]--;
3851 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 +00003852 spin_unlock_bh(&ecm_db_lock);
3853
3854 /*
3855 * Throw removed event to listeners
3856 */
3857 DEBUG_TRACE("%p: Throw iface removed event\n", ii);
3858 li = ecm_db_listeners_get_and_ref_first();
3859 while (li) {
3860 struct ecm_db_listener_instance *lin;
3861 if (li->iface_removed) {
3862 li->iface_removed(li->arg, ii);
3863 }
3864
3865 /*
3866 * Get next listener
3867 */
3868 lin = ecm_db_listener_get_and_ref_next(li);
3869 ecm_db_listener_deref(li);
3870 li = lin;
3871 }
3872 }
3873
3874 /*
3875 * Throw final event
3876 */
3877 if (ii->final) {
3878 ii->final(ii->arg);
3879 }
3880
3881 /*
3882 * We can now destroy the instance
3883 */
3884 DEBUG_CLEAR_MAGIC(ii);
3885 kfree(ii);
3886
3887 /*
3888 * Decrease global interface count
3889 */
3890 spin_lock_bh(&ecm_db_lock);
3891 ecm_db_iface_count--;
3892 DEBUG_ASSERT(ecm_db_iface_count >= 0, "%p: iface count wrap\n", ii);
Ben Menchaca84f36632014-02-28 20:57:38 +00003893 spin_unlock_bh(&ecm_db_lock);
3894
Ben Menchaca84f36632014-02-28 20:57:38 +00003895 return 0;
3896}
3897EXPORT_SYMBOL(ecm_db_iface_deref);
3898
3899/*
3900 * ecm_db_listener_deref()
3901 * Release reference to listener.
3902 *
3903 * On final reference release listener shall be removed from the database.
3904 */
3905int ecm_db_listener_deref(struct ecm_db_listener_instance *li)
3906{
3907 struct ecm_db_listener_instance *cli;
3908 struct ecm_db_listener_instance **cli_prev;
3909
3910 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
3911
3912 spin_lock_bh(&ecm_db_lock);
3913 li->refs--;
3914 DEBUG_ASSERT(li->refs >= 0, "%p: ref wrap\n", li);
3915 if (li->refs > 0) {
3916 int refs;
3917 refs = li->refs;
3918 spin_unlock_bh(&ecm_db_lock);
3919 return refs;
3920 }
3921
3922 /*
3923 * Instance is to be removed and destroyed.
3924 * Link the listener out of the listener list.
3925 */
3926 cli = ecm_db_listeners;
3927 cli_prev = &ecm_db_listeners;
3928 while (cli) {
3929 if (cli == li) {
3930 *cli_prev = cli->next;
3931 break;
3932 }
3933 cli_prev = &cli->next;
3934 cli = cli->next;
3935 }
3936 DEBUG_ASSERT(cli, "%p: not found\n", li);
3937 spin_unlock_bh(&ecm_db_lock);
3938
3939 /*
3940 * Invoke final callback
3941 */
3942 if (li->final) {
3943 li->final(li->arg);
3944 }
3945 DEBUG_CLEAR_MAGIC(li);
3946 kfree(li);
3947
3948 /*
3949 * Decrease global listener count
3950 */
3951 spin_lock_bh(&ecm_db_lock);
3952 ecm_db_listeners_count--;
3953 DEBUG_ASSERT(ecm_db_listeners_count >= 0, "%p: listener count wrap\n", li);
Ben Menchaca84f36632014-02-28 20:57:38 +00003954 spin_unlock_bh(&ecm_db_lock);
3955
Ben Menchaca84f36632014-02-28 20:57:38 +00003956 return 0;
3957}
3958EXPORT_SYMBOL(ecm_db_listener_deref);
3959
3960/*
3961 * ecm_db_connection_defunct_all()
3962 * Make defunct ALL connections.
3963 *
3964 * This API is typically used in shutdown situations commanded by the user.
3965 * NOTE: Ensure all front ends are stopped to avoid further connections being created while this is running.
3966 */
3967void ecm_db_connection_defunct_all(void)
3968{
3969 struct ecm_db_connection_instance *ci;
3970
3971 DEBUG_INFO("Defuncting all\n");
3972
3973 /*
3974 * Iterate all connections
3975 */
3976 ci = ecm_db_connections_get_and_ref_first();
3977 while (ci) {
3978 struct ecm_db_connection_instance *cin;
3979
3980 DEBUG_TRACE("%p: defunct\n", ci);
3981 ecm_db_connection_make_defunct(ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05303982
Ben Menchaca84f36632014-02-28 20:57:38 +00003983 cin = ecm_db_connection_get_and_ref_next(ci);
3984 ecm_db_connection_deref(ci);
3985 ci = cin;
3986 }
3987 DEBUG_INFO("Defuncting complete\n");
3988}
3989EXPORT_SYMBOL(ecm_db_connection_defunct_all);
3990
3991/*
3992 * ecm_db_connection_generate_hash_index()
3993 * Calculate the hash index.
3994 *
3995 * Note: The hash we produce is symmetric - i.e. we can swap the "from" and "to"
3996 * details without generating a different hash index!
3997 */
3998static 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)
3999{
Gareth Williams54d15d92015-04-24 19:28:27 +01004000 uint32_t hah1;
4001 uint32_t hah2;
4002 uint32_t ht1;
Ben Menchaca84f36632014-02-28 20:57:38 +00004003 uint32_t hash_val;
4004
4005 /*
4006 * The hash function only uses both host 1 address/port, host 2 address/port
4007 * and protocol fields.
4008 */
Gareth Williams54d15d92015-04-24 19:28:27 +01004009 ECM_IP_ADDR_HASH(hah1, host1_addr);
4010 ECM_IP_ADDR_HASH(hah2, host2_addr);
4011 ht1 = (u32)hah1 + host1_port + hah2 + host2_port + (uint32_t)protocol;
4012 hash_val = (uint32_t)jhash_1word(ht1, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00004013 return (ecm_db_connection_hash_t)(hash_val & (ECM_DB_CONNECTION_HASH_SLOTS - 1));
4014}
4015
4016/*
4017 * ecm_db_connection_generate_serial_hash_index()
4018 * Calculate the serial hash index.
4019 */
4020static inline ecm_db_connection_serial_hash_t ecm_db_connection_generate_serial_hash_index(uint32_t serial)
4021{
Gareth Williams54d15d92015-04-24 19:28:27 +01004022 uint32_t hash_val;
4023 hash_val = (uint32_t)jhash_1word(serial, ecm_db_jhash_rnd);
4024
4025 return (ecm_db_connection_serial_hash_t)(hash_val & (ECM_DB_CONNECTION_SERIAL_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00004026}
4027
Shyam Sunder1f037262015-05-18 20:04:13 +05304028#ifdef ECM_MULTICAST_ENABLE
4029/*
4030 * ecm_db_multicast_generate_hash_index()
4031 * Calculate the hash index given a multicast group address.
4032 */
4033static inline ecm_db_multicast_tuple_instance_hash_t ecm_db_multicast_generate_hash_index(ip_addr_t address)
4034{
4035 uint32_t temp;
4036 uint32_t hash_val;
4037
4038 if (ECM_IP_ADDR_IS_V4(address)){
4039 temp = (uint32_t)address[0];
4040 } else {
4041 temp = (uint32_t)address[3];
4042 }
4043
4044 hash_val = (uint32_t)jhash_1word(temp, ecm_db_jhash_rnd);
4045
4046 return (ecm_db_multicast_tuple_instance_hash_t)(hash_val & (ECM_DB_MULTICAST_TUPLE_INSTANCE_HASH_SLOTS - 1));
4047}
4048#endif
4049
Ben Menchaca84f36632014-02-28 20:57:38 +00004050/*
4051 * ecm_db_mapping_generate_hash_index()
4052 * Calculate the hash index.
4053 */
4054static inline ecm_db_mapping_hash_t ecm_db_mapping_generate_hash_index(ip_addr_t address, uint32_t port)
4055{
Gareth Williams54d15d92015-04-24 19:28:27 +01004056 uint32_t tuple;
Ben Menchaca84f36632014-02-28 20:57:38 +00004057 uint32_t hash_val;
4058
Gareth Williams54d15d92015-04-24 19:28:27 +01004059 ECM_IP_ADDR_HASH(tuple, address);
4060 hash_val = (uint32_t)jhash_2words(tuple, port, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00004061 return (ecm_db_mapping_hash_t)(hash_val & (ECM_DB_MAPPING_HASH_SLOTS - 1));
4062}
4063
4064/*
4065 * ecm_db_host_generate_hash_index()
4066 * Calculate the hash index.
4067 */
4068static inline ecm_db_host_hash_t ecm_db_host_generate_hash_index(ip_addr_t address)
4069{
Gareth Williams54d15d92015-04-24 19:28:27 +01004070 uint32_t tuple;
Ben Menchaca84f36632014-02-28 20:57:38 +00004071 uint32_t hash_val;
4072
Gareth Williams54d15d92015-04-24 19:28:27 +01004073 ECM_IP_ADDR_HASH(tuple, address);
4074 hash_val = (uint32_t)jhash_1word(tuple, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00004075 return (ecm_db_host_hash_t)(hash_val & (ECM_DB_HOST_HASH_SLOTS - 1));
4076}
4077
4078/*
4079 * ecm_db_node_generate_hash_index()
4080 * Calculate the hash index.
4081 */
4082static inline ecm_db_node_hash_t ecm_db_node_generate_hash_index(uint8_t *address)
4083{
4084 uint32_t hash_val;
4085
Gareth Williams54d15d92015-04-24 19:28:27 +01004086 hash_val = (uint32_t)jhash(address, 6, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00004087 hash_val &= (ECM_DB_NODE_HASH_SLOTS - 1);
4088
4089 return (ecm_db_node_hash_t)hash_val;
4090}
4091
Murat Sezgin91c5d712015-06-12 15:16:22 -07004092/*
4093 * ecm_db_iface_id_generate_hash_index()
4094 * Calculate the hash index based on interface identifier.
4095 */
4096static inline ecm_db_iface_id_hash_t ecm_db_iface_id_generate_hash_index(int32_t interface_id)
4097{
4098 uint32_t hash_val;
4099
4100 hash_val = (uint32_t)jhash_1word((uint32_t)interface_id, ecm_db_jhash_rnd);
4101 return (ecm_db_iface_id_hash_t)(hash_val & (ECM_DB_IFACE_ID_HASH_SLOTS - 1));
4102}
4103
Murat Sezginbde55f92015-03-11 16:44:11 -07004104#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004105/*
4106 * ecm_db_iface_generate_hash_index_sit()
4107 * Calculate the hash index.
4108 */
4109static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_sit(ip_addr_t saddr, ip_addr_t daddr)
4110{
Gareth Williams54d15d92015-04-24 19:28:27 +01004111 uint32_t tuple1;
4112 uint32_t tuple2;
Ben Menchaca84f36632014-02-28 20:57:38 +00004113 uint32_t hash_val;
4114
Gareth Williams54d15d92015-04-24 19:28:27 +01004115 ECM_IP_ADDR_HASH(tuple1, saddr);
4116 ECM_IP_ADDR_HASH(tuple2, daddr);
4117 hash_val = (uint32_t)jhash_2words(tuple1, tuple2, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00004118 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
4119}
Murat Sezginbde55f92015-03-11 16:44:11 -07004120#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004121
Murat Sezginc1402562015-03-12 12:32:20 -07004122#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +00004123#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004124/*
4125 * ecm_db_iface_generate_hash_index_tunipip6()
4126 * Calculate the hash index.
4127 */
4128static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_tunipip6(ip_addr_t saddr, ip_addr_t daddr)
4129{
Gareth Williams54d15d92015-04-24 19:28:27 +01004130 uint32_t tuple1;
4131 uint32_t tuple2;
Ben Menchaca84f36632014-02-28 20:57:38 +00004132 uint32_t hash_val;
4133
Gareth Williams54d15d92015-04-24 19:28:27 +01004134 ECM_IP_ADDR_HASH(tuple1, saddr);
4135 ECM_IP_ADDR_HASH(tuple2, daddr);
4136 hash_val = (uint32_t)jhash_2words(tuple1, tuple2, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00004137 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
4138}
Murat Sezginc1402562015-03-12 12:32:20 -07004139#endif
Gareth Williams8ac34292015-03-17 14:06:58 +00004140#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004141
4142/*
4143 * ecm_db_iface_generate_hash_index_ethernet()
4144 * Calculate the hash index.
4145 */
4146static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_ethernet(uint8_t *address)
4147{
Gareth Williams54d15d92015-04-24 19:28:27 +01004148 uint32_t hash_val;
4149 hash_val = (uint32_t)jhash(address, 6, ecm_db_jhash_rnd);
4150 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00004151}
4152
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304153#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004154/*
4155 * ecm_db_iface_generate_hash_index_pppoe()
4156 * Calculate the hash index.
4157 */
4158static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pppoe(uint16_t pppoe_session_id)
4159{
Gareth Williams54d15d92015-04-24 19:28:27 +01004160 uint32_t hash_val;
4161 hash_val = (uint32_t)jhash_1word((uint32_t)pppoe_session_id, ecm_db_jhash_rnd);
4162 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00004163}
Murat Sezginaad635c2015-03-06 16:11:41 -08004164#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004165
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304166#ifdef ECM_INTERFACE_L2TPV2_ENABLE
4167/*
4168 * ecm_db_iface_generate_hash_index_pppol2tpv2()
4169 * Calculate the hash index.
4170 */
4171static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pppol2tpv2(uint32_t pppol2tpv2_tunnel_id, uint32_t pppol2tpv2_session_id)
4172{
4173 uint32_t hash_val;
4174 hash_val = (uint32_t)jhash_2words(pppol2tpv2_tunnel_id, pppol2tpv2_session_id, ecm_db_jhash_rnd);
4175 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
4176}
4177
4178#endif
4179
Shyam Sunder23f2e542015-09-28 14:56:49 +05304180#ifdef ECM_INTERFACE_PPTP_ENABLE
4181/*
4182 * ecm_db_iface_generate_hash_index_pptp()
4183 * Calculate the hash index.
4184 */
4185static 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)
4186{
4187 uint32_t hash_val;
4188 hash_val = (uint32_t)jhash_2words(pptp_src_call_id, pptp_dst_call_id, ecm_db_jhash_rnd);
4189 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
4190}
4191#endif
ratheesh kannothcfdcb332015-12-24 07:19:18 +05304192
4193#ifdef ECM_INTERFACE_MAP_T_ENABLE
4194/*
4195 * ecm_db_iface_generate_hash_index_map_t()
4196 * Calculate the hash index.
4197 */
4198static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_map_t(int if_index)
4199{
4200 uint32_t hash_val;
4201 hash_val = (uint32_t)jhash_1word(if_index, ecm_db_jhash_rnd);
4202 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
4203}
4204#endif
4205
Ben Menchaca84f36632014-02-28 20:57:38 +00004206/*
4207 * ecm_db_iface_generate_hash_index_unknown()
4208 * Calculate the hash index.
4209 */
4210static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_unknown(uint32_t os_specific_ident)
4211{
Gareth Williams54d15d92015-04-24 19:28:27 +01004212 uint32_t hash_val;
4213 hash_val = (uint32_t)jhash_1word(os_specific_ident, ecm_db_jhash_rnd);
4214 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00004215}
4216
4217/*
4218 * ecm_db_iface_generate_hash_index_loopback()
4219 * Calculate the hash index.
4220 */
4221static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_loopback(uint32_t os_specific_ident)
4222{
Gareth Williams54d15d92015-04-24 19:28:27 +01004223 uint32_t hash_val;
4224 hash_val = (uint32_t)jhash_1word(os_specific_ident, ecm_db_jhash_rnd);
4225 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00004226}
4227
Murat Sezgin69a27532015-03-12 14:09:40 -07004228#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004229/*
4230 * ecm_db_iface_generate_hash_index_ipsec_tunnel()
4231 * Calculate the hash index.
4232 * GGG TODO Flesh this out using actual tunnel endpoint keys
4233 */
4234static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_ipsec_tunnel(uint32_t os_specific_ident)
4235{
Gareth Williams54d15d92015-04-24 19:28:27 +01004236 uint32_t hash_val;
4237 hash_val = (uint32_t)jhash_1word(os_specific_ident, ecm_db_jhash_rnd);
4238 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00004239}
Murat Sezgin69a27532015-03-12 14:09:40 -07004240#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004241
4242/*
4243 * ecm_db_host_find_and_ref()
4244 * Lookup and return a host reference if any
4245 */
4246struct ecm_db_host_instance *ecm_db_host_find_and_ref(ip_addr_t address)
4247{
4248 ecm_db_host_hash_t hash_index;
4249 struct ecm_db_host_instance *hi;
4250
4251 DEBUG_TRACE("Lookup host with addr " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(address));
4252
4253 /*
4254 * Compute the hash chain index and prepare to walk the chain
4255 */
4256 hash_index = ecm_db_host_generate_hash_index(address);
4257
4258 /*
4259 * Iterate the chain looking for a host with matching details
4260 */
4261 spin_lock_bh(&ecm_db_lock);
4262 hi = ecm_db_host_table[hash_index];
4263 while (hi) {
4264 if (!ECM_IP_ADDR_MATCH(hi->address, address)) {
4265 hi = hi->hash_next;
4266 continue;
4267 }
4268
4269 _ecm_db_host_ref(hi);
4270 spin_unlock_bh(&ecm_db_lock);
4271 DEBUG_TRACE("host found %p\n", hi);
4272 return hi;
4273 }
4274 spin_unlock_bh(&ecm_db_lock);
4275 DEBUG_TRACE("Host not found\n");
4276 return NULL;
4277}
4278EXPORT_SYMBOL(ecm_db_host_find_and_ref);
4279
4280/*
Murat Sezgina5f3de12016-08-02 17:29:30 -07004281 * ecm_db_node_is_mac_addr_equal()
4282 * Compares the node's mac address with the given mac address.
4283 */
4284bool ecm_db_node_is_mac_addr_equal(struct ecm_db_node_instance *ni, uint8_t *address)
4285{
4286 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
4287
4288 if (ecm_mac_addr_equal(ni->address, address)) {
4289 return false;
4290 }
4291
4292 return true;
4293}
4294EXPORT_SYMBOL(ecm_db_node_is_mac_addr_equal);
4295
4296/*
Ben Menchaca84f36632014-02-28 20:57:38 +00004297 * ecm_db_node_find_and_ref()
4298 * Lookup and return a node reference if any
4299 */
Murat Sezgina5f3de12016-08-02 17:29:30 -07004300struct 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 +00004301{
4302 ecm_db_node_hash_t hash_index;
4303 struct ecm_db_node_instance *ni;
4304
Murat Sezgina5f3de12016-08-02 17:29:30 -07004305 DEBUG_TRACE("Lookup node with addr %pMi and iface %p\n", address, ii);
Ben Menchaca84f36632014-02-28 20:57:38 +00004306
4307 /*
4308 * Compute the hash chain index and prepare to walk the chain
4309 */
4310 hash_index = ecm_db_node_generate_hash_index(address);
4311
4312 /*
4313 * Iterate the chain looking for a host with matching details
4314 */
4315 spin_lock_bh(&ecm_db_lock);
4316 ni = ecm_db_node_table[hash_index];
4317 while (ni) {
4318 if (memcmp(ni->address, address, ETH_ALEN)) {
4319 ni = ni->hash_next;
4320 continue;
4321 }
4322
Murat Sezgina5f3de12016-08-02 17:29:30 -07004323 if (ni->iface != ii) {
4324 ni = ni->hash_next;
4325 continue;
4326 }
4327
Ben Menchaca84f36632014-02-28 20:57:38 +00004328 _ecm_db_node_ref(ni);
4329 spin_unlock_bh(&ecm_db_lock);
4330 DEBUG_TRACE("node found %p\n", ni);
4331 return ni;
4332 }
4333 spin_unlock_bh(&ecm_db_lock);
4334 DEBUG_TRACE("Node not found\n");
4335 return NULL;
4336}
4337EXPORT_SYMBOL(ecm_db_node_find_and_ref);
4338
4339/*
Murat Sezgina5f3de12016-08-02 17:29:30 -07004340 * ecm_db_node_chain_get_and_ref_first()
4341 * Gets and refs the first node in the chain of that mac address.
4342 */
4343struct ecm_db_node_instance *ecm_db_node_chain_get_and_ref_first(uint8_t *address)
4344{
4345 ecm_db_node_hash_t hash_index;
4346 struct ecm_db_node_instance *ni;
4347
4348 DEBUG_TRACE("Get the first node with addr %pMi in the chain\n", address);
4349
4350 /*
4351 * Compute the hash chain index.
4352 */
4353 hash_index = ecm_db_node_generate_hash_index(address);
4354
4355 spin_lock_bh(&ecm_db_lock);
4356 ni = ecm_db_node_table[hash_index];
4357 if (ni) {
4358 _ecm_db_node_ref(ni);
4359 }
4360 spin_unlock_bh(&ecm_db_lock);
4361
4362 return ni;
4363}
4364EXPORT_SYMBOL(ecm_db_node_chain_get_and_ref_first);
4365
4366/*
4367 * ecm_db_node_chain_get_and_ref_next()
4368 * Gets and refs the next node in the chain..
4369 */
4370struct ecm_db_node_instance *ecm_db_node_chain_get_and_ref_next(struct ecm_db_node_instance *ni)
4371{
4372 struct ecm_db_node_instance *nin;
4373 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
4374
4375 spin_lock_bh(&ecm_db_lock);
4376 nin = ni->hash_next;
4377 if (nin) {
4378 _ecm_db_node_ref(nin);
4379 }
4380 spin_unlock_bh(&ecm_db_lock);
4381 return nin;
4382}
4383EXPORT_SYMBOL(ecm_db_node_chain_get_and_ref_next);
4384
4385/*
Ben Menchaca84f36632014-02-28 20:57:38 +00004386 * ecm_db_iface_ethernet_address_get()
4387 * Obtain the ethernet address for an ethernet interface
4388 */
4389void ecm_db_iface_ethernet_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
4390{
4391 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4392 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_ETHERNET, "%p: Bad type, expected ethernet, actual: %d\n", ii, ii->type);
4393 spin_lock_bh(&ecm_db_lock);
4394 memcpy(address, ii->type_info.ethernet.address, sizeof(ii->type_info.ethernet.address));
4395 spin_unlock_bh(&ecm_db_lock);
4396}
4397EXPORT_SYMBOL(ecm_db_iface_ethernet_address_get);
4398
4399/*
Gareth Williams83125b12014-05-26 19:58:09 +01004400 * ecm_db_iface_bridge_address_get()
4401 * Obtain the ethernet address for a bridge interface
4402 */
4403void ecm_db_iface_bridge_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
4404{
4405 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4406 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_BRIDGE, "%p: Bad type, expected bridge, actual: %d\n", ii, ii->type);
4407 spin_lock_bh(&ecm_db_lock);
4408 memcpy(address, ii->type_info.bridge.address, sizeof(ii->type_info.bridge.address));
4409 spin_unlock_bh(&ecm_db_lock);
4410}
4411EXPORT_SYMBOL(ecm_db_iface_bridge_address_get);
4412
Gareth Williamsf98d4192015-03-11 16:55:41 +00004413/*
Shyam Sunder39e25672015-09-03 14:28:09 +05304414 * _ecm_db_iface_identifier_hash_table_insert_entry()
4415 * Calculate the hash index based on updated interface_identifier, and
4416 * re-insert into interface identifier chain.
4417 *
4418 * Note: Must take ecm_db_lock before calling this.
4419 */
4420static void _ecm_db_iface_identifier_hash_table_insert_entry(struct ecm_db_iface_instance *ii, int32_t interface_identifier)
4421{
4422 ecm_db_iface_id_hash_t iface_id_hash_index;
4423
4424 /*
4425 * Compute hash chain for insertion
4426 */
4427 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
4428 ii->iface_id_hash_index = iface_id_hash_index;
4429
4430 /*
4431 * Insert into interface identifier chain
4432 */
4433 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
4434 if (ecm_db_iface_id_table[iface_id_hash_index]) {
4435 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
4436 }
4437
4438 ecm_db_iface_id_table[iface_id_hash_index] = ii;
4439 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
4440 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]);
4441}
4442
4443/*
4444 * _ecm_db_iface_identifier_hash_table_remove_entry()
4445 * Remove an entry of a given interface instance from interface identifier chain.
4446 *
4447 * Note: Must take ecm_db_lock before calling this.
4448 */
4449static void _ecm_db_iface_identifier_hash_table_remove_entry(struct ecm_db_iface_instance *ii)
4450{
4451 /*
4452 * Remove from database if inserted
4453 */
4454 if (!ii->flags & ECM_DB_IFACE_FLAGS_INSERTED) {
4455 return;
4456 }
4457
4458 /*
4459 * Link out of interface identifier hash table
4460 */
4461 if (!ii->iface_id_hash_prev) {
4462 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);
4463 ecm_db_iface_id_table[ii->iface_id_hash_index] = ii->iface_id_hash_next;
4464 } else {
4465 ii->iface_id_hash_prev->iface_id_hash_next = ii->iface_id_hash_next;
4466 }
4467
4468 if (ii->iface_id_hash_next) {
4469 ii->iface_id_hash_next->iface_id_hash_prev = ii->iface_id_hash_prev;
4470 }
4471
4472 ii->iface_id_hash_next = NULL;
4473 ii->iface_id_hash_prev = NULL;
4474 ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]--;
4475 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]);
4476}
4477
4478/*
4479 * ecm_db_iface_identifier_hash_table_entry_check_and_update()
4480 * Update the hash table entry of interface identifier hash table.
4481 * First remove the 'ii' from curent hash index position, re-calculate new hash and re-insert
4482 * the 'ii' at new hash index position into interface identifier hash table.
4483 */
4484void ecm_db_iface_identifier_hash_table_entry_check_and_update(struct ecm_db_iface_instance *ii, int32_t new_interface_identifier)
4485{
4486 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4487 spin_lock_bh(&ecm_db_lock);
4488 if (ii->interface_identifier == new_interface_identifier) {
4489 spin_unlock_bh(&ecm_db_lock);
4490 return;
4491 }
4492
4493 DEBUG_TRACE("%p: interface ifindex has changed Old %d, New %d \n", ii, ii->interface_identifier, new_interface_identifier);
4494 _ecm_db_iface_identifier_hash_table_remove_entry(ii);
4495 ii->interface_identifier = new_interface_identifier;
4496 _ecm_db_iface_identifier_hash_table_insert_entry(ii, new_interface_identifier);
4497 spin_unlock_bh(&ecm_db_lock);
4498}
4499EXPORT_SYMBOL(ecm_db_iface_identifier_hash_table_entry_check_and_update);
4500
4501/*
Murat Sezgin91c5d712015-06-12 15:16:22 -07004502 * ecm_db_iface_find_and_ref_by_interface_identifier()
4503 * Return an interface based on a hlos interface identifier
4504 */
4505struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_by_interface_identifier(int32_t interface_id)
4506{
4507 ecm_db_iface_id_hash_t hash_index;
4508 struct ecm_db_iface_instance *ii;
4509
4510 DEBUG_TRACE("Lookup database iface with interface_id %d\n", interface_id);
4511
4512 /*
4513 * Compute the hash chain index and prepare to walk the chain
4514 */
4515 hash_index = ecm_db_iface_id_generate_hash_index(interface_id);
4516
4517 /*
4518 * Iterate the chain looking for a host with matching details
4519 */
4520 spin_lock_bh(&ecm_db_lock);
4521 ii = ecm_db_iface_id_table[hash_index];
Murat Sezgin91c5d712015-06-12 15:16:22 -07004522 while (ii) {
Murat Sezgin91c5d712015-06-12 15:16:22 -07004523 if (ii->interface_identifier == interface_id) {
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004524 _ecm_db_iface_ref(ii);
4525 spin_unlock_bh(&ecm_db_lock);
Murat Sezgin91c5d712015-06-12 15:16:22 -07004526 DEBUG_TRACE("iface found %p\n", ii);
4527 return ii;
4528 }
4529
4530 /*
4531 * Try next
4532 */
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004533 ii = ii->iface_id_hash_next;
Murat Sezgin91c5d712015-06-12 15:16:22 -07004534 }
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004535 spin_unlock_bh(&ecm_db_lock);
Murat Sezgin91c5d712015-06-12 15:16:22 -07004536 DEBUG_TRACE("Iface not found\n");
4537 return NULL;
4538}
4539EXPORT_SYMBOL(ecm_db_iface_find_and_ref_by_interface_identifier);
4540
4541/*
Gareth Williamsf98d4192015-03-11 16:55:41 +00004542 * ecm_db_iface_ifidx_find_and_ref_ethernet()
4543 * Return an interface based on a MAC address and interface hlos interface identifier
4544 */
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304545struct 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 +00004546{
4547 ecm_db_iface_hash_t hash_index;
4548 struct ecm_db_iface_instance *ii;
4549
4550 DEBUG_TRACE("Lookup ethernet iface with addr %pM\n", address);
4551
4552 /*
4553 * Compute the hash chain index and prepare to walk the chain
4554 */
4555 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
4556
4557 /*
4558 * Iterate the chain looking for a host with matching details
4559 */
4560 spin_lock_bh(&ecm_db_lock);
4561 ii = ecm_db_iface_table[hash_index];
4562 while (ii) {
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304563 if ((ii->type != ECM_DB_IFACE_TYPE_ETHERNET)
4564 || memcmp(ii->type_info.ethernet.address, address, ETH_ALEN)
4565 || ii->interface_identifier != ifidx) {
Ben Menchaca84f36632014-02-28 20:57:38 +00004566 ii = ii->hash_next;
4567 continue;
4568 }
4569
4570 _ecm_db_iface_ref(ii);
4571 spin_unlock_bh(&ecm_db_lock);
4572 DEBUG_TRACE("iface found %p\n", ii);
4573 return ii;
4574 }
4575 spin_unlock_bh(&ecm_db_lock);
4576 DEBUG_TRACE("Iface not found\n");
4577 return NULL;
4578}
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304579EXPORT_SYMBOL(ecm_db_iface_ifidx_find_and_ref_ethernet);
4580
Murat Sezgin37fb3952015-03-10 16:45:13 -07004581#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004582/*
4583 * ecm_db_iface_vlan_info_get()
4584 * Get vlan interface specific information
4585 */
4586void ecm_db_iface_vlan_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_vlan *vlan_info)
4587{
4588 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4589 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_VLAN, "%p: Bad type, expected vlan, actual: %d\n", ii, ii->type);
4590 spin_lock_bh(&ecm_db_lock);
4591 memcpy(vlan_info->address, ii->type_info.vlan.address, sizeof(ii->type_info.vlan.address));
4592 vlan_info->vlan_tag = ii->type_info.vlan.vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304593 vlan_info->vlan_tpid = ii->type_info.vlan.vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00004594 spin_unlock_bh(&ecm_db_lock);
4595}
4596EXPORT_SYMBOL(ecm_db_iface_vlan_info_get);
4597
4598/*
4599 * ecm_db_iface_find_and_ref_vlan()
4600 * Lookup and return a iface reference if any
4601 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304602struct 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 +00004603{
4604 ecm_db_iface_hash_t hash_index;
4605 struct ecm_db_iface_instance *ii;
4606
Sol Kavyd7583592014-06-05 18:51:46 -07004607 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 +00004608
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_VLAN) || (ii->type_info.vlan.vlan_tag != vlan_tag)
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304621 || (ii->type_info.vlan.vlan_tpid != vlan_tpid)
Ben Menchaca84f36632014-02-28 20:57:38 +00004622 || memcmp(ii->type_info.vlan.address, address, ETH_ALEN)) {
4623 ii = ii->hash_next;
4624 continue;
4625 }
4626
4627 _ecm_db_iface_ref(ii);
4628 spin_unlock_bh(&ecm_db_lock);
4629 DEBUG_TRACE("iface found %p\n", ii);
4630 return ii;
4631 }
4632 spin_unlock_bh(&ecm_db_lock);
4633 DEBUG_TRACE("Iface not found\n");
4634 return NULL;
4635}
4636EXPORT_SYMBOL(ecm_db_iface_find_and_ref_vlan);
Murat Sezgin37fb3952015-03-10 16:45:13 -07004637#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004638
4639/*
4640 * ecm_db_iface_find_and_ref_bridge()
4641 * Lookup and return a iface reference if any
4642 */
4643struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_bridge(uint8_t *address)
4644{
4645 ecm_db_iface_hash_t hash_index;
4646 struct ecm_db_iface_instance *ii;
4647
4648 DEBUG_TRACE("Lookup bridge iface with addr %pM\n", address);
4649
4650 /*
4651 * Compute the hash chain index and prepare to walk the chain
4652 */
4653 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
4654
4655 /*
4656 * Iterate the chain looking for a host with matching details
4657 */
4658 spin_lock_bh(&ecm_db_lock);
4659 ii = ecm_db_iface_table[hash_index];
4660 while (ii) {
4661 if ((ii->type != ECM_DB_IFACE_TYPE_BRIDGE) || memcmp(ii->type_info.bridge.address, address, ETH_ALEN)) {
4662 ii = ii->hash_next;
4663 continue;
4664 }
4665
4666 _ecm_db_iface_ref(ii);
4667 spin_unlock_bh(&ecm_db_lock);
4668 DEBUG_TRACE("iface found %p\n", ii);
4669 return ii;
4670 }
4671 spin_unlock_bh(&ecm_db_lock);
4672 DEBUG_TRACE("Iface not found\n");
4673 return NULL;
4674}
4675EXPORT_SYMBOL(ecm_db_iface_find_and_ref_bridge);
4676
Murat Sezgin910c9662015-03-11 16:15:06 -07004677#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004678/*
4679 * ecm_db_iface_find_and_ref_lag()
4680 * Lookup and return a iface reference if any
4681 */
4682struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_lag(uint8_t *address)
4683{
4684 ecm_db_iface_hash_t hash_index;
4685 struct ecm_db_iface_instance *ii;
4686
4687 DEBUG_TRACE("Lookup lag iface with addr %pM\n", address);
4688
4689 /*
4690 * Compute the hash chain index and prepare to walk the chain
4691 */
4692 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
4693
4694 /*
4695 * Iterate the chain looking for a host with matching details
4696 */
4697 spin_lock_bh(&ecm_db_lock);
4698 ii = ecm_db_iface_table[hash_index];
4699 while (ii) {
4700 if ((ii->type != ECM_DB_IFACE_TYPE_LAG) || memcmp(ii->type_info.lag.address, address, ETH_ALEN)) {
4701 ii = ii->hash_next;
4702 continue;
4703 }
4704
4705 _ecm_db_iface_ref(ii);
4706 spin_unlock_bh(&ecm_db_lock);
4707 DEBUG_TRACE("iface found %p\n", ii);
4708 return ii;
4709 }
4710 spin_unlock_bh(&ecm_db_lock);
4711 DEBUG_TRACE("Iface not found\n");
4712 return NULL;
4713}
4714EXPORT_SYMBOL(ecm_db_iface_find_and_ref_lag);
Murat Sezgin910c9662015-03-11 16:15:06 -07004715#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004716
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304717#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004718/*
4719 * ecm_db_iface_pppoe_session_info_get()
Murat Sezgin37fb3952015-03-10 16:45:13 -07004720 * Get pppoe interface specific information
Ben Menchaca84f36632014-02-28 20:57:38 +00004721 */
4722void ecm_db_iface_pppoe_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppoe *pppoe_info)
4723{
4724 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4725 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPPOE, "%p: Bad type, expected pppoe, actual: %d\n", ii, ii->type);
4726 spin_lock_bh(&ecm_db_lock);
4727 memcpy(pppoe_info->remote_mac, ii->type_info.pppoe.remote_mac, sizeof(ii->type_info.pppoe.remote_mac));
4728 pppoe_info->pppoe_session_id = ii->type_info.pppoe.pppoe_session_id;
4729 spin_unlock_bh(&ecm_db_lock);
4730}
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304731
Ben Menchaca84f36632014-02-28 20:57:38 +00004732EXPORT_SYMBOL(ecm_db_iface_pppoe_session_info_get);
4733
4734/*
4735 * ecm_db_iface_find_and_ref_pppoe()
4736 * Lookup and return a iface reference if any
4737 */
4738struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pppoe(uint16_t pppoe_session_id, uint8_t *remote_mac)
4739{
4740 ecm_db_iface_hash_t hash_index;
4741 struct ecm_db_iface_instance *ii;
4742
4743 DEBUG_TRACE("Lookup pppoe iface with addr %x\n", pppoe_session_id);
4744
4745 /*
4746 * Compute the hash chain index and prepare to walk the chain
4747 */
4748 hash_index = ecm_db_iface_generate_hash_index_pppoe(pppoe_session_id);
4749
4750 /*
4751 * Iterate the chain looking for a host with matching details
4752 */
4753 spin_lock_bh(&ecm_db_lock);
4754 ii = ecm_db_iface_table[hash_index];
4755 while (ii) {
4756 if ((ii->type != ECM_DB_IFACE_TYPE_PPPOE)
4757 || (ii->type_info.pppoe.pppoe_session_id != pppoe_session_id)
4758 || memcmp(ii->type_info.pppoe.remote_mac, remote_mac, ETH_ALEN)) {
4759 ii = ii->hash_next;
4760 continue;
4761 }
4762
4763 _ecm_db_iface_ref(ii);
4764 spin_unlock_bh(&ecm_db_lock);
4765 DEBUG_TRACE("iface found %p\n", ii);
4766 return ii;
4767 }
4768 spin_unlock_bh(&ecm_db_lock);
4769 DEBUG_TRACE("Iface not found\n");
4770 return NULL;
4771}
4772EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pppoe);
Murat Sezginaad635c2015-03-06 16:11:41 -08004773#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004774
ratheesh kannothed721852015-09-28 12:39:52 +05304775/*
4776 * ecm_db_iface_update_ae_interface_identifier()
4777 * update ae_interface_identifier in iface instance.
4778 */
4779void ecm_db_iface_update_ae_interface_identifier(struct ecm_db_iface_instance *ii, int32_t ae_interface_identifier)
4780{
4781 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304782
ratheesh kannothed721852015-09-28 12:39:52 +05304783 spin_lock_bh(&ecm_db_lock);
4784 if (ii->ae_interface_identifier == ae_interface_identifier) {
4785 spin_unlock_bh(&ecm_db_lock);
4786 return;
4787 }
4788 ii->ae_interface_identifier = ae_interface_identifier;
4789 spin_unlock_bh(&ecm_db_lock);
4790}
4791EXPORT_SYMBOL(ecm_db_iface_update_ae_interface_identifier);
4792
4793#ifdef ECM_INTERFACE_L2TPV2_ENABLE
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304794/*
4795 * ecm_db_iface_pppol2tpv2_session_info_get
4796 * get l2tpv2 specific info
4797 */
4798void ecm_db_iface_pppol2tpv2_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppol2tpv2 *pppol2tpv2_info)
4799{
4800 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4801 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPPOL2TPV2, "%p: Bad type, expected pppol2tpv2, actual: %d\n", ii, ii->type);
4802 spin_lock_bh(&ecm_db_lock);
4803 memcpy(pppol2tpv2_info, &ii->type_info.pppol2tpv2, sizeof(struct ecm_db_interface_info_pppol2tpv2));
4804 spin_unlock_bh(&ecm_db_lock);
4805}
4806EXPORT_SYMBOL(ecm_db_iface_pppol2tpv2_session_info_get);
4807
4808/*
4809 * ecm_db_iface_find_and_ref_pppol2tpv2()
4810 * Lookup and return a iface reference if any
4811 */
4812struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pppol2tpv2(uint32_t pppol2tpv2_tunnel_id, uint32_t pppol2tpv2_session_id)
4813{
4814 ecm_db_iface_hash_t hash_index;
4815 struct ecm_db_iface_instance *ii;
4816
4817 /*
4818 * Compute the hash chain index and prepare to walk the chain
4819 */
4820 hash_index = ecm_db_iface_generate_hash_index_pppol2tpv2(pppol2tpv2_tunnel_id, pppol2tpv2_session_id);
4821
4822 DEBUG_TRACE("Lookup pppol2tpv2 iface with local_tunnel_id = %d, local_session_id = %d, hash = 0x%x\n", pppol2tpv2_tunnel_id,
4823 pppol2tpv2_session_id, hash_index);
4824
4825 /*
4826 * Iterate the chain looking for a host with matching details
4827 */
4828 spin_lock_bh(&ecm_db_lock);
4829 ii = ecm_db_iface_table[hash_index];
4830
4831 while (ii) {
4832 if ((ii->type != ECM_DB_IFACE_TYPE_PPPOL2TPV2)
4833 || (ii->type_info.pppol2tpv2.l2tp.session.session_id != pppol2tpv2_session_id)
4834 || (ii->type_info.pppol2tpv2.l2tp.tunnel.tunnel_id != pppol2tpv2_tunnel_id)) {
4835 ii = ii->hash_next;
4836 continue;
4837 }
4838
4839 _ecm_db_iface_ref(ii);
4840 spin_unlock_bh(&ecm_db_lock);
4841 DEBUG_TRACE("iface found %p\n", ii);
4842 return ii;
4843 }
4844 spin_unlock_bh(&ecm_db_lock);
4845
4846 DEBUG_TRACE("Iface not found\n");
4847 return NULL;
4848}
4849EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pppol2tpv2);
4850
4851#endif
4852
Shyam Sunder23f2e542015-09-28 14:56:49 +05304853#ifdef ECM_INTERFACE_PPTP_ENABLE
4854/*
4855 * ecm_db_iface_pptp_session_info_get
4856 * get pptp specific info
4857 */
4858void ecm_db_iface_pptp_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info)
4859{
4860 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4861 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPTP, "%p: Bad type, expected pptp, actual: %d\n", ii, ii->type);
4862 spin_lock_bh(&ecm_db_lock);
4863 memcpy(pptp_info, &ii->type_info.pptp, sizeof(struct ecm_db_interface_info_pptp));
4864 spin_unlock_bh(&ecm_db_lock);
4865}
4866EXPORT_SYMBOL(ecm_db_iface_pptp_session_info_get);
4867
4868/*
4869 * ecm_db_iface_find_and_ref_pptp()
4870 * Lookup and return a iface reference if any
4871 */
4872struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pptp(uint32_t pptp_src_call_id, uint32_t pptp_dst_call_id)
4873{
4874 ecm_db_iface_hash_t hash_index;
4875 struct ecm_db_iface_instance *ii;
4876
4877 /*
4878 * Compute the hash chain index and prepare to walk the chain
4879 */
4880 hash_index = ecm_db_iface_generate_hash_index_pptp(pptp_src_call_id, pptp_dst_call_id);
4881
4882 DEBUG_TRACE("Lookup pptp iface with local_call_id = %d, remote_call_id = %d, hash = 0x%x\n", pptp_src_call_id,
4883 pptp_dst_call_id, hash_index);
4884
4885 /*
4886 * Iterate the chain looking for a host with matching details
4887 */
4888 spin_lock_bh(&ecm_db_lock);
4889 ii = ecm_db_iface_table[hash_index];
4890
4891 while (ii) {
4892 if ((ii->type != ECM_DB_IFACE_TYPE_PPTP)
4893 || (ii->type_info.pptp.src_call_id != pptp_src_call_id)
4894 || (ii->type_info.pptp.dst_call_id != pptp_dst_call_id)) {
4895 ii = ii->hash_next;
4896 continue;
4897 }
4898
4899 _ecm_db_iface_ref(ii);
4900 spin_unlock_bh(&ecm_db_lock);
4901 DEBUG_TRACE("iface found %p\n", ii);
4902 return ii;
4903 }
4904 spin_unlock_bh(&ecm_db_lock);
4905
4906 DEBUG_TRACE("Iface not found\n");
4907 return NULL;
4908}
4909EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pptp);
4910#endif
4911
ratheesh kannothcfdcb332015-12-24 07:19:18 +05304912#ifdef ECM_INTERFACE_MAP_T_ENABLE
4913/*
4914 * ecm_db_iface_map_t_info_get
4915 * get map_t specific info
4916 */
4917void ecm_db_iface_map_t_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_map_t *map_t_info)
4918{
4919 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4920 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_MAP_T, "%p: Bad type, expected map_t, actual: %d\n", ii, ii->type);
4921 spin_lock_bh(&ecm_db_lock);
4922 memcpy(map_t_info, &ii->type_info.map_t, sizeof(struct ecm_db_interface_info_map_t));
4923 spin_unlock_bh(&ecm_db_lock);
4924}
4925EXPORT_SYMBOL(ecm_db_iface_map_t_info_get);
4926
4927/*
4928 * ecm_db_iface_find_and_ref_map_t()
4929 * Lookup and return a iface reference if any
4930 */
4931struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_map_t(int if_index)
4932{
4933 ecm_db_iface_hash_t hash_index;
4934 struct ecm_db_iface_instance *ii;
4935
4936 DEBUG_TRACE("Lookup map_t iface with if_index = %d\n", if_index);
4937
4938 /*
4939 * Compute the hash chain index and prepare to walk the chain
4940 */
4941 hash_index = ecm_db_iface_generate_hash_index_map_t(if_index);
4942
4943 /*
4944 * Iterate the chain looking for a host with matching details
4945 */
4946 spin_lock_bh(&ecm_db_lock);
4947 ii = ecm_db_iface_table[hash_index];
4948
4949 while (ii) {
4950 if ((ii->type != ECM_DB_IFACE_TYPE_MAP_T)
4951 || (ii->type_info.map_t.if_index != if_index)) {
4952 ii = ii->hash_next;
4953 continue;
4954 }
4955
4956 _ecm_db_iface_ref(ii);
4957 spin_unlock_bh(&ecm_db_lock);
4958 DEBUG_TRACE("%p: iface found\n", ii);
4959 return ii;
4960 }
4961 spin_unlock_bh(&ecm_db_lock);
4962
4963 DEBUG_TRACE("Iface not found\n");
4964 return NULL;
4965}
4966EXPORT_SYMBOL(ecm_db_iface_find_and_ref_map_t);
4967
4968#endif
4969
Ben Menchaca84f36632014-02-28 20:57:38 +00004970/*
4971 * ecm_db_iface_find_and_ref_unknown()
4972 * Lookup and return a iface reference if any
4973 */
4974struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_unknown(uint32_t os_specific_ident)
4975{
4976 ecm_db_iface_hash_t hash_index;
4977 struct ecm_db_iface_instance *ii;
4978
4979 DEBUG_TRACE("Lookup unknown iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
4980
4981 /*
4982 * Compute the hash chain index and prepare to walk the chain
4983 */
4984 hash_index = ecm_db_iface_generate_hash_index_unknown(os_specific_ident);
4985
4986 /*
4987 * Iterate the chain looking for a host with matching details
4988 */
4989 spin_lock_bh(&ecm_db_lock);
4990 ii = ecm_db_iface_table[hash_index];
4991 while (ii) {
4992 if ((ii->type != ECM_DB_IFACE_TYPE_UNKNOWN) || (ii->type_info.unknown.os_specific_ident != os_specific_ident)) {
4993 ii = ii->hash_next;
4994 continue;
4995 }
4996
4997 _ecm_db_iface_ref(ii);
4998 spin_unlock_bh(&ecm_db_lock);
4999 DEBUG_TRACE("iface found %p\n", ii);
5000 return ii;
5001 }
5002 spin_unlock_bh(&ecm_db_lock);
5003 DEBUG_TRACE("Iface not found\n");
5004 return NULL;
5005}
5006EXPORT_SYMBOL(ecm_db_iface_find_and_ref_unknown);
5007
5008/*
5009 * ecm_db_iface_find_and_ref_loopback()
5010 * Lookup and return a iface reference if any
5011 */
5012struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_loopback(uint32_t os_specific_ident)
5013{
5014 ecm_db_iface_hash_t hash_index;
5015 struct ecm_db_iface_instance *ii;
5016
5017 DEBUG_TRACE("Lookup loopback iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
5018
5019 /*
5020 * Compute the hash chain index and prepare to walk the chain
5021 */
5022 hash_index = ecm_db_iface_generate_hash_index_loopback(os_specific_ident);
5023
5024 /*
5025 * Iterate the chain looking for a host with matching details
5026 */
5027 spin_lock_bh(&ecm_db_lock);
5028 ii = ecm_db_iface_table[hash_index];
5029 while (ii) {
5030 if ((ii->type != ECM_DB_IFACE_TYPE_LOOPBACK) || (ii->type_info.loopback.os_specific_ident != os_specific_ident)) {
5031 ii = ii->hash_next;
5032 continue;
5033 }
5034
5035 _ecm_db_iface_ref(ii);
5036 spin_unlock_bh(&ecm_db_lock);
5037 DEBUG_TRACE("iface found %p\n", ii);
5038 return ii;
5039 }
5040 spin_unlock_bh(&ecm_db_lock);
5041 DEBUG_TRACE("Iface not found\n");
5042 return NULL;
5043}
5044EXPORT_SYMBOL(ecm_db_iface_find_and_ref_loopback);
5045
Murat Sezgin69a27532015-03-12 14:09:40 -07005046#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00005047/*
5048 * ecm_db_iface_find_and_ref_ipsec_tunnel()
5049 * Lookup and return a iface reference if any.
5050 * GGG TODO Flesh this out using tunnel endpoint keys
5051 */
5052struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_ipsec_tunnel(uint32_t os_specific_ident)
5053{
5054 ecm_db_iface_hash_t hash_index;
5055 struct ecm_db_iface_instance *ii;
5056
5057 DEBUG_TRACE("Lookup ipsec_tunnel iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
5058
5059 /*
5060 * Compute the hash chain index and prepare to walk the chain
5061 */
5062 hash_index = ecm_db_iface_generate_hash_index_ipsec_tunnel(os_specific_ident);
5063
5064 /*
5065 * Iterate the chain looking for a host with matching details
5066 */
5067 spin_lock_bh(&ecm_db_lock);
5068 ii = ecm_db_iface_table[hash_index];
5069 while (ii) {
5070 if ((ii->type != ECM_DB_IFACE_TYPE_IPSEC_TUNNEL) || (ii->type_info.ipsec_tunnel.os_specific_ident != os_specific_ident)) {
5071 ii = ii->hash_next;
5072 continue;
5073 }
5074
5075 _ecm_db_iface_ref(ii);
5076 spin_unlock_bh(&ecm_db_lock);
5077 DEBUG_TRACE("iface found %p\n", ii);
5078 return ii;
5079 }
5080 spin_unlock_bh(&ecm_db_lock);
5081 DEBUG_TRACE("Iface not found\n");
5082 return NULL;
5083}
5084EXPORT_SYMBOL(ecm_db_iface_find_and_ref_ipsec_tunnel);
Murat Sezgin69a27532015-03-12 14:09:40 -07005085#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00005086
Murat Sezginbde55f92015-03-11 16:44:11 -07005087#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00005088/*
5089 * ecm_db_iface_find_and_ref_sit()
5090 * Lookup and return a iface reference if any
5091 */
5092struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_sit(ip_addr_t saddr, ip_addr_t daddr)
5093{
5094 ecm_db_iface_hash_t hash_index;
5095 struct ecm_db_iface_instance *ii;
5096
5097 DEBUG_TRACE("Lookup sit (6-in-4) iface with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT "\n",
5098 ECM_IP_ADDR_TO_OCTAL(saddr), ECM_IP_ADDR_TO_OCTAL(daddr));
5099
5100 /*
5101 * Compute the hash chain index and prepare to walk the chain
5102 */
5103 hash_index = ecm_db_iface_generate_hash_index_sit(saddr, daddr);
5104
5105 /*
5106 * Iterate the chain looking for a host with matching details
5107 */
5108 spin_lock_bh(&ecm_db_lock);
5109 ii = ecm_db_iface_table[hash_index];
5110 while (ii) {
5111 if ((ii->type != ECM_DB_IFACE_TYPE_SIT)
5112 || !ECM_IP_ADDR_MATCH(ii->type_info.sit.saddr, saddr)
5113 || !ECM_IP_ADDR_MATCH(ii->type_info.sit.daddr, daddr)) {
5114 ii = ii->hash_next;
5115 continue;
5116 }
5117
5118 _ecm_db_iface_ref(ii);
5119 spin_unlock_bh(&ecm_db_lock);
5120 DEBUG_TRACE("iface found %p\n", ii);
5121 return ii;
5122 }
5123 spin_unlock_bh(&ecm_db_lock);
5124 DEBUG_TRACE("Iface not found\n");
5125 return NULL;
5126}
5127EXPORT_SYMBOL(ecm_db_iface_find_and_ref_sit);
Murat Sezginbde55f92015-03-11 16:44:11 -07005128#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00005129
Murat Sezginc1402562015-03-12 12:32:20 -07005130#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +00005131#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00005132/*
5133 * ecm_db_iface_find_and_ref_tunipip6()
5134 * Lookup and return a iface reference if any
5135 */
5136struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_tunipip6(ip_addr_t saddr, ip_addr_t daddr)
5137{
5138 ecm_db_iface_hash_t hash_index;
5139 struct ecm_db_iface_instance *ii;
5140
5141 DEBUG_TRACE("Lookup TUNIPIP6 iface with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT "\n",
5142 ECM_IP_ADDR_TO_OCTAL(saddr), ECM_IP_ADDR_TO_OCTAL(daddr));
5143
5144 /*
5145 * Compute the hash chain index and prepare to walk the chain
5146 */
5147 hash_index = ecm_db_iface_generate_hash_index_tunipip6(saddr, daddr);
5148
5149 /*
5150 * Iterate the chain looking for a host with matching details
5151 */
5152 spin_lock_bh(&ecm_db_lock);
5153 ii = ecm_db_iface_table[hash_index];
5154 while (ii) {
5155 if ((ii->type != ECM_DB_IFACE_TYPE_TUNIPIP6)
5156 || !ECM_IP_ADDR_MATCH(ii->type_info.tunipip6.saddr, saddr)
5157 || !ECM_IP_ADDR_MATCH(ii->type_info.tunipip6.daddr, daddr)) {
5158 ii = ii->hash_next;
5159 continue;
5160 }
5161
5162 _ecm_db_iface_ref(ii);
5163 spin_unlock_bh(&ecm_db_lock);
5164 DEBUG_TRACE("iface found %p\n", ii);
5165 return ii;
5166 }
5167 spin_unlock_bh(&ecm_db_lock);
5168 DEBUG_TRACE("Iface not found\n");
5169 return NULL;
5170}
5171EXPORT_SYMBOL(ecm_db_iface_find_and_ref_tunipip6);
Murat Sezginc1402562015-03-12 12:32:20 -07005172#endif
Gareth Williams8ac34292015-03-17 14:06:58 +00005173#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00005174
5175/*
5176 * ecm_db_mapping_find_and_ref()
5177 * Lookup and return a mapping reference if any.
5178 *
5179 * NOTE: For non-port based protocols the ports are expected to be -(protocol)
5180 */
5181struct ecm_db_mapping_instance *ecm_db_mapping_find_and_ref(ip_addr_t address, int port)
5182{
5183 ecm_db_mapping_hash_t hash_index;
5184 struct ecm_db_mapping_instance *mi;
5185
5186 DEBUG_TRACE("Lookup mapping with addr " ECM_IP_ADDR_OCTAL_FMT " and port %d\n", ECM_IP_ADDR_TO_OCTAL(address), port);
5187
5188 /*
5189 * Compute the hash chain index and prepare to walk the chain
5190 */
5191 hash_index = ecm_db_mapping_generate_hash_index(address, port);
5192
5193 /*
5194 * Iterate the chain looking for a mapping with matching details
5195 */
5196 spin_lock_bh(&ecm_db_lock);
5197 mi = ecm_db_mapping_table[hash_index];
5198 while (mi) {
5199 if (mi->port != port) {
5200 mi = mi->hash_next;
5201 continue;
5202 }
5203
5204 if (!ECM_IP_ADDR_MATCH(mi->host->address, address)) {
5205 mi = mi->hash_next;
5206 continue;
5207 }
5208
5209 _ecm_db_mapping_ref(mi);
5210 spin_unlock_bh(&ecm_db_lock);
5211 DEBUG_TRACE("Mapping found %p\n", mi);
5212 return mi;
5213 }
5214 spin_unlock_bh(&ecm_db_lock);
5215 DEBUG_TRACE("Mapping not found\n");
5216 return NULL;
5217}
5218EXPORT_SYMBOL(ecm_db_mapping_find_and_ref);
5219
5220/*
Gareth Williams54d15d92015-04-24 19:28:27 +01005221 * ecm_db_connection_find_and_ref_chain()
5222 * Given a hash chain index locate the connection
Ben Menchaca84f36632014-02-28 20:57:38 +00005223 */
Gareth Williams54d15d92015-04-24 19:28:27 +01005224static struct ecm_db_connection_instance *ecm_db_connection_find_and_ref_chain(ecm_db_connection_hash_t hash_index,
5225 ip_addr_t host1_addr, ip_addr_t host2_addr,
5226 int protocol, int host1_port, int host2_port)
Ben Menchaca84f36632014-02-28 20:57:38 +00005227{
Ben Menchaca84f36632014-02-28 20:57:38 +00005228 struct ecm_db_connection_instance *ci;
5229
Ben Menchaca84f36632014-02-28 20:57:38 +00005230 /*
5231 * Iterate the chain looking for a connection with matching details
5232 */
5233 spin_lock_bh(&ecm_db_lock);
5234 ci = ecm_db_connection_table[hash_index];
Ben Menchaca84f36632014-02-28 20:57:38 +00005235 while (ci) {
Ben Menchaca84f36632014-02-28 20:57:38 +00005236 /*
5237 * The use of unlikely() is liberally used because under fast-hit scenarios the connection would always be at the start of a chain
5238 */
5239 if (unlikely(ci->protocol != protocol)) {
5240 goto try_next;
5241 }
5242
5243 if (unlikely(!ECM_IP_ADDR_MATCH(host1_addr, ci->mapping_from->host->address))) {
5244 goto try_reverse;
5245 }
5246
5247 if (unlikely(host1_port != ci->mapping_from->port)) {
5248 goto try_reverse;
5249 }
5250
5251 if (unlikely(!ECM_IP_ADDR_MATCH(host2_addr, ci->mapping_to->host->address))) {
5252 goto try_reverse;
5253 }
5254
5255 if (unlikely(host2_port != ci->mapping_to->port)) {
5256 goto try_reverse;
5257 }
5258
5259 goto connection_found;
5260
5261try_reverse:
5262 if (unlikely(!ECM_IP_ADDR_MATCH(host1_addr, ci->mapping_to->host->address))) {
5263 goto try_next;
5264 }
5265
5266 if (unlikely(host1_port != ci->mapping_to->port)) {
5267 goto try_next;
5268 }
5269
5270 if (unlikely(!ECM_IP_ADDR_MATCH(host2_addr, ci->mapping_from->host->address))) {
5271 goto try_next;
5272 }
5273
5274 if (unlikely(host2_port != ci->mapping_from->port)) {
5275 goto try_next;
5276 }
5277
5278 goto connection_found;
5279
5280try_next:
Gareth Williamse5cb08b2015-10-28 17:02:53 +00005281 ci = ci->hash_next;
Ben Menchaca84f36632014-02-28 20:57:38 +00005282 }
Gareth Williamse5cb08b2015-10-28 17:02:53 +00005283 spin_unlock_bh(&ecm_db_lock);
Gareth Williams54d15d92015-04-24 19:28:27 +01005284 DEBUG_TRACE("Connection not found in hash chain\n");
Ben Menchaca84f36632014-02-28 20:57:38 +00005285 return NULL;
5286
5287connection_found:
Gareth Williamse5cb08b2015-10-28 17:02:53 +00005288 _ecm_db_connection_ref(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00005289 spin_unlock_bh(&ecm_db_lock);
Gareth Williamse5cb08b2015-10-28 17:02:53 +00005290 DEBUG_TRACE("Connection found %p\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00005291 return ci;
5292}
Gareth Williams54d15d92015-04-24 19:28:27 +01005293
5294/*
5295 * ecm_db_connection_find_and_ref()
5296 * Locate a connection instance based on addressing, protocol and optional port information.
5297 *
5298 * NOTE: For non-port based protocols then ports are expected to be -(protocol).
5299 */
5300struct 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)
5301{
5302 ecm_db_connection_hash_t hash_index;
5303
5304 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);
5305
5306 /*
5307 * Compute the hash chain index and prepare to walk the chain
5308 */
5309 hash_index = ecm_db_connection_generate_hash_index(host1_addr, host1_port, host2_addr, host2_port, protocol);
5310 return ecm_db_connection_find_and_ref_chain(hash_index, host1_addr, host2_addr, protocol, host1_port, host2_port);
5311}
Ben Menchaca84f36632014-02-28 20:57:38 +00005312EXPORT_SYMBOL(ecm_db_connection_find_and_ref);
5313
5314/*
5315 * ecm_db_connection_serial_find_and_ref()
5316 * Locate a connection instance based on serial if it still exists
5317 */
5318struct ecm_db_connection_instance *ecm_db_connection_serial_find_and_ref(uint32_t serial)
5319{
5320 ecm_db_connection_serial_hash_t serial_hash_index;
5321 struct ecm_db_connection_instance *ci;
5322
5323 DEBUG_TRACE("Lookup connection serial: %u\n", serial);
5324
5325 /*
5326 * Compute the hash chain index and prepare to walk the chain
5327 */
5328 serial_hash_index = ecm_db_connection_generate_serial_hash_index(serial);
5329
5330 /*
5331 * Iterate the chain looking for a connection with matching serial
5332 */
5333 spin_lock_bh(&ecm_db_lock);
5334 ci = ecm_db_connection_serial_table[serial_hash_index];
Ben Menchaca84f36632014-02-28 20:57:38 +00005335 while (ci) {
Ben Menchaca84f36632014-02-28 20:57:38 +00005336 /*
5337 * The use of likely() is used because under fast-hit scenarios the connection would always be at the start of a chain
5338 */
5339 if (likely(ci->serial == serial)) {
Gareth Williamse5cb08b2015-10-28 17:02:53 +00005340 _ecm_db_connection_ref(ci);
5341 spin_unlock_bh(&ecm_db_lock);
5342 DEBUG_TRACE("Connection found %p\n", ci);
5343 return ci;
Ben Menchaca84f36632014-02-28 20:57:38 +00005344 }
5345
Gareth Williamse5cb08b2015-10-28 17:02:53 +00005346 ci = ci->serial_hash_next;
Ben Menchaca84f36632014-02-28 20:57:38 +00005347 }
Gareth Williamse5cb08b2015-10-28 17:02:53 +00005348 spin_unlock_bh(&ecm_db_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00005349 DEBUG_TRACE("Connection not found\n");
5350 return NULL;
Ben Menchaca84f36632014-02-28 20:57:38 +00005351}
5352EXPORT_SYMBOL(ecm_db_connection_serial_find_and_ref);
5353
5354/*
Gareth Williamsb5903892015-03-20 15:13:07 +00005355 * ecm_db_connection_node_to_get_and_ref()
5356 * Return node reference
5357 */
5358struct ecm_db_node_instance *ecm_db_connection_node_to_get_and_ref(struct ecm_db_connection_instance *ci)
5359{
5360 struct ecm_db_node_instance *ni;
5361
5362 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5363
5364 spin_lock_bh(&ecm_db_lock);
5365 ni = ci->to_node;
5366 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
5367 _ecm_db_node_ref(ni);
5368 spin_unlock_bh(&ecm_db_lock);
5369 return ni;
5370}
5371EXPORT_SYMBOL(ecm_db_connection_node_to_get_and_ref);
5372
5373/*
5374 * ecm_db_connection_node_from_get_and_ref()
5375 * Return node reference
5376 */
5377struct ecm_db_node_instance *ecm_db_connection_node_from_get_and_ref(struct ecm_db_connection_instance *ci)
5378{
5379 struct ecm_db_node_instance *ni;
5380
5381 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5382
5383 spin_lock_bh(&ecm_db_lock);
5384 ni = ci->from_node;
5385 _ecm_db_node_ref(ni);
5386 spin_unlock_bh(&ecm_db_lock);
5387 return ni;
5388}
5389EXPORT_SYMBOL(ecm_db_connection_node_from_get_and_ref);
5390
5391#ifdef ECM_DB_XREF_ENABLE
5392/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005393 * ecm_db_mapping_connections_from_get_and_ref_first()
5394 * Return a reference to the first connection made from this mapping
5395 */
5396struct ecm_db_connection_instance *ecm_db_mapping_connections_from_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5397{
5398 struct ecm_db_connection_instance *ci;
5399
5400 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5401
5402 spin_lock_bh(&ecm_db_lock);
5403 ci = mi->from_connections;
5404 if (ci) {
5405 _ecm_db_connection_ref(ci);
5406 }
5407 spin_unlock_bh(&ecm_db_lock);
5408
5409 return ci;
5410}
5411EXPORT_SYMBOL(ecm_db_mapping_connections_from_get_and_ref_first);
5412
5413/*
5414 * ecm_db_mapping_connections_to_get_and_ref_first()
5415 * Return a reference to the first connection made to this mapping
5416 */
5417struct ecm_db_connection_instance *ecm_db_mapping_connections_to_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5418{
5419 struct ecm_db_connection_instance *ci;
5420
5421 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5422
5423 spin_lock_bh(&ecm_db_lock);
5424 ci = mi->to_connections;
5425 if (ci) {
5426 _ecm_db_connection_ref(ci);
5427 }
5428 spin_unlock_bh(&ecm_db_lock);
5429
5430 return ci;
5431}
5432EXPORT_SYMBOL(ecm_db_mapping_connections_to_get_and_ref_first);
5433
5434/*
5435 * ecm_db_mapping_connections_nat_from_get_and_ref_first()
5436 * Return a reference to the first NAT connection made from this mapping
5437 */
5438struct ecm_db_connection_instance *ecm_db_mapping_connections_nat_from_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5439{
5440 struct ecm_db_connection_instance *ci;
5441
5442 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5443
5444 spin_lock_bh(&ecm_db_lock);
5445 ci = mi->from_nat_connections;
5446 if (ci) {
5447 _ecm_db_connection_ref(ci);
5448 }
5449 spin_unlock_bh(&ecm_db_lock);
5450
5451 return ci;
5452}
5453EXPORT_SYMBOL(ecm_db_mapping_connections_nat_from_get_and_ref_first);
5454
5455/*
5456 * ecm_db_mapping_connections_nat_to_get_and_ref_first()
5457 * Return a reference to the first NAT connection made to this mapping
5458 */
5459struct ecm_db_connection_instance *ecm_db_mapping_connections_nat_to_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5460{
5461 struct ecm_db_connection_instance *ci;
5462
5463 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5464
5465 spin_lock_bh(&ecm_db_lock);
5466 ci = mi->to_nat_connections;
5467 if (ci) {
5468 _ecm_db_connection_ref(ci);
5469 }
5470 spin_unlock_bh(&ecm_db_lock);
5471
5472 return ci;
5473}
5474EXPORT_SYMBOL(ecm_db_mapping_connections_nat_to_get_and_ref_first);
5475
5476/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005477 * ecm_db_connection_mapping_from_get_and_ref_next()
5478 * Return reference to next connection in from mapping chain
5479 */
5480struct ecm_db_connection_instance *ecm_db_connection_mapping_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5481{
5482 struct ecm_db_connection_instance *nci;
5483
5484 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5485
5486 spin_lock_bh(&ecm_db_lock);
5487 nci = ci->from_next;
5488 if (nci) {
5489 _ecm_db_connection_ref(nci);
5490 }
5491 spin_unlock_bh(&ecm_db_lock);
5492
5493 return nci;
5494}
5495EXPORT_SYMBOL(ecm_db_connection_mapping_from_get_and_ref_next);
5496
5497/*
5498 * ecm_db_connection_mapping_to_get_and_ref_next()
5499 * Return reference to next connection in to mapping chain
5500 */
5501struct ecm_db_connection_instance *ecm_db_connection_mapping_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5502{
5503 struct ecm_db_connection_instance *nci;
5504
5505 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5506
5507 spin_lock_bh(&ecm_db_lock);
5508 nci = ci->to_next;
5509 if (nci) {
5510 _ecm_db_connection_ref(nci);
5511 }
5512 spin_unlock_bh(&ecm_db_lock);
5513
5514 return nci;
5515}
5516EXPORT_SYMBOL(ecm_db_connection_mapping_to_get_and_ref_next);
5517
5518/*
5519 * ecm_db_connection_mapping_nat_from_get_and_ref_next()
5520 * Return reference to next connection in from NAT mapping chain
5521 */
5522struct ecm_db_connection_instance *ecm_db_connection_mapping_nat_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5523{
5524 struct ecm_db_connection_instance *nci;
5525
5526 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5527
5528 spin_lock_bh(&ecm_db_lock);
5529 nci = ci->from_nat_next;
5530 if (nci) {
5531 _ecm_db_connection_ref(nci);
5532 }
5533 spin_unlock_bh(&ecm_db_lock);
5534
5535 return nci;
5536}
5537EXPORT_SYMBOL(ecm_db_connection_mapping_nat_from_get_and_ref_next);
5538
5539/*
5540 * ecm_db_connection_mapping_nat_to_get_and_ref_next()
5541 * Return reference to next connection in to NAT mapping chain
5542 */
5543struct ecm_db_connection_instance *ecm_db_connection_mapping_nat_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5544{
5545 struct ecm_db_connection_instance *nci;
5546
5547 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5548
5549 spin_lock_bh(&ecm_db_lock);
5550 nci = ci->to_nat_next;
5551 if (nci) {
5552 _ecm_db_connection_ref(nci);
5553 }
5554 spin_unlock_bh(&ecm_db_lock);
5555
5556 return nci;
5557}
5558EXPORT_SYMBOL(ecm_db_connection_mapping_nat_to_get_and_ref_next);
5559
5560/*
5561 * ecm_db_iface_connections_from_get_and_ref_first()
5562 * Return a reference to the first connection made from this iface
5563 */
5564struct ecm_db_connection_instance *ecm_db_iface_connections_from_get_and_ref_first(struct ecm_db_iface_instance *ii)
5565{
5566 struct ecm_db_connection_instance *ci;
5567
5568 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5569
5570 spin_lock_bh(&ecm_db_lock);
5571 ci = ii->from_connections;
5572 if (ci) {
5573 _ecm_db_connection_ref(ci);
5574 }
5575 spin_unlock_bh(&ecm_db_lock);
5576
5577 return ci;
5578}
5579EXPORT_SYMBOL(ecm_db_iface_connections_from_get_and_ref_first);
5580
5581/*
5582 * ecm_db_iface_connections_to_get_and_ref_first()
5583 * Return a reference to the first connection made to this iface
5584 */
5585struct ecm_db_connection_instance *ecm_db_iface_connections_to_get_and_ref_first(struct ecm_db_iface_instance *ii)
5586{
5587 struct ecm_db_connection_instance *ci;
5588
5589 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5590
5591 spin_lock_bh(&ecm_db_lock);
5592 ci = ii->to_connections;
5593 if (ci) {
5594 _ecm_db_connection_ref(ci);
5595 }
5596 spin_unlock_bh(&ecm_db_lock);
5597
5598 return ci;
5599}
5600EXPORT_SYMBOL(ecm_db_iface_connections_to_get_and_ref_first);
5601
5602/*
5603 * ecm_db_iface_connections_nat_from_get_and_ref_first()
5604 * Return a reference to the first NAT connection made from this iface
5605 */
5606struct ecm_db_connection_instance *ecm_db_iface_connections_nat_from_get_and_ref_first(struct ecm_db_iface_instance *ii)
5607{
5608 struct ecm_db_connection_instance *ci;
5609
5610 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5611
5612 spin_lock_bh(&ecm_db_lock);
5613 ci = ii->from_nat_connections;
5614 if (ci) {
5615 _ecm_db_connection_ref(ci);
5616 }
5617 spin_unlock_bh(&ecm_db_lock);
5618
5619 return ci;
5620}
5621EXPORT_SYMBOL(ecm_db_iface_connections_nat_from_get_and_ref_first);
5622
5623/*
5624 * ecm_db_iface_connections_nat_to_get_and_ref_first()
5625 * Return a reference to the first NAT connection made to this iface
5626 */
5627struct ecm_db_connection_instance *ecm_db_iface_connections_nat_to_get_and_ref_first(struct ecm_db_iface_instance *ii)
5628{
5629 struct ecm_db_connection_instance *ci;
5630
5631 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5632
5633 spin_lock_bh(&ecm_db_lock);
5634 ci = ii->to_nat_connections;
5635 if (ci) {
5636 _ecm_db_connection_ref(ci);
5637 }
5638 spin_unlock_bh(&ecm_db_lock);
5639
5640 return ci;
5641}
5642EXPORT_SYMBOL(ecm_db_iface_connections_nat_to_get_and_ref_first);
5643
5644/*
5645 * ecm_db_connection_iface_from_get_and_ref_next()
5646 * Return reference to next connection in from iface chain
5647 */
5648struct ecm_db_connection_instance *ecm_db_connection_iface_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5649{
5650 struct ecm_db_connection_instance *nci;
5651
5652 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5653
5654 spin_lock_bh(&ecm_db_lock);
5655 nci = ci->iface_from_next;
5656 if (nci) {
5657 _ecm_db_connection_ref(nci);
5658 }
5659 spin_unlock_bh(&ecm_db_lock);
5660
5661 return nci;
5662}
5663EXPORT_SYMBOL(ecm_db_connection_iface_from_get_and_ref_next);
5664
5665/*
5666 * ecm_db_connection_iface_to_get_and_ref_next()
5667 * Return reference to next connection in to iface chain
5668 */
5669struct ecm_db_connection_instance *ecm_db_connection_iface_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5670{
5671 struct ecm_db_connection_instance *nci;
5672
5673 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5674
5675 spin_lock_bh(&ecm_db_lock);
5676 nci = ci->iface_to_next;
5677 if (nci) {
5678 _ecm_db_connection_ref(nci);
5679 }
5680 spin_unlock_bh(&ecm_db_lock);
5681
5682 return nci;
5683}
5684EXPORT_SYMBOL(ecm_db_connection_iface_to_get_and_ref_next);
5685
5686/*
5687 * ecm_db_connection_iface_nat_from_get_and_ref_next()
5688 * Return reference to next connection in from NAT iface chain
5689 */
5690struct ecm_db_connection_instance *ecm_db_connection_iface_nat_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5691{
5692 struct ecm_db_connection_instance *nci;
5693
5694 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5695
5696 spin_lock_bh(&ecm_db_lock);
5697 nci = ci->iface_from_nat_next;
5698 if (nci) {
5699 _ecm_db_connection_ref(nci);
5700 }
5701 spin_unlock_bh(&ecm_db_lock);
5702
5703 return nci;
5704}
5705EXPORT_SYMBOL(ecm_db_connection_iface_nat_from_get_and_ref_next);
5706
5707/*
5708 * ecm_db_connection_iface_nat_to_get_and_ref_next()
5709 * Return reference to next connection in to NAT iface chain
5710 */
5711struct ecm_db_connection_instance *ecm_db_connection_iface_nat_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5712{
5713 struct ecm_db_connection_instance *nci;
5714
5715 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5716
5717 spin_lock_bh(&ecm_db_lock);
5718 nci = ci->iface_to_nat_next;
5719 if (nci) {
5720 _ecm_db_connection_ref(nci);
5721 }
5722 spin_unlock_bh(&ecm_db_lock);
5723
5724 return nci;
5725}
5726EXPORT_SYMBOL(ecm_db_connection_iface_nat_to_get_and_ref_next);
5727
5728/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005729 * ecm_db_iface_nodes_get_and_ref_first()
5730 * Return a reference to the first node made from this iface
5731 */
5732struct ecm_db_node_instance *ecm_db_iface_nodes_get_and_ref_first(struct ecm_db_iface_instance *ii)
5733{
5734 struct ecm_db_node_instance *ni;
5735
5736 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5737
5738 spin_lock_bh(&ecm_db_lock);
5739 ni = ii->nodes;
5740 if (ni) {
5741 _ecm_db_node_ref(ni);
5742 }
5743 spin_unlock_bh(&ecm_db_lock);
5744
5745 return ni;
5746}
5747EXPORT_SYMBOL(ecm_db_iface_nodes_get_and_ref_first);
5748
5749/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005750 * ecm_db_iface_node_count_get()
5751 * Return the number of nodes to this iface
5752 */
5753int ecm_db_iface_node_count_get(struct ecm_db_iface_instance *ii)
5754{
5755 int count;
5756
5757 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305758
Ben Menchaca84f36632014-02-28 20:57:38 +00005759 spin_lock_bh(&ecm_db_lock);
5760 count = ii->node_count;
5761 spin_unlock_bh(&ecm_db_lock);
5762 return count;
5763}
5764EXPORT_SYMBOL(ecm_db_iface_node_count_get);
5765
5766/*
5767 * ecm_db_host_mapping_count_get()
5768 * Return the number of mappings to this host
5769 */
5770int ecm_db_host_mapping_count_get(struct ecm_db_host_instance *hi)
5771{
5772 int count;
5773
5774 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305775
Ben Menchaca84f36632014-02-28 20:57:38 +00005776 spin_lock_bh(&ecm_db_lock);
5777 count = hi->mapping_count;
5778 spin_unlock_bh(&ecm_db_lock);
5779 return count;
5780}
5781EXPORT_SYMBOL(ecm_db_host_mapping_count_get);
Gareth Williamsb5903892015-03-20 15:13:07 +00005782#endif
5783
5784/*
5785 * ecm_db_mapping_host_get_and_ref()
5786 */
5787struct ecm_db_host_instance *ecm_db_mapping_host_get_and_ref(struct ecm_db_mapping_instance *mi)
5788{
5789 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
5790
5791 spin_lock_bh(&ecm_db_lock);
5792 _ecm_db_host_ref(mi->host);
5793 spin_unlock_bh(&ecm_db_lock);
5794 return mi->host;
5795}
5796EXPORT_SYMBOL(ecm_db_mapping_host_get_and_ref);
5797
5798/*
5799 * ecm_db_node_iface_get_and_ref()
5800 */
5801struct ecm_db_iface_instance *ecm_db_node_iface_get_and_ref(struct ecm_db_node_instance *ni)
5802{
5803 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
5804
5805 spin_lock_bh(&ecm_db_lock);
5806 _ecm_db_iface_ref(ni->iface);
5807 spin_unlock_bh(&ecm_db_lock);
5808 return ni->iface;
5809}
5810EXPORT_SYMBOL(ecm_db_node_iface_get_and_ref);
Ben Menchaca84f36632014-02-28 20:57:38 +00005811
5812/*
5813 * ecm_db_mapping_connections_total_count_get()
5814 * Return the total number of connections (NAT and non-NAT) this mapping has
5815 */
5816int ecm_db_mapping_connections_total_count_get(struct ecm_db_mapping_instance *mi)
5817{
5818 int count;
5819
5820 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305821
Ben Menchaca84f36632014-02-28 20:57:38 +00005822 spin_lock_bh(&ecm_db_lock);
5823 count = mi->from + mi->to + mi->nat_from + mi->nat_to;
5824 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);
5825 spin_unlock_bh(&ecm_db_lock);
5826 return count;
5827}
5828EXPORT_SYMBOL(ecm_db_mapping_connections_total_count_get);
5829
5830/*
5831 * ecm_db_connection_mapping_from_get_and_ref()
5832 * Return a reference to the from mapping of the connection
5833 */
5834struct ecm_db_mapping_instance *ecm_db_connection_mapping_from_get_and_ref(struct ecm_db_connection_instance *ci)
5835{
5836 struct ecm_db_mapping_instance *mi;
5837
5838 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305839
Ben Menchaca84f36632014-02-28 20:57:38 +00005840 spin_lock_bh(&ecm_db_lock);
5841 mi = ci->mapping_from;
5842 _ecm_db_mapping_ref(mi);
5843 spin_unlock_bh(&ecm_db_lock);
5844 return mi;
5845}
5846EXPORT_SYMBOL(ecm_db_connection_mapping_from_get_and_ref);
5847
5848/*
5849 * ecm_db_connection_mapping_nat_from_get_and_ref()
5850 * Return a reference to the from NAT mapping of the connection
5851 */
5852struct ecm_db_mapping_instance *ecm_db_connection_mapping_nat_from_get_and_ref(struct ecm_db_connection_instance *ci)
5853{
5854 struct ecm_db_mapping_instance *mi;
5855
5856 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305857
Ben Menchaca84f36632014-02-28 20:57:38 +00005858 spin_lock_bh(&ecm_db_lock);
5859 mi = ci->mapping_nat_from;
5860 _ecm_db_mapping_ref(mi);
5861 spin_unlock_bh(&ecm_db_lock);
5862 return mi;
5863}
5864EXPORT_SYMBOL(ecm_db_connection_mapping_nat_from_get_and_ref);
5865
5866/*
5867 * ecm_db_connection_mapping_to_get_and_ref()
5868 * Return a reference to the from mapping of the connection
5869 */
5870struct ecm_db_mapping_instance *ecm_db_connection_mapping_to_get_and_ref(struct ecm_db_connection_instance *ci)
5871{
5872 struct ecm_db_mapping_instance *mi;
5873
5874 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305875
Ben Menchaca84f36632014-02-28 20:57:38 +00005876 spin_lock_bh(&ecm_db_lock);
5877 mi = ci->mapping_to;
5878 _ecm_db_mapping_ref(mi);
5879 spin_unlock_bh(&ecm_db_lock);
5880 return mi;
5881}
5882EXPORT_SYMBOL(ecm_db_connection_mapping_to_get_and_ref);
5883
5884/*
5885 * ecm_db_connection_mapping_to_nat_get_and_ref()
5886 * Return a reference to the from NAT mapping of the connection
5887 */
5888struct ecm_db_mapping_instance *ecm_db_connection_mapping_nat_to_get_and_ref(struct ecm_db_connection_instance *ci)
5889{
5890 struct ecm_db_mapping_instance *mi;
5891
5892 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305893
Ben Menchaca84f36632014-02-28 20:57:38 +00005894 spin_lock_bh(&ecm_db_lock);
5895 mi = ci->mapping_nat_to;
5896 _ecm_db_mapping_ref(mi);
5897 spin_unlock_bh(&ecm_db_lock);
5898 return mi;
5899}
5900EXPORT_SYMBOL(ecm_db_connection_mapping_nat_to_get_and_ref);
5901
5902/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005903 * ecm_db_timer_groups_check()
5904 * Check for expired group entries, returns the number that have expired
5905 */
5906static uint32_t ecm_db_timer_groups_check(uint32_t time_now)
5907{
5908 ecm_db_timer_group_t i;
5909 uint32_t expired = 0;
5910
5911 DEBUG_TRACE("Timer groups check start %u\n", time_now);
5912
5913 /*
5914 * Examine all timer groups for expired entries.
5915 */
5916 for (i = 0; i < ECM_DB_TIMER_GROUPS_MAX; ++i) {
5917 struct ecm_db_timer_group *timer_group;
5918
5919 /*
5920 * The group tail tracks the oldest entry so that is what we examine.
5921 */
5922 timer_group = &ecm_db_timer_groups[i];
5923 spin_lock_bh(&ecm_db_lock);
5924 while (timer_group->tail) {
5925 struct ecm_db_timer_group_entry *tge;
5926
5927 tge = timer_group->tail;
5928 if (tge->timeout > time_now) {
5929 /*
5930 * Not expired - and no further will be as they are in order
5931 */
5932 break;
5933 }
5934
5935 /*
5936 * Has expired - remove the entry from the list and invoke the callback
5937 * NOTE: We know the entry is at the tail of the group
5938 */
5939 if (tge->prev) {
5940 tge->prev->next = NULL;
5941 } else {
5942 /*
5943 * First in the group
5944 */
5945 DEBUG_ASSERT(timer_group->head == tge, "%p: bad head, expecting %p got %p\n", timer_group, tge, timer_group->head);
5946 timer_group->head = NULL;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305947 }
Ben Menchaca84f36632014-02-28 20:57:38 +00005948 timer_group->tail = tge->prev;
5949 tge->group = ECM_DB_TIMER_GROUPS_MAX;
5950 spin_unlock_bh(&ecm_db_lock);
5951 expired++;
5952 DEBUG_TRACE("%p: Expired\n", tge);
5953 tge->fn(tge->arg);
5954 spin_lock_bh(&ecm_db_lock);
5955 }
5956 spin_unlock_bh(&ecm_db_lock);
5957 }
5958
5959 spin_lock_bh(&ecm_db_lock);
5960 time_now = ecm_db_time;
5961 spin_unlock_bh(&ecm_db_lock);
5962 DEBUG_TRACE("Timer groups check end %u, expired count %u\n", time_now, expired);
5963 return expired;
5964}
5965
5966/*
5967 * ecm_db_connection_classifier_assign()
5968 * Assign a classifier to the connection assigned classifier list.
5969 *
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005970 * This adds the classifier in the ci->assignments list in ascending priority order according to the classifier type.
5971 * 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 +00005972 * 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.
5973 * This allows fast lookup based on type too.
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005974 * 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 +00005975 */
5976void ecm_db_connection_classifier_assign(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *new_ca)
5977{
5978 struct ecm_classifier_instance *ca;
5979 struct ecm_classifier_instance *ca_prev;
5980 ecm_classifier_type_t new_ca_type;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005981#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005982 struct ecm_db_connection_classifier_type_assignment *ta;
5983 struct ecm_db_connection_classifier_type_assignment_list *tal;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005984#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005985
Ben Menchaca84f36632014-02-28 20:57:38 +00005986 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5987
5988 /*
5989 * Get the type (which is also used as the priority)
5990 */
5991 new_ca_type = new_ca->type_get(new_ca);
5992
5993 /*
5994 * Connection holds ref to the classifier
5995 */
5996 new_ca->ref(new_ca);
5997
5998 /*
5999 * Find place to insert the classifier
6000 */
6001 spin_lock_bh(&ecm_db_lock);
6002 ca = ci->assignments;
6003 ca_prev = NULL;
6004 while (ca) {
6005 ecm_classifier_type_t ca_type;
6006 ca_type = ca->type_get(ca);
6007
6008 /*
6009 * If new ca is less important that the current assigned classifier insert here
6010 */
6011 if (new_ca_type < ca_type) {
6012 break;
6013 }
6014 ca_prev = ca;
6015 ca = ca->ca_next;
6016 }
6017
6018 /*
6019 * Insert new_ca before ca and after ca_prev.
6020 */
6021 new_ca->ca_prev = ca_prev;
6022 if (ca_prev) {
6023 ca_prev->ca_next = new_ca;
6024 } else {
6025 DEBUG_ASSERT(ci->assignments == ca, "%p: Bad assigmnment list, expecting: %p, got: %p\n", ci, ca, ci->assignments);
6026 ci->assignments = new_ca;
6027 }
6028
6029 new_ca->ca_next = ca;
6030 if (ca) {
6031 ca->ca_prev = new_ca;
6032 }
6033
6034 /*
6035 * Insert based on type too
6036 */
6037 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",
6038 ci, new_ca_type, new_ca, ci->assignments_by_type[new_ca_type]);
6039 ci->assignments_by_type[new_ca_type] = new_ca;
6040
Gareth Williamsb39e7c22015-03-25 10:15:33 +00006041#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006042 /*
Murat Sezgince65bc12016-01-07 15:00:17 -08006043 * Default classifier will not be added to the classifier type assignment list.
6044 * Only assigned classifiers can be added.
6045 */
6046 if (new_ca_type == ECM_CLASSIFIER_TYPE_DEFAULT) {
6047 spin_unlock_bh(&ecm_db_lock);
6048 return;
6049 }
6050
6051 /*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006052 * Add the connection into the type assignment list too.
6053 */
6054 ta = &ci->type_assignment[new_ca_type];
6055 if (ta->pending_unassign) {
6056 /*
6057 * The connection is pending unassignment / removal from list, but since it has been
6058 * re-assigned to the same type of classifier we can just clear the flag and avoid the removal.
6059 * NOTE: pending_unassign is only ever true if the iteration count is non-zero i.e. iteration is in progress.
6060 */
6061 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
6062 DEBUG_ASSERT(ta->iteration_count != 0, "%p: Bad pending_unassign: type: %d, Iteration count zero\n", ci, new_ca_type);
6063 ta->pending_unassign = false;
6064 spin_unlock_bh(&ecm_db_lock);
6065 return;
6066 }
6067
6068 /*
6069 * iteration_count should be zero as there should not be a duplicate assignment of the same type.
6070 * This is because if iteration_count was non-zero then pending_unassign should have been true.
6071 */
6072 DEBUG_ASSERT(ta->iteration_count == 0, "%p: Type: %d, Iteration count not zero: %d\n", ci, new_ca_type, ta->iteration_count);
6073
6074 /*
6075 * Insert the connection into the classifier type assignment list, at the head
6076 */
6077 tal = &ecm_db_connection_classifier_type_assignments[new_ca_type];
6078 ta->next = tal->type_assignments_list;
6079 ta->prev = NULL;
6080
6081 /*
6082 * If there is an existing head, it is no longer the head
6083 */
6084 if (tal->type_assignments_list) {
6085 struct ecm_db_connection_classifier_type_assignment *talh;
6086 talh = &tal->type_assignments_list->type_assignment[new_ca_type];
6087 talh->prev = ci;
6088 }
6089
6090 /*
6091 * Set new head
6092 */
6093 tal->type_assignments_list = ci;
6094
6095 /*
6096 * Set magic
6097 */
6098 DEBUG_SET_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC);
6099
6100 /*
6101 * Increment assignment count
6102 */
6103 tal->type_assignment_count++;
6104 DEBUG_ASSERT(tal->type_assignment_count > 0, "Bad iteration count: %d\n", tal->type_assignment_count);
Gareth Williamsb39e7c22015-03-25 10:15:33 +00006105#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00006106 spin_unlock_bh(&ecm_db_lock);
6107}
6108EXPORT_SYMBOL(ecm_db_connection_classifier_assign);
6109
6110/*
6111 * ecm_db_connection_classifier_assignments_get_and_ref()
6112 * Populate the given array with references to the currently assigned classifiers.
6113 *
6114 * This function returns the number of assignments starting from [0].
6115 * [0] is the lowest priority classifier, [return_val - 1] is the highest priority.
6116 * Release each classifier when you are done, for convenience use ecm_db_connection_assignments_release().
6117 *
6118 * NOTE: The array also contains the default classifier too which of course will always be at [0]
6119 *
6120 * WARNING: The array MUST be of size ECM_CLASSIFIER_TYPES.
6121 */
6122int ecm_db_connection_classifier_assignments_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *assignments[])
6123{
6124 int aci_count;
6125 struct ecm_classifier_instance *aci;
6126 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6127
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006128 aci_count = 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00006129 spin_lock_bh(&ecm_db_lock);
6130 aci = ci->assignments;
6131 while (aci) {
6132 aci->ref(aci);
6133 assignments[aci_count++] = aci;
6134 aci = aci->ca_next;
6135 }
6136 spin_unlock_bh(&ecm_db_lock);
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006137 DEBUG_ASSERT(aci_count >= 1, "%p: Must have at least default classifier!\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00006138 return aci_count;
6139}
6140EXPORT_SYMBOL(ecm_db_connection_classifier_assignments_get_and_ref);
6141
6142/*
6143 * ecm_db_connection_assignments_release()
6144 * Release references to classifiers in the assignments array
6145 */
6146void ecm_db_connection_assignments_release(int assignment_count, struct ecm_classifier_instance *assignments[])
6147{
6148 int i;
6149 for (i = 0; i < assignment_count; ++i) {
6150 struct ecm_classifier_instance *aci = assignments[i];
6151 if (aci) {
6152 aci->deref(aci);
6153 }
6154 }
6155}
6156EXPORT_SYMBOL(ecm_db_connection_assignments_release);
6157
6158/*
6159 * ecm_db_connection_assigned_classifier_find_and_ref()
6160 * Return a ref to classifier of the requested type, if found
6161 */
6162struct ecm_classifier_instance *ecm_db_connection_assigned_classifier_find_and_ref(struct ecm_db_connection_instance *ci, ecm_classifier_type_t type)
6163{
6164 struct ecm_classifier_instance *ca;
6165 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6166 spin_lock_bh(&ecm_db_lock);
6167 ca = ci->assignments_by_type[type];
6168 if (ca) {
6169 ca->ref(ca);
6170 }
6171 spin_unlock_bh(&ecm_db_lock);
6172 return ca;
6173}
6174EXPORT_SYMBOL(ecm_db_connection_assigned_classifier_find_and_ref);
6175
6176/*
6177 * ecm_db_connection_classifier_unassign()
6178 * Unassign a classifier
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006179 *
6180 * The default classifier cannot be unassigned.
Ben Menchaca84f36632014-02-28 20:57:38 +00006181 */
6182void ecm_db_connection_classifier_unassign(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *cci)
6183{
6184 ecm_classifier_type_t ca_type;
Ben Menchaca84f36632014-02-28 20:57:38 +00006185
Shyam Sunder8793f612016-01-06 20:16:20 +05306186 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00006187
Ben Menchaca84f36632014-02-28 20:57:38 +00006188 /*
6189 * Get the type
6190 */
6191 ca_type = cci->type_get(cci);
Shyam Sunder8793f612016-01-06 20:16:20 +05306192 DEBUG_ASSERT(ca_type != ECM_CLASSIFIER_TYPE_DEFAULT, "%p: Cannot unassign default", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00006193
Murat Sezginfa915da2016-04-04 16:45:34 -07006194 if (ca_type >= ECM_CLASSIFIER_TYPES) {
6195 DEBUG_WARN("%p: ca_type: %d is higher than the max classifier type number: %d\n", ci, ca_type, (ECM_CLASSIFIER_TYPES - 1));
6196 return;
6197 }
6198
Ben Menchaca84f36632014-02-28 20:57:38 +00006199 DEBUG_TRACE("%p: Unassign type: %d, classifier: %p\n", ci, ca_type, cci);
6200
Ben Menchaca84f36632014-02-28 20:57:38 +00006201 /*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006202 * NOTE: It is possible that in SMP this classifier has already been unassigned.
Ben Menchaca84f36632014-02-28 20:57:38 +00006203 */
Shyam Sunder8793f612016-01-06 20:16:20 +05306204 spin_lock_bh(&ecm_db_lock);
Gareth Williamsee0a38a2014-06-05 15:41:20 +01006205 if (ci->assignments_by_type[ca_type] == NULL) {
6206 spin_unlock_bh(&ecm_db_lock);
6207 DEBUG_TRACE("%p: Classifier type: %d already unassigned\n", ci, ca_type);
6208 return;
6209 }
Shyam Sunder8793f612016-01-06 20:16:20 +05306210 _ecm_db_connection_classifier_unassign(ci, cci, ca_type);
Ben Menchaca84f36632014-02-28 20:57:38 +00006211 spin_unlock_bh(&ecm_db_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00006212}
6213EXPORT_SYMBOL(ecm_db_connection_classifier_unassign);
6214
Gareth Williamsb39e7c22015-03-25 10:15:33 +00006215#ifdef ECM_DB_CTA_TRACK_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00006216/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006217 * ecm_db_connection_by_classifier_type_assignment_get_and_ref_first()
6218 * Return a reference to the first connection for which a classifier of the given type is associated with
6219 *
6220 * WARNING: YOU MUST NOT USE ecm_db_connection_deref() to release the references taken using this API.
6221 * YOU MUST use ecm_db_connection_by_classifier_type_assignment_deref(), this ensures type assignment list integrity.
6222 */
6223struct ecm_db_connection_instance *ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ecm_classifier_type_t ca_type)
6224{
6225 struct ecm_db_connection_classifier_type_assignment_list *tal;
6226 struct ecm_db_connection_instance *ci;
6227
6228 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
6229
6230 DEBUG_TRACE("Get and ref first connection assigned with classifier type: %d\n", ca_type);
6231
6232 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
6233 spin_lock_bh(&ecm_db_lock);
6234 ci = tal->type_assignments_list;
6235 while (ci) {
6236 struct ecm_db_connection_classifier_type_assignment *ta;
6237 ta = &ci->type_assignment[ca_type];
6238 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
6239
6240 if (ta->pending_unassign) {
6241 DEBUG_TRACE("Skip %p, pending unassign for type: %d\n", ci, ca_type);
6242 ci = ta->next;
6243 continue;
6244 }
6245
6246 /*
6247 * Take reference to this connection.
6248 * NOTE: Hold both the connection and the assignment entry so that when we unlock both the connection
6249 * and the type assignment list entry maintains integrity.
6250 */
6251 _ecm_db_connection_ref(ci);
6252 ta->iteration_count++;
6253 DEBUG_ASSERT(ta->iteration_count > 0, "Bad Iteration count: %d for type: %d, connection: %p\n", ta->iteration_count, ca_type, ci);
6254 spin_unlock_bh(&ecm_db_lock);
6255 return ci;
6256 }
6257 spin_unlock_bh(&ecm_db_lock);
6258 return NULL;
6259}
6260EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_get_and_ref_first);
6261
6262/*
6263 * ecm_db_connection_by_classifier_type_assignment_get_and_ref_next()
6264 * Return a reference to the next connection for which a classifier of the given type is associated with.
6265 *
6266 * WARNING: YOU MUST NOT USE ecm_db_connection_deref() to release the references taken using this API.
6267 * YOU MUST use ecm_db_connection_by_classifier_type_assignment_deref(), this ensures type assignment list integrity.
6268 */
6269struct 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)
6270{
6271 struct ecm_db_connection_classifier_type_assignment *ta;
6272 struct ecm_db_connection_instance *cin;
6273
6274 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
6275 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6276
6277 DEBUG_TRACE("Get and ref next connection assigned with classifier type: %d and ci: %p\n", ca_type, ci);
6278
6279 spin_lock_bh(&ecm_db_lock);
6280 ta = &ci->type_assignment[ca_type];
6281 cin = ta->next;
6282 while (cin) {
6283 struct ecm_db_connection_classifier_type_assignment *tan;
6284
6285 tan = &cin->type_assignment[ca_type];
6286 DEBUG_CHECK_MAGIC(tan, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", tan, cin);
6287
6288 if (tan->pending_unassign) {
6289 DEBUG_TRACE("Skip %p, pending unassign for type: %d\n", cin, ca_type);
6290 cin = tan->next;
6291 continue;
6292 }
6293
6294 /*
6295 * Take reference to this connection.
6296 * NOTE: Hold both the connection and the assignment entry so that when we unlock both the connection
6297 * and the type assignment list entry maintains integrity.
6298 */
6299 _ecm_db_connection_ref(cin);
6300 tan->iteration_count++;
6301 DEBUG_ASSERT(tan->iteration_count > 0, "Bad Iteration count: %d for type: %d, connection: %p\n", tan->iteration_count, ca_type, cin);
6302 spin_unlock_bh(&ecm_db_lock);
6303 return cin;
6304 }
6305 spin_unlock_bh(&ecm_db_lock);
6306 return NULL;
6307}
6308EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_get_and_ref_next);
6309
6310/*
6311 * ecm_db_connection_by_classifier_type_assignment_deref()
6312 * Release a reference to a connection while iterating a classifier type assignment list
6313 */
6314void ecm_db_connection_by_classifier_type_assignment_deref(struct ecm_db_connection_instance *ci, ecm_classifier_type_t ca_type)
6315{
6316 struct ecm_db_connection_classifier_type_assignment_list *tal;
6317 struct ecm_db_connection_classifier_type_assignment *ta;
6318
6319 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
6320 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6321
6322 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
6323
6324 /*
6325 * Drop the iteration count
6326 */
6327 spin_lock_bh(&ecm_db_lock);
6328 ta = &ci->type_assignment[ca_type];
6329 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
6330 ta->iteration_count--;
6331 DEBUG_ASSERT(ta->iteration_count >= 0, "Bad Iteration count: %d for type: %d, connection: %p\n", ta->iteration_count, ca_type, ci);
6332
6333 /*
6334 * If there are no more iterations on-going and this is pending unassign then we can remove it from the assignments list
6335 */
6336 if (ta->pending_unassign && (ta->iteration_count == 0)) {
6337 DEBUG_INFO("%p: Remove type assignment: %d\n", ci, ca_type);
6338 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
6339 }
6340 spin_unlock_bh(&ecm_db_lock);
6341 ecm_db_connection_deref(ci);
6342}
6343EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_deref);
6344
6345/*
6346 * ecm_db_connection_make_defunct_by_assignment_type()
6347 * Make defunct all connections that are currently assigned to a classifier of the given type
6348 */
6349void ecm_db_connection_make_defunct_by_assignment_type(ecm_classifier_type_t ca_type)
6350{
6351 struct ecm_db_connection_instance *ci;
6352
6353 DEBUG_INFO("Make defunct all assigned to type: %d\n", ca_type);
6354
6355 ci = ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ca_type);
6356 while (ci) {
6357 struct ecm_db_connection_instance *cin;
6358
6359 DEBUG_TRACE("%p: Make defunct: %d\n", ci, ca_type);
6360 ecm_db_connection_make_defunct(ci);
6361
6362 cin = ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(ci, ca_type);
6363 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
6364 ci = cin;
6365 }
6366}
6367EXPORT_SYMBOL(ecm_db_connection_make_defunct_by_assignment_type);
6368
6369/*
6370 * ecm_db_connection_regenerate_by_assignment_type()
6371 * Cause regeneration all connections that are currently assigned to a classifier of the given type
6372 */
6373void ecm_db_connection_regenerate_by_assignment_type(ecm_classifier_type_t ca_type)
6374{
6375 struct ecm_db_connection_instance *ci;
6376
6377 DEBUG_INFO("Regenerate all assigned to type: %d\n", ca_type);
6378
6379 ci = ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ca_type);
6380 while (ci) {
6381 struct ecm_db_connection_instance *cin;
6382
6383 DEBUG_TRACE("%p: Re-generate: %d\n", ci, ca_type);
Xiaoping Faned6d37e2015-09-17 14:13:47 -07006384 ecm_db_connection_regenerate(ci);
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006385
6386 cin = ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(ci, ca_type);
6387 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
6388 ci = cin;
6389 }
6390}
6391EXPORT_SYMBOL(ecm_db_connection_regenerate_by_assignment_type);
Gareth Williamsb39e7c22015-03-25 10:15:33 +00006392#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006393
6394/*
Ben Menchaca84f36632014-02-28 20:57:38 +00006395 * ecm_db_connection_from_interfaces_get_and_ref()
6396 * Return the interface heirarchy from which this connection is established.
6397 *
6398 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6399 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6400 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6401 *
6402 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6403 */
6404int32_t ecm_db_connection_from_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6405{
6406 int32_t n;
6407 int32_t i;
6408 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6409
6410 spin_lock_bh(&ecm_db_lock);
6411 n = ci->from_interface_first;
6412 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6413 interfaces[i] = ci->from_interfaces[i];
6414 _ecm_db_iface_ref(interfaces[i]);
6415 }
6416 spin_unlock_bh(&ecm_db_lock);
6417 return n;
6418}
6419EXPORT_SYMBOL(ecm_db_connection_from_interfaces_get_and_ref);
6420
6421/*
6422 * ecm_db_connection_to_interfaces_get_and_ref()
6423 * Return the interface heirarchy to which this connection is established.
6424 *
6425 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6426 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6427 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6428 *
6429 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6430 */
6431int32_t ecm_db_connection_to_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6432{
6433 int32_t n;
6434 int32_t i;
6435 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6436
6437 spin_lock_bh(&ecm_db_lock);
6438 n = ci->to_interface_first;
6439 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6440 interfaces[i] = ci->to_interfaces[i];
6441 _ecm_db_iface_ref(interfaces[i]);
6442 }
6443 spin_unlock_bh(&ecm_db_lock);
6444 return n;
6445}
6446EXPORT_SYMBOL(ecm_db_connection_to_interfaces_get_and_ref);
6447
6448/*
6449 * ecm_db_connection_from_nat_interfaces_get_and_ref()
6450 * Return the interface heirarchy from (nat) which this connection is established.
6451 *
6452 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6453 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6454 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6455 *
6456 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6457 */
6458int32_t ecm_db_connection_from_nat_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6459{
6460 int32_t n;
6461 int32_t i;
6462 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6463
6464 spin_lock_bh(&ecm_db_lock);
6465 n = ci->from_nat_interface_first;
6466 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6467 interfaces[i] = ci->from_nat_interfaces[i];
6468 _ecm_db_iface_ref(interfaces[i]);
6469 }
6470 spin_unlock_bh(&ecm_db_lock);
6471 return n;
6472}
6473EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_get_and_ref);
6474
6475/*
6476 * ecm_db_connection_to_nat_interfaces_get_and_ref()
6477 * Return the interface heirarchy to (nat) which this connection is established.
6478 *
6479 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6480 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6481 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6482 *
6483 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6484 */
6485int32_t ecm_db_connection_to_nat_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6486{
6487 int32_t n;
6488 int32_t i;
6489 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6490
6491 spin_lock_bh(&ecm_db_lock);
6492 n = ci->to_nat_interface_first;
6493 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6494 interfaces[i] = ci->to_nat_interfaces[i];
6495 _ecm_db_iface_ref(interfaces[i]);
6496 }
6497 spin_unlock_bh(&ecm_db_lock);
6498 return n;
6499}
6500EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_get_and_ref);
6501
6502/*
6503 * ecm_db_connection_interfaces_deref()
6504 * Release all interfaces in the given interfaces heirarchy array.
6505 *
6506 * 'first' is the number returned by one of the ecm_db_connection_xx_interfaces_get_and_ref().
6507 * You should NOT have released any references to any of the interfaces in the array youself, this releases them all.
6508 */
6509void ecm_db_connection_interfaces_deref(struct ecm_db_iface_instance *interfaces[], int32_t first)
6510{
6511 int32_t i;
6512 DEBUG_ASSERT((first >= 0) && (first <= ECM_DB_IFACE_HEIRARCHY_MAX), "Bad first: %d\n", first);
6513
6514 for (i = first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6515 ecm_db_iface_deref(interfaces[i]);
6516 }
6517}
6518EXPORT_SYMBOL(ecm_db_connection_interfaces_deref);
6519
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306520#ifdef ECM_MULTICAST_ENABLE
6521/*
6522 * ecm_db_multicast_connection_to_interfaces_reset()
6523 * Reset the 'to' interfaces heirarchy with a new set of destination interfaces for
6524 * the multicast connection
6525 */
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306526int 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 +05306527{
6528 struct ecm_db_iface_instance *ii_temp;
6529 struct ecm_db_iface_instance *ii_single;
6530 struct ecm_db_iface_instance **ifaces;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306531 struct ecm_db_iface_instance *ii_db;
6532 struct ecm_db_iface_instance *ii_db_single;
6533 struct ecm_db_iface_instance **ifaces_db;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306534 int32_t *nf_p;
6535 int32_t heirarchy_index;
6536 int32_t i;
6537 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6538
6539 /*
6540 * First remove all old interface hierarchies if any hierarchy
6541 * uphold in the ci->to_mcast_interfaces.
6542 */
6543 ecm_db_multicast_connection_to_interfaces_clear(ci);
6544
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306545 ci->to_mcast_interfaces = (struct ecm_db_iface_instance *)kzalloc(ECM_DB_TO_MCAST_INTERFACES_SIZE, GFP_ATOMIC | __GFP_NOWARN);
6546 if (!ci->to_mcast_interfaces) {
6547 DEBUG_WARN("%p: Memory is not available for to_mcast_interfaces\n", ci);
6548 return -1;
6549 }
6550
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306551 /*
6552 * Iterate the to interface list and add the new interface hierarchies
6553 */
6554 spin_lock_bh(&ecm_db_lock);
6555
6556 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
6557 ii_temp = ecm_db_multicast_if_heirarchy_get(interfaces, heirarchy_index);
6558 nf_p = ecm_db_multicast_if_first_get_at_index(new_first, heirarchy_index);
6559
6560 if (*nf_p == ECM_DB_IFACE_HEIRARCHY_MAX) {
6561 continue;
6562 }
6563
6564 for (i = *nf_p; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6565
6566 /*
6567 * Store valid dest interface list into DB connection
6568 */
6569 ii_single = ecm_db_multicast_if_instance_get_at_index(ii_temp, i);
6570 ifaces = (struct ecm_db_iface_instance **)ii_single;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306571
6572 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
6576 *ifaces_db = *ifaces;
6577 _ecm_db_iface_ref(*ifaces_db);
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306578 }
6579 }
6580
6581 /*
6582 * Update the first indices
6583 */
6584 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
6585 nf_p = ecm_db_multicast_if_first_get_at_index(new_first, heirarchy_index);
6586 ci->to_mcast_interface_first[heirarchy_index] = *nf_p;
6587 }
6588
6589 ci->to_mcast_interfaces_set = true;
6590 spin_unlock_bh(&ecm_db_lock);
6591
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306592 return 0;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306593}
6594EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_reset);
6595
6596/*
6597 * ecm_db_multicast_connection_to_interfaces_update()
6598 * Merge the latest valid multicast destination interfaces into DB Connection
6599 * instance. The new list holds the updated list of interfaces for the multicast
6600 * connection, due to JOIN updates.
6601 */
6602void ecm_db_multicast_connection_to_interfaces_update(struct ecm_db_connection_instance *ci,
6603 struct ecm_db_iface_instance *interfaces, int32_t *mc_join_first, int32_t *mc_join_valid_idx)
6604{
6605 struct ecm_db_iface_instance *ii_temp;
6606 struct ecm_db_iface_instance *ii_single;
6607 struct ecm_db_iface_instance **ifaces;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306608 struct ecm_db_iface_instance *ii_db;
6609 struct ecm_db_iface_instance *ii_db_single;
6610 struct ecm_db_iface_instance **ifaces_db;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306611 int32_t *join_first;
6612 int32_t *join_idx;
6613 int heirarchy_index;
6614 int32_t if_index;
6615 int32_t i;
6616
6617 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6618
6619 /*
6620 * Iterate the to interface list, adding in the new
6621 */
6622 spin_lock_bh(&ecm_db_lock);
6623 for (heirarchy_index = 0, if_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
6624 ii_temp = ecm_db_multicast_if_heirarchy_get(interfaces, if_index);
6625 join_first = ecm_db_multicast_if_first_get_at_index(mc_join_first, if_index);
6626 join_idx = ecm_db_multicast_if_num_get_at_index(mc_join_valid_idx, heirarchy_index);
6627
6628 if (*join_idx == 0) {
6629
6630 /*
6631 * No update for the interface at this index
6632 */
6633 continue;
6634 }
6635
6636 /*
6637 * This interface has joined the group. Add it to the list.
6638 */
6639 if (*join_first == ECM_DB_IFACE_HEIRARCHY_MAX) {
6640 if_index++;
6641 continue;
6642 }
6643
6644 ci->to_mcast_interface_first[heirarchy_index] = *join_first;
6645 for (i = *join_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6646
6647 /*
6648 * Store valid dest interface list into DB connection
6649 */
6650 ii_single = ecm_db_multicast_if_instance_get_at_index(ii_temp, i);
6651 ifaces = (struct ecm_db_iface_instance **)ii_single;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306652 ii_db = ecm_db_multicast_if_heirarchy_get(ci->to_mcast_interfaces, heirarchy_index);
6653 ii_db_single = ecm_db_multicast_if_instance_get_at_index(ii_db, i);
6654 ifaces_db = (struct ecm_db_iface_instance **)ii_db_single;
6655 *ifaces_db = *ifaces;
6656 _ecm_db_iface_ref(*ifaces_db);
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306657 }
6658 if_index++;
6659 }
6660 spin_unlock_bh(&ecm_db_lock);
6661 return;
6662}
6663EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_update);
6664#endif
6665
Ben Menchaca84f36632014-02-28 20:57:38 +00006666/*
6667 * ecm_db_connection_from_interfaces_reset()
6668 * Reset the from interfaces heirarchy with a new set of interfaces
6669 *
6670 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6671 * This is deliberate - it's stating that there is no list :-)
6672 */
6673void ecm_db_connection_from_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6674{
6675 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6676 int32_t old_first;
6677 int32_t i;
6678 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6679
6680 /*
6681 * Iterate the from interface list, removing the old and adding in the new
6682 */
6683 spin_lock_bh(&ecm_db_lock);
6684 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6685 /*
6686 * Put any previous interface into the old list
6687 */
6688 old[i] = ci->from_interfaces[i];
6689 ci->from_interfaces[i] = NULL;
6690 if (i < new_first) {
6691 continue;
6692 }
6693 ci->from_interfaces[i] = interfaces[i];
6694 _ecm_db_iface_ref(ci->from_interfaces[i]);
6695 }
6696
6697 /*
6698 * Get old first and update to new first
6699 */
6700 old_first = ci->from_interface_first;
6701 ci->from_interface_first = new_first;
6702 ci->from_interface_set = true;
6703 spin_unlock_bh(&ecm_db_lock);
6704
6705 /*
6706 * Release old
6707 */
6708 ecm_db_connection_interfaces_deref(old, old_first);
6709}
6710EXPORT_SYMBOL(ecm_db_connection_from_interfaces_reset);
6711
6712/*
6713 * ecm_db_connection_to_interfaces_reset()
6714 * Reset the to interfaces heirarchy with a new set of interfaces
6715 *
6716 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6717 * This is deliberate - it's stating that there is no list :-)
6718 */
6719void ecm_db_connection_to_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6720{
6721 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6722 int32_t old_first;
6723 int32_t i;
6724 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6725
6726 /*
6727 * Iterate the to interface list, removing the old and adding in the new
6728 */
6729 spin_lock_bh(&ecm_db_lock);
6730 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6731 /*
6732 * Put any previous interface into the old list
6733 */
6734 old[i] = ci->to_interfaces[i];
6735 ci->to_interfaces[i] = NULL;
6736 if (i < new_first) {
6737 continue;
6738 }
6739 ci->to_interfaces[i] = interfaces[i];
6740 _ecm_db_iface_ref(ci->to_interfaces[i]);
6741 }
6742
6743 /*
6744 * Get old first and update to new first
6745 */
6746 old_first = ci->to_interface_first;
6747 ci->to_interface_first = new_first;
6748 ci->to_interface_set = true;
6749 spin_unlock_bh(&ecm_db_lock);
6750
6751 /*
6752 * Release old
6753 */
6754 ecm_db_connection_interfaces_deref(old, old_first);
6755}
6756EXPORT_SYMBOL(ecm_db_connection_to_interfaces_reset);
6757
6758/*
6759 * ecm_db_connection_from_nat_interfaces_reset()
6760 * Reset the from NAT interfaces heirarchy with a new set of interfaces
6761 *
6762 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6763 * This is deliberate - it's stating that there is no list :-)
6764 */
6765void ecm_db_connection_from_nat_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6766{
6767 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6768 int32_t old_first;
6769 int32_t i;
6770 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6771
6772 /*
6773 * Iterate the from nat interface list, removing the old and adding in the new
6774 */
6775 spin_lock_bh(&ecm_db_lock);
6776 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6777 /*
6778 * Put any previous interface into the old list
6779 */
6780 old[i] = ci->from_nat_interfaces[i];
6781 ci->from_nat_interfaces[i] = NULL;
6782 if (i < new_first) {
6783 continue;
6784 }
6785 ci->from_nat_interfaces[i] = interfaces[i];
6786 _ecm_db_iface_ref(ci->from_nat_interfaces[i]);
6787 }
6788
6789 /*
6790 * Get old first and update to new first
6791 */
6792 old_first = ci->from_nat_interface_first;
6793 ci->from_nat_interface_first = new_first;
6794 ci->from_nat_interface_set = true;
6795 spin_unlock_bh(&ecm_db_lock);
6796
6797 /*
6798 * Release old
6799 */
6800 ecm_db_connection_interfaces_deref(old, old_first);
6801}
6802EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_reset);
6803
6804/*
6805 * ecm_db_connection_to_nat_interfaces_reset()
6806 * Reset the to NAT interfaces heirarchy with a new set of interfaces.
6807 *
6808 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6809 * This is deliberate - it's stating that there is no list :-)
6810 */
6811void ecm_db_connection_to_nat_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6812{
6813 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6814 int32_t old_first;
6815 int32_t i;
6816 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6817
6818 /*
6819 * Iterate the to nat interface list, removing the old and adding in the new
6820 */
6821 spin_lock_bh(&ecm_db_lock);
6822 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6823 /*
6824 * Put any previous interface into the old list
6825 */
6826 old[i] = ci->to_nat_interfaces[i];
6827 ci->to_nat_interfaces[i] = NULL;
6828 if (i < new_first) {
6829 continue;
6830 }
6831 ci->to_nat_interfaces[i] = interfaces[i];
6832 _ecm_db_iface_ref(ci->to_nat_interfaces[i]);
6833 }
6834
6835 /*
6836 * Get old first and update to new first
6837 */
6838 old_first = ci->to_nat_interface_first;
6839 ci->to_nat_interface_first = new_first;
6840 ci->to_nat_interface_set = true;
6841 spin_unlock_bh(&ecm_db_lock);
6842
6843 /*
6844 * Release old
6845 */
6846 ecm_db_connection_interfaces_deref(old, old_first);
6847}
6848EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_reset);
6849
6850/*
6851 * ecm_db_connection_to_nat_interfaces_get_count()
6852 * Return the number of interfaces in the list
6853 */
6854int32_t ecm_db_connection_to_nat_interfaces_get_count(struct ecm_db_connection_instance *ci)
6855{
6856 int32_t first;
6857 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6858 spin_lock_bh(&ecm_db_lock);
6859 first = ci->to_nat_interface_first;
6860 spin_unlock_bh(&ecm_db_lock);
6861 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6862}
6863EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_get_count);
6864
6865/*
6866 * ecm_db_connection_from_nat_interfaces_get_count()
6867 * Return the number of interfaces in the list
6868 */
6869int32_t ecm_db_connection_from_nat_interfaces_get_count(struct ecm_db_connection_instance *ci)
6870{
6871 int32_t first;
6872 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6873 spin_lock_bh(&ecm_db_lock);
6874 first = ci->from_nat_interface_first;
6875 spin_unlock_bh(&ecm_db_lock);
6876 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6877}
6878EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_get_count);
6879
6880/*
6881 * ecm_db_connection_to_interfaces_get_count()
6882 * Return the number of interfaces in the list
6883 */
6884int32_t ecm_db_connection_to_interfaces_get_count(struct ecm_db_connection_instance *ci)
6885{
6886 int32_t first;
6887 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6888 spin_lock_bh(&ecm_db_lock);
6889 first = ci->to_interface_first;
6890 spin_unlock_bh(&ecm_db_lock);
6891 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6892}
6893EXPORT_SYMBOL(ecm_db_connection_to_interfaces_get_count);
6894
6895/*
6896 * ecm_db_connection_from_interfaces_get_count()
6897 * Return the number of interfaces in the list
6898 */
6899int32_t ecm_db_connection_from_interfaces_get_count(struct ecm_db_connection_instance *ci)
6900{
6901 int32_t first;
6902 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6903 spin_lock_bh(&ecm_db_lock);
6904 first = ci->from_interface_first;
6905 spin_unlock_bh(&ecm_db_lock);
6906 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6907}
6908EXPORT_SYMBOL(ecm_db_connection_from_interfaces_get_count);
6909
6910/*
6911 * ecm_db_connection_to_interfaces_set_check()
6912 * Returns true if the interface list has been set - even if set to an empty list!
6913 */
6914bool ecm_db_connection_to_interfaces_set_check(struct ecm_db_connection_instance *ci)
6915{
6916 bool set;
6917
6918 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6919 spin_lock_bh(&ecm_db_lock);
6920 set = ci->to_interface_set;
6921 spin_unlock_bh(&ecm_db_lock);
6922 return set;
6923}
6924EXPORT_SYMBOL(ecm_db_connection_to_interfaces_set_check);
6925
6926/*
6927 * ecm_db_connection_from_interfaces_set_check()
6928 * Returns true if the interface list has been set - even if set to an empty list!
6929 */
6930bool ecm_db_connection_from_interfaces_set_check(struct ecm_db_connection_instance *ci)
6931{
6932 bool set;
6933
6934 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6935 spin_lock_bh(&ecm_db_lock);
6936 set = ci->from_interface_set;
6937 spin_unlock_bh(&ecm_db_lock);
6938 return set;
6939}
6940EXPORT_SYMBOL(ecm_db_connection_from_interfaces_set_check);
6941
6942/*
6943 * ecm_db_connection_to_nat_interfaces_set_check()
6944 * Returns true if the interface list has been set - even if set to an empty list!
6945 */
6946bool ecm_db_connection_to_nat_interfaces_set_check(struct ecm_db_connection_instance *ci)
6947{
6948 bool set;
6949
6950 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6951 spin_lock_bh(&ecm_db_lock);
6952 set = ci->to_nat_interface_set;
6953 spin_unlock_bh(&ecm_db_lock);
6954 return set;
6955}
6956EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_set_check);
6957
6958/*
6959 * ecm_db_connection_from_nat_interfaces_set_check()
6960 * Returns true if the interface list has been set - even if set to an empty list!
6961 */
6962bool ecm_db_connection_from_nat_interfaces_set_check(struct ecm_db_connection_instance *ci)
6963{
6964 bool set;
6965
6966 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6967 spin_lock_bh(&ecm_db_lock);
6968 set = ci->from_nat_interface_set;
6969 spin_unlock_bh(&ecm_db_lock);
6970 return set;
6971}
6972EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_set_check);
6973
6974/*
6975 * ecm_db_connection_from_interfaces_clear()
6976 * Clear down the interfaces list, marking the list as not set
6977 */
6978void ecm_db_connection_from_interfaces_clear(struct ecm_db_connection_instance *ci)
6979{
6980 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
6981 int32_t discard_first;
6982 int32_t i;
6983
6984 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6985
6986 spin_lock_bh(&ecm_db_lock);
6987 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6988 discard[i] = ci->from_interfaces[i];
6989 }
6990
6991 discard_first = ci->from_interface_first;
6992 ci->from_interface_set = false;
6993 ci->from_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
6994 spin_unlock_bh(&ecm_db_lock);
6995
6996 /*
6997 * Release previous
6998 */
6999 ecm_db_connection_interfaces_deref(discard, discard_first);
7000}
7001EXPORT_SYMBOL(ecm_db_connection_from_interfaces_clear);
7002
7003/*
7004 * ecm_db_connection_from_nat_interfaces_clear()
7005 * Clear down the interfaces list, marking the list as not set
7006 */
7007void ecm_db_connection_from_nat_interfaces_clear(struct ecm_db_connection_instance *ci)
7008{
7009 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
7010 int32_t discard_first;
7011 int32_t i;
7012
7013 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
7014
7015 spin_lock_bh(&ecm_db_lock);
7016 for (i = ci->from_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
7017 discard[i] = ci->from_nat_interfaces[i];
7018 }
7019
7020 discard_first = ci->from_nat_interface_first;
7021 ci->from_nat_interface_set = false;
7022 ci->from_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
7023 spin_unlock_bh(&ecm_db_lock);
7024
7025 /*
7026 * Release previous
7027 */
7028 ecm_db_connection_interfaces_deref(discard, discard_first);
7029}
7030EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_clear);
7031
7032/*
7033 * ecm_db_connection_to_interfaces_clear()
7034 * Clear down the interfaces list, marking the list as not set
7035 */
7036void ecm_db_connection_to_interfaces_clear(struct ecm_db_connection_instance *ci)
7037{
7038 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
7039 int32_t discard_first;
7040 int32_t i;
7041
7042 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
7043
7044 spin_lock_bh(&ecm_db_lock);
7045 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
7046 discard[i] = ci->to_interfaces[i];
7047 }
7048
7049 discard_first = ci->to_interface_first;
7050 ci->to_interface_set = false;
7051 ci->to_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
7052 spin_unlock_bh(&ecm_db_lock);
7053
7054 /*
7055 * Release previous
7056 */
7057 ecm_db_connection_interfaces_deref(discard, discard_first);
7058}
7059EXPORT_SYMBOL(ecm_db_connection_to_interfaces_clear);
7060
7061/*
7062 * ecm_db_connection_to_nat_interfaces_clear()
7063 * Clear down the interfaces list, marking the list as not set
7064 */
7065void ecm_db_connection_to_nat_interfaces_clear(struct ecm_db_connection_instance *ci)
7066{
7067 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
7068 int32_t discard_first;
7069 int32_t i;
7070
7071 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
7072
7073 spin_lock_bh(&ecm_db_lock);
7074 for (i = ci->to_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
7075 discard[i] = ci->to_nat_interfaces[i];
7076 }
7077
7078 discard_first = ci->to_nat_interface_first;
7079 ci->to_nat_interface_set = false;
7080 ci->to_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
7081 spin_unlock_bh(&ecm_db_lock);
7082
7083 /*
7084 * Release previous
7085 */
7086 ecm_db_connection_interfaces_deref(discard, discard_first);
7087}
7088EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_clear);
7089
7090/*
Murat Sezginfdb595e2016-05-10 11:27:37 -07007091 * ecm_db_front_end_instance_ref_and_set()
7092 * Refs and sets the front end instance of connection.
7093 */
7094void ecm_db_front_end_instance_ref_and_set(struct ecm_db_connection_instance *ci, struct ecm_front_end_connection_instance *feci)
7095{
7096 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
7097
7098 feci->ref(feci);
7099 ci->feci = feci;
7100}
7101EXPORT_SYMBOL(ecm_db_front_end_instance_ref_and_set);
7102
7103/*
Ben Menchaca84f36632014-02-28 20:57:38 +00007104 * ecm_db_connection_add()
7105 * Add the connection into the database.
7106 *
7107 * NOTE: The parameters are DIRECTIONAL in terms of which mapping established the connection.
7108 * 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.
7109 */
7110void ecm_db_connection_add(struct ecm_db_connection_instance *ci,
Ben Menchaca84f36632014-02-28 20:57:38 +00007111 struct ecm_db_mapping_instance *mapping_from, struct ecm_db_mapping_instance *mapping_to,
7112 struct ecm_db_mapping_instance *mapping_nat_from, struct ecm_db_mapping_instance *mapping_nat_to,
Gareth Williams90f2a282014-08-27 15:56:25 +01007113 struct ecm_db_node_instance *from_node, struct ecm_db_node_instance *to_node,
7114 struct ecm_db_node_instance *from_nat_node, struct ecm_db_node_instance *to_nat_node,
Gareth Williams3e5b37f2015-05-13 10:04:12 +01007115 int ip_version,
Ben Menchaca84f36632014-02-28 20:57:38 +00007116 int protocol, ecm_db_direction_t dir,
7117 ecm_db_connection_final_callback_t final,
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07007118 ecm_db_connection_defunct_callback_t defunct,
Ben Menchaca84f36632014-02-28 20:57:38 +00007119 ecm_db_timer_group_t tg, bool is_routed,
7120 void *arg)
7121{
7122 ecm_db_connection_hash_t hash_index;
7123 ecm_db_connection_serial_hash_t serial_hash_index;
7124 struct ecm_db_listener_instance *li;
Gareth Williamsb5903892015-03-20 15:13:07 +00007125#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007126 struct ecm_db_iface_instance *iface_from;
7127 struct ecm_db_iface_instance *iface_to;
7128 struct ecm_db_iface_instance *iface_nat_from;
7129 struct ecm_db_iface_instance *iface_nat_to;
Gareth Williamsb5903892015-03-20 15:13:07 +00007130#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007131
7132 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
7133 DEBUG_CHECK_MAGIC(mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_from);
7134 DEBUG_CHECK_MAGIC(mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_to);
7135 DEBUG_CHECK_MAGIC(mapping_nat_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_nat_from);
7136 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 +01007137 DEBUG_CHECK_MAGIC(from_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", from_node);
7138 DEBUG_CHECK_MAGIC(to_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", to_node);
7139 DEBUG_CHECK_MAGIC(from_nat_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", from_nat_node);
7140 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 +00007141 DEBUG_ASSERT((protocol >= 0) && (protocol <= 255), "%p: invalid protocol number %d\n", ci, protocol);
7142
7143 spin_lock_bh(&ecm_db_lock);
7144 DEBUG_ASSERT(!(ci->flags & ECM_DB_CONNECTION_FLAGS_INSERTED), "%p: inserted\n", ci);
7145 spin_unlock_bh(&ecm_db_lock);
7146
7147 /*
7148 * Record owner arg and callbacks
7149 */
7150 ci->final = final;
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07007151 ci->defunct = defunct;
Ben Menchaca84f36632014-02-28 20:57:38 +00007152 ci->arg = arg;
7153
Shyam Sunder317ca912016-01-22 16:51:28 +05307154#ifdef ECM_MULTICAST_ENABLE
7155 ci->ti = NULL;
7156#endif
7157
Ben Menchaca84f36632014-02-28 20:57:38 +00007158 /*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01007159 * Ensure default classifier has been assigned this is a must to ensure minimum level of classification
Ben Menchaca84f36632014-02-28 20:57:38 +00007160 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01007161 DEBUG_ASSERT(ci->assignments_by_type[ECM_CLASSIFIER_TYPE_DEFAULT], "%p: No default classifier assigned\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00007162
7163 /*
7164 * Connection takes references to the mappings
7165 */
7166 ecm_db_mapping_ref(mapping_from);
7167 ecm_db_mapping_ref(mapping_to);
7168 ci->mapping_from = mapping_from;
7169 ci->mapping_to = mapping_to;
7170
7171 ecm_db_mapping_ref(mapping_nat_from);
7172 ecm_db_mapping_ref(mapping_nat_to);
7173 ci->mapping_nat_from = mapping_nat_from;
7174 ci->mapping_nat_to = mapping_nat_to;
7175
7176 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01007177 * Take references to the nodes
7178 */
7179 ci->from_node = from_node;
7180 ecm_db_node_ref(from_node);
7181 ci->to_node = to_node;
7182 ecm_db_node_ref(to_node);
7183
7184 ci->from_nat_node = from_nat_node;
7185 ecm_db_node_ref(from_nat_node);
7186 ci->to_nat_node = to_nat_node;
7187 ecm_db_node_ref(to_nat_node);
7188
7189 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00007190 * Set the protocol and routed flag
7191 */
Gareth Williams3e5b37f2015-05-13 10:04:12 +01007192 ci->ip_version = ip_version;
Ben Menchaca84f36632014-02-28 20:57:38 +00007193 ci->protocol = protocol;
7194 ci->is_routed = is_routed;
7195
7196 /*
7197 * Set direction of connection
7198 */
7199 ci->direction = dir;
7200
7201 /*
7202 * Identify which hash chain this connection will go into
7203 */
7204 hash_index = ecm_db_connection_generate_hash_index(mapping_from->host->address, mapping_from->port, mapping_to->host->address, mapping_to->port, protocol);
7205 ci->hash_index = hash_index;
7206
7207 /*
7208 * Identify which serial hash chain this connection will go into
7209 */
7210 serial_hash_index = ecm_db_connection_generate_serial_hash_index(ci->serial);
7211 ci->serial_hash_index = serial_hash_index;
7212
7213 /*
7214 * Now we need to lock
7215 */
7216 spin_lock_bh(&ecm_db_lock);
7217
7218 /*
7219 * Increment protocol counter stats
7220 */
7221 ecm_db_connection_count_by_protocol[protocol]++;
7222 DEBUG_ASSERT(ecm_db_connection_count_by_protocol[protocol] > 0, "%p: Invalid protocol count %d\n", ci, ecm_db_connection_count_by_protocol[protocol]);
7223
Ben Menchaca84f36632014-02-28 20:57:38 +00007224 /*
7225 * Set time
7226 */
7227 ci->time_added = ecm_db_time;
7228
7229 /*
7230 * Add connection into the global list
7231 */
7232 ci->prev = NULL;
7233 ci->next = ecm_db_connections;
7234 if (ecm_db_connections) {
7235 ecm_db_connections->prev = ci;
7236 }
7237 ecm_db_connections = ci;
7238
7239 /*
7240 * Add this connection into the connections hash table
7241 */
7242 ci->flags |= ECM_DB_CONNECTION_FLAGS_INSERTED;
7243
7244 /*
Gareth Williamsb5903892015-03-20 15:13:07 +00007245 * Insert connection into the connections hash table
Ben Menchaca84f36632014-02-28 20:57:38 +00007246 */
7247 ci->hash_next = ecm_db_connection_table[hash_index];
7248 if (ecm_db_connection_table[hash_index]) {
7249 ecm_db_connection_table[hash_index]->hash_prev = ci;
7250 }
7251 ecm_db_connection_table[hash_index] = ci;
7252 ecm_db_connection_table_lengths[hash_index]++;
7253 DEBUG_ASSERT(ecm_db_connection_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ci, ecm_db_connection_table_lengths[hash_index]);
7254
7255 /*
7256 * Insert connection into the connections serial hash table
7257 */
7258 ci->serial_hash_next = ecm_db_connection_serial_table[serial_hash_index];
7259 if (ecm_db_connection_serial_table[serial_hash_index]) {
7260 ecm_db_connection_serial_table[serial_hash_index]->serial_hash_prev = ci;
7261 }
7262 ecm_db_connection_serial_table[serial_hash_index] = ci;
7263 ecm_db_connection_serial_table_lengths[serial_hash_index]++;
7264 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]);
7265
Gareth Williamsb5903892015-03-20 15:13:07 +00007266#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007267 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01007268 * Add this connection into the FROM node
7269 */
7270 ci->node_from_prev = NULL;
7271 ci->node_from_next = from_node->from_connections;
7272 if (from_node->from_connections) {
7273 from_node->from_connections->node_from_prev = ci;
7274 }
7275 from_node->from_connections = ci;
7276 from_node->from_connections_count++;
7277 DEBUG_ASSERT(from_node->from_connections_count > 0, "%p: invalid count\n", ci);
7278
7279 /*
7280 * Add this connection into the TO node
7281 */
7282 ci->node_to_prev = NULL;
7283 ci->node_to_next = to_node->to_connections;
7284 if (to_node->to_connections) {
7285 to_node->to_connections->node_to_prev = ci;
7286 }
7287 to_node->to_connections = ci;
7288 to_node->to_connections_count++;
7289 DEBUG_ASSERT(to_node->to_connections_count > 0, "%p: invalid count\n", ci);
7290
7291 /*
7292 * Add this connection into the FROM NAT node
7293 */
7294 ci->node_from_nat_prev = NULL;
7295 ci->node_from_nat_next = from_nat_node->from_nat_connections;
7296 if (from_nat_node->from_nat_connections) {
7297 from_nat_node->from_nat_connections->node_from_nat_prev = ci;
7298 }
7299 from_nat_node->from_nat_connections = ci;
7300 from_nat_node->from_nat_connections_count++;
7301 DEBUG_ASSERT(from_nat_node->from_nat_connections_count > 0, "%p: invalid count\n", ci);
7302
7303 /*
7304 * Add this connection into the TO NAT node
7305 */
7306 ci->node_to_nat_prev = NULL;
7307 ci->node_to_nat_next = to_nat_node->to_nat_connections;
7308 if (to_nat_node->to_nat_connections) {
7309 to_nat_node->to_nat_connections->node_to_nat_prev = ci;
7310 }
7311 to_nat_node->to_nat_connections = ci;
7312 to_nat_node->to_nat_connections_count++;
7313 DEBUG_ASSERT(to_nat_node->to_nat_connections_count > 0, "%p: invalid count\n", ci);
7314
7315 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00007316 * Add this connection into the FROM mapping
7317 */
7318 ci->from_prev = NULL;
7319 ci->from_next = mapping_from->from_connections;
7320 if (mapping_from->from_connections) {
7321 mapping_from->from_connections->from_prev = ci;
7322 }
7323 mapping_from->from_connections = ci;
7324
7325 /*
7326 * Add this connection into the TO mapping
7327 */
7328 ci->to_prev = NULL;
7329 ci->to_next = mapping_to->to_connections;
7330 if (mapping_to->to_connections) {
7331 mapping_to->to_connections->to_prev = ci;
7332 }
7333 mapping_to->to_connections = ci;
7334
7335 /*
7336 * Add this connection into the FROM NAT mapping
7337 */
7338 ci->from_nat_prev = NULL;
7339 ci->from_nat_next = mapping_nat_from->from_nat_connections;
7340 if (mapping_nat_from->from_nat_connections) {
7341 mapping_nat_from->from_nat_connections->from_nat_prev = ci;
7342 }
7343 mapping_nat_from->from_nat_connections = ci;
7344
7345 /*
7346 * Add this connection into the TO NAT mapping
7347 */
7348 ci->to_nat_prev = NULL;
7349 ci->to_nat_next = mapping_nat_to->to_nat_connections;
7350 if (mapping_nat_to->to_nat_connections) {
7351 mapping_nat_to->to_nat_connections->to_nat_prev = ci;
7352 }
7353 mapping_nat_to->to_nat_connections = ci;
7354
7355 /*
7356 * Add this connection into the FROM iface list of connections
7357 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
7358 * due to the heirarchy of dependencies being kept by the database.
7359 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007360 iface_from = from_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007361 ci->iface_from_prev = NULL;
7362 ci->iface_from_next = iface_from->from_connections;
7363 if (iface_from->from_connections) {
7364 iface_from->from_connections->iface_from_prev = ci;
7365 }
7366 iface_from->from_connections = ci;
7367
7368 /*
7369 * Add this connection into the TO iface list of connections
7370 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
7371 * due to the heirarchy of dependencies being kept by the database.
7372 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007373 iface_to = to_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007374 ci->iface_to_prev = NULL;
7375 ci->iface_to_next = iface_to->to_connections;
7376 if (iface_to->to_connections) {
7377 iface_to->to_connections->iface_to_prev = ci;
7378 }
7379 iface_to->to_connections = ci;
7380
7381 /*
7382 * Add this connection into the FROM NAT iface list of connections
7383 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
7384 * due to the heirarchy of dependencies being kept by the database.
7385 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007386 iface_nat_from = from_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007387 ci->iface_from_nat_prev = NULL;
7388 ci->iface_from_nat_next = iface_nat_from->from_nat_connections;
7389 if (iface_nat_from->from_nat_connections) {
7390 iface_nat_from->from_nat_connections->iface_from_nat_prev = ci;
7391 }
7392 iface_nat_from->from_nat_connections = ci;
7393
7394 /*
7395 * Add this connection into the TO NAT iface list of connections
7396 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
7397 * due to the heirarchy of dependencies being kept by the database.
7398 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007399 iface_nat_to = to_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007400 ci->iface_to_nat_prev = NULL;
7401 ci->iface_to_nat_next = iface_nat_to->to_nat_connections;
7402 if (iface_nat_to->to_nat_connections) {
7403 iface_nat_to->to_nat_connections->iface_to_nat_prev = ci;
7404 }
7405 iface_nat_to->to_nat_connections = ci;
Gareth Williamsb5903892015-03-20 15:13:07 +00007406#endif
Gareth Williams90f2a282014-08-27 15:56:25 +01007407
Ben Menchaca84f36632014-02-28 20:57:38 +00007408 /*
7409 * NOTE: The interface heirarchy lists are deliberately left empty - these are completed
7410 * by the front end if it is appropriate to do so.
7411 */
7412
7413 /*
7414 * Update the counters in the mapping
7415 */
7416 if (protocol == IPPROTO_UDP) {
7417 mapping_from->udp_from++;
7418 mapping_to->udp_to++;
7419 mapping_nat_from->udp_nat_from++;
7420 mapping_nat_to->udp_nat_to++;
7421 } else if (protocol == IPPROTO_TCP) {
7422 mapping_from->tcp_from++;
7423 mapping_to->tcp_to++;
7424 mapping_nat_from->tcp_nat_from++;
7425 mapping_nat_to->tcp_nat_to++;
7426 }
7427
7428 mapping_from->from++;
7429 mapping_to->to++;
7430 mapping_nat_from->nat_from++;
7431 mapping_nat_to->nat_to++;
7432
7433 /*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05307434 * Set the generation number to match global
Ben Menchaca84f36632014-02-28 20:57:38 +00007435 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05307436 ci->generation = ecm_db_connection_generation;
Ben Menchaca84f36632014-02-28 20:57:38 +00007437
7438 spin_unlock_bh(&ecm_db_lock);
7439
7440 /*
7441 * Throw add event to the listeners
7442 */
7443 DEBUG_TRACE("%p: Throw connection added event\n", ci);
7444 li = ecm_db_listeners_get_and_ref_first();
7445 while (li) {
7446 struct ecm_db_listener_instance *lin;
7447 if (li->connection_added) {
7448 li->connection_added(li->arg, ci);
7449 }
7450
7451 /*
7452 * Get next listener
7453 */
7454 lin = ecm_db_listener_get_and_ref_next(li);
7455 ecm_db_listener_deref(li);
7456 li = lin;
7457 }
7458
7459 /*
7460 * Set timer group. 'ref' the connection to ensure it persists for the timer.
7461 */
7462 ecm_db_connection_ref(ci);
7463 ecm_db_timer_group_entry_set(&ci->defunct_timer, tg);
7464}
7465EXPORT_SYMBOL(ecm_db_connection_add);
7466
7467/*
7468 * ecm_db_mapping_add()
7469 * Add a mapping instance into the database
7470 *
7471 * NOTE: The mapping will take a reference to the host instance.
7472 */
7473void ecm_db_mapping_add(struct ecm_db_mapping_instance *mi, struct ecm_db_host_instance *hi, int port,
7474 ecm_db_mapping_final_callback_t final, void *arg)
7475{
7476 ecm_db_mapping_hash_t hash_index;
7477 struct ecm_db_listener_instance *li;
7478
7479 spin_lock_bh(&ecm_db_lock);
7480 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
7481 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007482 DEBUG_ASSERT(!(mi->flags & ECM_DB_MAPPING_FLAGS_INSERTED), "%p: inserted\n", mi);
7483 DEBUG_ASSERT((hi->flags & ECM_DB_HOST_FLAGS_INSERTED), "%p: not inserted\n", hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00007484 DEBUG_ASSERT(!mi->tcp_from && !mi->tcp_to && !mi->udp_from && !mi->udp_to, "%p: protocol count errors\n", mi);
7485#ifdef ECM_DB_XREF_ENABLE
7486 DEBUG_ASSERT(mi->from_connections == NULL, "%p: connections not null\n", mi);
7487 DEBUG_ASSERT(mi->to_connections == NULL, "%p: connections not null\n", mi);
7488 DEBUG_ASSERT(!mi->from && !mi->to && !mi->nat_from && !mi->nat_to, "%p: connection count errors\n", mi);
7489#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007490 spin_unlock_bh(&ecm_db_lock);
7491
7492 mi->arg = arg;
7493 mi->final = final;
7494
7495 /*
7496 * Compute hash table position for insertion
7497 */
7498 hash_index = ecm_db_mapping_generate_hash_index(hi->address, port);
7499 mi->hash_index = hash_index;
7500
7501 /*
7502 * Record port
7503 */
7504 mi->port = port;
7505
7506 /*
7507 * Mapping takes a ref to the host
7508 */
7509 ecm_db_host_ref(hi);
7510 mi->host = hi;
7511
7512 /*
7513 * Set time
7514 */
7515 spin_lock_bh(&ecm_db_lock);
7516 mi->time_added = ecm_db_time;
7517
7518 /*
7519 * Record the mapping is inserted
7520 */
7521 mi->flags |= ECM_DB_MAPPING_FLAGS_INSERTED;
7522
7523 /*
7524 * Add into the global list
7525 */
7526 mi->prev = NULL;
7527 mi->next = ecm_db_mappings;
7528 if (ecm_db_mappings) {
7529 ecm_db_mappings->prev = mi;
7530 }
7531 ecm_db_mappings = mi;
7532
7533 /*
7534 * Insert mapping into the mappings hash table
7535 */
7536 mi->hash_next = ecm_db_mapping_table[hash_index];
7537 if (ecm_db_mapping_table[hash_index]) {
7538 ecm_db_mapping_table[hash_index]->hash_prev = mi;
7539 }
7540 ecm_db_mapping_table[hash_index] = mi;
7541 ecm_db_mapping_table_lengths[hash_index]++;
7542 DEBUG_ASSERT(ecm_db_mapping_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", hi, ecm_db_mapping_table_lengths[hash_index]);
7543
Gareth Williamsb5903892015-03-20 15:13:07 +00007544#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007545 /*
7546 * Insert mapping into the host mapping list
7547 */
7548 mi->mapping_prev = NULL;
7549 mi->mapping_next = hi->mappings;
7550 if (hi->mappings) {
7551 hi->mappings->mapping_prev = mi;
7552 }
7553 hi->mappings = mi;
7554 hi->mapping_count++;
Gareth Williamsb5903892015-03-20 15:13:07 +00007555#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007556 spin_unlock_bh(&ecm_db_lock);
7557
7558 /*
7559 * Throw add event to the listeners
7560 */
7561 DEBUG_TRACE("%p: Throw mapping added event\n", mi);
7562 li = ecm_db_listeners_get_and_ref_first();
7563 while (li) {
7564 struct ecm_db_listener_instance *lin;
7565 if (li->mapping_added) {
7566 li->mapping_added(li->arg, mi);
7567 }
7568
7569 /*
7570 * Get next listener
7571 */
7572 lin = ecm_db_listener_get_and_ref_next(li);
7573 ecm_db_listener_deref(li);
7574 li = lin;
7575 }
7576}
7577EXPORT_SYMBOL(ecm_db_mapping_add);
7578
7579/*
7580 * ecm_db_host_add()
7581 * Add a host instance into the database
7582 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007583void 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 +00007584{
7585 ecm_db_host_hash_t hash_index;
7586 struct ecm_db_listener_instance *li;
7587
7588 spin_lock_bh(&ecm_db_lock);
7589 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007590 DEBUG_ASSERT(!(hi->flags & ECM_DB_HOST_FLAGS_INSERTED), "%p: inserted\n", hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00007591#ifdef ECM_DB_XREF_ENABLE
7592 DEBUG_ASSERT((hi->mappings == NULL) && (hi->mapping_count == 0), "%p: mappings not null\n", hi);
7593#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007594 spin_unlock_bh(&ecm_db_lock);
7595
7596 hi->arg = arg;
7597 hi->final = final;
7598 ECM_IP_ADDR_COPY(hi->address, address);
7599 hi->on_link = on_link;
7600
7601 /*
7602 * Compute hash index into which host will be added
7603 */
7604 hash_index = ecm_db_host_generate_hash_index(address);
7605 hi->hash_index = hash_index;
7606
7607 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00007608 * Add into the global list
7609 */
7610 spin_lock_bh(&ecm_db_lock);
7611 hi->flags |= ECM_DB_HOST_FLAGS_INSERTED;
7612 hi->prev = NULL;
7613 hi->next = ecm_db_hosts;
7614 if (ecm_db_hosts) {
7615 ecm_db_hosts->prev = hi;
7616 }
7617 ecm_db_hosts = hi;
7618
7619 /*
7620 * Add host into the hash table
7621 */
7622 hi->hash_next = ecm_db_host_table[hash_index];
7623 if (ecm_db_host_table[hash_index]) {
7624 ecm_db_host_table[hash_index]->hash_prev = hi;
7625 }
7626 ecm_db_host_table[hash_index] = hi;
7627 ecm_db_host_table_lengths[hash_index]++;
7628 DEBUG_ASSERT(ecm_db_host_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", hi, ecm_db_host_table_lengths[hash_index]);
7629
7630 /*
7631 * Set time of add
7632 */
7633 hi->time_added = ecm_db_time;
Ben Menchaca84f36632014-02-28 20:57:38 +00007634 spin_unlock_bh(&ecm_db_lock);
7635
7636 /*
7637 * Throw add event to the listeners
7638 */
7639 DEBUG_TRACE("%p: Throw host added event\n", hi);
7640 li = ecm_db_listeners_get_and_ref_first();
7641 while (li) {
7642 struct ecm_db_listener_instance *lin;
7643 if (li->host_added) {
7644 li->host_added(li->arg, hi);
7645 }
7646
7647 /*
7648 * Get next listener
7649 */
7650 lin = ecm_db_listener_get_and_ref_next(li);
7651 ecm_db_listener_deref(li);
7652 li = lin;
7653 }
7654}
7655EXPORT_SYMBOL(ecm_db_host_add);
7656
7657/*
7658 * ecm_db_node_add()
7659 * Add a node instance into the database
7660 */
7661void ecm_db_node_add(struct ecm_db_node_instance *ni, struct ecm_db_iface_instance *ii, uint8_t *address,
7662 ecm_db_node_final_callback_t final, void *arg)
7663{
7664 ecm_db_node_hash_t hash_index;
7665 struct ecm_db_listener_instance *li;
7666
7667 spin_lock_bh(&ecm_db_lock);
7668 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
7669 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7670 DEBUG_ASSERT(address, "%p: address null\n", ni);
Gareth Williamsb5903892015-03-20 15:13:07 +00007671 DEBUG_ASSERT((ni->iface == NULL), "%p: iface not null\n", ni);
7672 DEBUG_ASSERT(!(ni->flags & ECM_DB_NODE_FLAGS_INSERTED), "%p: inserted\n", ni);
7673#ifdef ECM_DB_XREF_ENABLE
Gareth Williams90f2a282014-08-27 15:56:25 +01007674 DEBUG_ASSERT((ni->from_connections == NULL) && (ni->from_connections_count == 0), "%p: from_connections not null\n", ni);
7675 DEBUG_ASSERT((ni->to_connections == NULL) && (ni->to_connections_count == 0), "%p: to_connections not null\n", ni);
7676 DEBUG_ASSERT((ni->from_nat_connections == NULL) && (ni->from_nat_connections_count == 0), "%p: from_nat_connections not null\n", ni);
7677 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 +00007678#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007679 spin_unlock_bh(&ecm_db_lock);
7680
7681 memcpy(ni->address, address, ETH_ALEN);
7682 ni->arg = arg;
7683 ni->final = final;
7684
7685 /*
7686 * Compute hash chain for insertion
7687 */
7688 hash_index = ecm_db_node_generate_hash_index(address);
7689 ni->hash_index = hash_index;
7690
7691 /*
7692 * Node takes a ref to the iface
7693 */
7694 ecm_db_iface_ref(ii);
7695 ni->iface = ii;
7696
7697 /*
7698 * Add into the global list
7699 */
7700 spin_lock_bh(&ecm_db_lock);
7701 ni->flags |= ECM_DB_NODE_FLAGS_INSERTED;
7702 ni->prev = NULL;
7703 ni->next = ecm_db_nodes;
7704 if (ecm_db_nodes) {
7705 ecm_db_nodes->prev = ni;
7706 }
7707 ecm_db_nodes = ni;
7708
7709 /*
7710 * Insert into the hash chain
7711 */
7712 ni->hash_next = ecm_db_node_table[hash_index];
7713 if (ecm_db_node_table[hash_index]) {
7714 ecm_db_node_table[hash_index]->hash_prev = ni;
7715 }
7716 ecm_db_node_table[hash_index] = ni;
7717 ecm_db_node_table_lengths[hash_index]++;
7718 DEBUG_ASSERT(ecm_db_node_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ni, ecm_db_node_table_lengths[hash_index]);
7719
7720 /*
7721 * Set time of add
7722 */
7723 ni->time_added = ecm_db_time;
7724
Gareth Williamsb5903892015-03-20 15:13:07 +00007725#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007726 /*
7727 * Insert node into the iface nodes list
7728 */
7729 ni->node_prev = NULL;
7730 ni->node_next = ii->nodes;
7731 if (ii->nodes) {
7732 ii->nodes->node_prev = ni;
7733 }
7734 ii->nodes = ni;
7735 ii->node_count++;
Gareth Williamsb5903892015-03-20 15:13:07 +00007736#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007737 spin_unlock_bh(&ecm_db_lock);
7738
7739 /*
7740 * Throw add event to the listeners
7741 */
7742 DEBUG_TRACE("%p: Throw node added event\n", ni);
7743 li = ecm_db_listeners_get_and_ref_first();
7744 while (li) {
7745 struct ecm_db_listener_instance *lin;
7746 if (li->node_added) {
7747 li->node_added(li->arg, ni);
7748 }
7749
7750 /*
7751 * Get next listener
7752 */
7753 lin = ecm_db_listener_get_and_ref_next(li);
7754 ecm_db_listener_deref(li);
7755 li = lin;
7756 }
7757}
7758EXPORT_SYMBOL(ecm_db_node_add);
7759
Gareth Williamsd5618a82015-05-20 11:13:32 +01007760/*
7761 * ecm_db_adv_stats_state_write()
7762 * Write out advanced stats state
7763 */
7764static int ecm_db_adv_stats_state_write(struct ecm_state_file_instance *sfi,uint64_t from_data_total, uint64_t to_data_total,
7765 uint64_t from_packet_total, uint64_t to_packet_total, uint64_t from_data_total_dropped,
7766 uint64_t to_data_total_dropped, uint64_t from_packet_total_dropped, uint64_t to_packet_total_dropped)
7767{
7768 int result;
7769
7770 if ((result = ecm_state_prefix_add(sfi, "adv_stats"))) {
7771 return result;
7772 }
7773
7774 if ((result = ecm_state_write(sfi, "from_data_total", "%llu", from_data_total))) {
7775 return result;
7776 }
7777 if ((result = ecm_state_write(sfi, "to_data_total", "%llu", to_data_total))) {
7778 return result;
7779 }
7780 if ((result = ecm_state_write(sfi, "from_packet_total", "%llu", from_packet_total))) {
7781 return result;
7782 }
7783 if ((result = ecm_state_write(sfi, "to_packet_total", "%llu", to_packet_total))) {
7784 return result;
7785 }
7786 if ((result = ecm_state_write(sfi, "from_data_total_dropped", "%llu", from_data_total_dropped))) {
7787 return result;
7788 }
7789 if ((result = ecm_state_write(sfi, "to_data_total_dropped", "%llu", to_data_total_dropped))) {
7790 return result;
7791 }
7792 if ((result = ecm_state_write(sfi, "from_packet_total_dropped", "%llu", from_packet_total_dropped))) {
7793 return result;
7794 }
7795 if ((result = ecm_state_write(sfi, "to_packet_total_dropped", "%llu", to_packet_total_dropped))) {
7796 return result;
7797 }
7798
7799 return ecm_state_prefix_remove(sfi);
7800}
7801
Gareth Williamsf98d4192015-03-11 16:55:41 +00007802#ifdef ECM_STATE_OUTPUT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007803/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007804 * ecm_db_iface_state_get_base()
7805 * Get the basic state for an interface object
Ben Menchaca84f36632014-02-28 20:57:38 +00007806 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007807static 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 +00007808{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007809 int result;
Gareth Williamsb5903892015-03-20 15:13:07 +00007810#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007811 int node_count;
Gareth Williamsb5903892015-03-20 15:13:07 +00007812#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007813 uint32_t time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00007814 int32_t interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07007815 int32_t ae_interface_identifier;
Gareth Williams85331c92015-03-11 20:39:18 +00007816 char name[IFNAMSIZ];
7817 int32_t mtu;
7818 ecm_db_iface_type_t type;
7819#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007820 uint64_t from_data_total;
7821 uint64_t to_data_total;
7822 uint64_t from_packet_total;
7823 uint64_t to_packet_total;
7824 uint64_t from_data_total_dropped;
7825 uint64_t to_data_total_dropped;
7826 uint64_t from_packet_total_dropped;
7827 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00007828#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007829
7830 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7831 DEBUG_TRACE("%p: Open iface msg\n", ii);
7832
Gareth Williamsd5618a82015-05-20 11:13:32 +01007833 if ((result = ecm_state_prefix_add(sfi, "iface"))) {
7834 return result;
7835 }
7836
Gareth Williamsb5903892015-03-20 15:13:07 +00007837#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007838 node_count = ecm_db_iface_node_count_get(ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00007839#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007840 time_added = ii->time_added;
Ben Menchaca84f36632014-02-28 20:57:38 +00007841 type = ii->type;
Gareth Williamsd5618a82015-05-20 11:13:32 +01007842 interface_identifier = ii->interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07007843 ae_interface_identifier = ii->ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +00007844 spin_lock_bh(&ecm_db_lock);
7845 strcpy(name, ii->name);
7846 mtu = ii->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00007847 spin_unlock_bh(&ecm_db_lock);
7848
Gareth Williams85331c92015-03-11 20:39:18 +00007849#ifdef ECM_DB_ADVANCED_STATS_ENABLE
7850 ecm_db_iface_data_stats_get(ii, &from_data_total, &to_data_total,
7851 &from_packet_total, &to_packet_total,
7852 &from_data_total_dropped, &to_data_total_dropped,
7853 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williamsd5618a82015-05-20 11:13:32 +01007854
7855 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
7856 from_packet_total, to_packet_total, from_data_total_dropped,
7857 to_data_total_dropped, from_packet_total_dropped,
7858 to_packet_total_dropped))) {
7859 return result;
7860 }
Gareth Williams85331c92015-03-11 20:39:18 +00007861#endif
7862
Gareth Williamsd5618a82015-05-20 11:13:32 +01007863 if ((result = ecm_state_write(sfi, "type", "%d", type))) {
7864 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007865 }
7866
Gareth Williamsd5618a82015-05-20 11:13:32 +01007867 if ((result = ecm_state_write(sfi, "name", "%s", name))) {
7868 return result;
7869 }
7870
7871 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
7872 return result;
7873 }
7874
7875 if ((result = ecm_state_write(sfi, "mtu", "%d", mtu))) {
7876 return result;
7877 }
7878
7879 if ((result = ecm_state_write(sfi, "interface_identifier", "%d", interface_identifier))) {
7880 return result;
7881 }
7882
Murat Sezgin91c5d712015-06-12 15:16:22 -07007883 if ((result = ecm_state_write(sfi, "ae_interface_identifier", "%d", ae_interface_identifier))) {
Gareth Williamsd5618a82015-05-20 11:13:32 +01007884 return result;
7885 }
7886
7887#ifdef ECM_DB_XREF_ENABLE
7888 if ((result = ecm_state_write(sfi, "nodes", "%d", node_count))) {
7889 return result;
7890 }
7891#endif
7892
7893 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007894}
7895
7896/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007897 * ecm_db_iface_ethernet_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007898 * Return interface type specific state
7899 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007900static 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 +00007901{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007902 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007903 uint8_t address[ETH_ALEN];
7904
7905 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7906 spin_lock_bh(&ecm_db_lock);
7907 memcpy(address, ii->type_info.ethernet.address, ETH_ALEN);
7908 spin_unlock_bh(&ecm_db_lock);
7909
Gareth Williamsd5618a82015-05-20 11:13:32 +01007910 if ((result = ecm_state_prefix_add(sfi, "ethernet"))) {
7911 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007912 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007913
Gareth Williamsd5618a82015-05-20 11:13:32 +01007914 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7915 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007916 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007917
Gareth Williamsd5618a82015-05-20 11:13:32 +01007918 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
7919 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007920 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007921
7922 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007923}
7924
Murat Sezgin910c9662015-03-11 16:15:06 -07007925#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007926/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007927 * ecm_db_iface_lag_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007928 * Return interface type specific state
7929 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007930static 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 +00007931{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007932 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007933 uint8_t address[ETH_ALEN];
7934
7935 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7936 spin_lock_bh(&ecm_db_lock);
7937 memcpy(address, ii->type_info.lag.address, ETH_ALEN);
7938 spin_unlock_bh(&ecm_db_lock);
7939
Gareth Williamsd5618a82015-05-20 11:13:32 +01007940 if ((result = ecm_state_prefix_add(sfi, "lag"))) {
7941 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007942 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007943 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7944 return result;
7945 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007946
Gareth Williamsd5618a82015-05-20 11:13:32 +01007947 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
7948 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007949 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007950
Gareth Williamsd5618a82015-05-20 11:13:32 +01007951 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007952}
Murat Sezgin910c9662015-03-11 16:15:06 -07007953#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007954
7955/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007956 * ecm_db_iface_bridge_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007957 * Return interface type specific state
7958 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007959static 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 +00007960{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007961 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007962 uint8_t address[ETH_ALEN];
7963
7964 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7965 spin_lock_bh(&ecm_db_lock);
7966 memcpy(address, ii->type_info.bridge.address, ETH_ALEN);
7967 spin_unlock_bh(&ecm_db_lock);
7968
Gareth Williamsd5618a82015-05-20 11:13:32 +01007969 if ((result = ecm_state_prefix_add(sfi, "bridge"))) {
7970 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007971 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007972 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7973 return result;
7974 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007975
Gareth Williamsd5618a82015-05-20 11:13:32 +01007976 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
7977 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007978 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007979
Gareth Williamsd5618a82015-05-20 11:13:32 +01007980 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007981}
7982
Murat Sezgin37fb3952015-03-10 16:45:13 -07007983#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007984/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007985 * ecm_db_iface_vlan_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007986 * Return interface type specific state
7987 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007988static 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 +00007989{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007990 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007991 uint8_t address[ETH_ALEN];
7992 uint16_t vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307993 uint16_t vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00007994
7995 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7996 spin_lock_bh(&ecm_db_lock);
7997 memcpy(address, ii->type_info.vlan.address, ETH_ALEN);
7998 vlan_tag = ii->type_info.vlan.vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307999 vlan_tpid = ii->type_info.vlan.vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00008000 spin_unlock_bh(&ecm_db_lock);
8001
Gareth Williamsd5618a82015-05-20 11:13:32 +01008002 if ((result = ecm_state_prefix_add(sfi, "vlan"))) {
8003 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008004 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008005 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
8006 return result;
8007 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008008
Gareth Williamsd5618a82015-05-20 11:13:32 +01008009 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
8010 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008011 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008012 if ((result = ecm_state_write(sfi, "tag", "%x", vlan_tag))) {
8013 return result;
8014 }
8015 if ((result = ecm_state_write(sfi, "tpid", "%x", vlan_tpid))) {
8016 return result;
8017 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008018
Gareth Williamsd5618a82015-05-20 11:13:32 +01008019 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00008020}
Murat Sezgin37fb3952015-03-10 16:45:13 -07008021#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00008022
ratheesh kannotha32fdd12015-09-09 08:02:58 +05308023#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00008024/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008025 * ecm_db_iface_pppoe_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00008026 * Return interface type specific state
8027 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008028static 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 +00008029{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008030 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008031 uint16_t pppoe_session_id;
8032 uint8_t remote_mac[ETH_ALEN];
8033
8034 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8035 spin_lock_bh(&ecm_db_lock);
8036 pppoe_session_id = ii->type_info.pppoe.pppoe_session_id;
8037 memcpy(remote_mac, ii->type_info.pppoe.remote_mac, ETH_ALEN);
8038 spin_unlock_bh(&ecm_db_lock);
8039
Gareth Williamsd5618a82015-05-20 11:13:32 +01008040 if ((result = ecm_state_prefix_add(sfi, "pppoe"))) {
8041 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008042 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008043 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
8044 return result;
8045 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008046
Gareth Williamsd5618a82015-05-20 11:13:32 +01008047 if ((result = ecm_state_write(sfi, "remote_max", "%pM", remote_mac))) {
8048 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008049 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008050 if ((result = ecm_state_write(sfi, "session_id", "%u", pppoe_session_id))) {
8051 return result;
8052 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008053
Gareth Williamsd5618a82015-05-20 11:13:32 +01008054 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00008055}
Murat Sezginaad635c2015-03-06 16:11:41 -08008056#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00008057
ratheesh kannothcfdcb332015-12-24 07:19:18 +05308058#ifdef ECM_INTERFACE_MAP_T_ENABLE
8059/*
8060 * ecm_db_iface_map_t_state_get()
8061 * Return interface type specific state
8062 */
8063static int ecm_db_iface_map_t_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
8064{
8065 int result;
8066 int32_t if_index;
8067
8068 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8069 spin_lock_bh(&ecm_db_lock);
8070 if_index = ii->type_info.map_t.if_index;
8071 spin_unlock_bh(&ecm_db_lock);
8072
8073 if ((result = ecm_state_prefix_add(sfi, "map_t"))) {
8074 return result;
8075 }
8076 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
8077 return result;
8078 }
8079
8080 if ((result = ecm_state_write(sfi, "if_index", "%d", if_index))) {
8081 return result;
8082 }
8083
8084 return ecm_state_prefix_remove(sfi);
8085}
8086#endif
8087
ratheesh kannotha32fdd12015-09-09 08:02:58 +05308088#ifdef ECM_INTERFACE_L2TPV2_ENABLE
8089
8090/*
8091 * ecm_db_iface_pppol2tpv2_state_get()
8092 * Return interface type specific state
8093 */
8094static int ecm_db_iface_pppol2tpv2_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
8095{
8096 int result;
8097 struct ecm_db_interface_info_pppol2tpv2 type_info;
8098
8099 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8100 spin_lock_bh(&ecm_db_lock);
8101 memcpy(&type_info, &ii->type_info, sizeof(struct ecm_db_interface_info_pppol2tpv2));
8102 spin_unlock_bh(&ecm_db_lock);
8103
8104 if ((result = ecm_state_prefix_add(sfi, "pppol2tpv2"))) {
8105 return result;
8106 }
8107
8108 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
8109 return result;
8110 }
8111
8112 if ((result = ecm_state_write(sfi, "local_tunnel_id", "%u", type_info.l2tp.tunnel.tunnel_id))) {
8113 return result;
8114 }
8115
8116 if ((result = ecm_state_write(sfi, "local_session_id", "%u", type_info.l2tp.session.session_id))) {
8117 return result;
8118 }
8119
8120 if ((result = ecm_state_write(sfi, "peer_tunnnel_id", "%u", type_info.l2tp.tunnel.peer_tunnel_id))) {
8121 return result;
8122 }
8123
8124 if ((result = ecm_state_write(sfi, "peer_session_id", "%u", type_info.l2tp.session.peer_session_id))) {
8125 return result;
8126 }
8127
8128 return ecm_state_prefix_remove(sfi);
8129}
8130
8131#endif
8132
Shyam Sunder23f2e542015-09-28 14:56:49 +05308133#ifdef ECM_INTERFACE_PPTP_ENABLE
8134/*
8135 * ecm_db_iface_pptp_state_get()
8136 * Return interface type specific state
8137 */
8138static int ecm_db_iface_pptp_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
8139{
8140 int result;
8141 struct ecm_db_interface_info_pptp type_info;
8142
8143 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8144 spin_lock_bh(&ecm_db_lock);
8145 memcpy(&type_info, &ii->type_info, sizeof(struct ecm_db_interface_info_pptp));
8146 spin_unlock_bh(&ecm_db_lock);
8147
8148 result = ecm_state_prefix_add(sfi, "pptp");
8149 if (result) {
8150 return result;
8151 }
8152
8153 result = ecm_db_iface_state_get_base(ii, sfi);
8154 if (result) {
8155 return result;
8156 }
8157
8158 result = ecm_state_write(sfi, "local_call_id", "%u", type_info.src_call_id);
8159 if (result) {
8160 return result;
8161 }
8162
8163 result = ecm_state_write(sfi, "peer_call_id", "%u", type_info.dst_call_id);
8164 if (result) {
8165 return result;
8166 }
8167
8168 return ecm_state_prefix_remove(sfi);
8169}
8170#endif
8171
Ben Menchaca84f36632014-02-28 20:57:38 +00008172/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008173 * ecm_db_iface_unknown_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00008174 * Return interface type specific state
8175 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008176static 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 +00008177{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008178 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008179 uint32_t os_specific_ident;
8180
8181 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8182 spin_lock_bh(&ecm_db_lock);
8183 os_specific_ident = ii->type_info.unknown.os_specific_ident;
8184 spin_unlock_bh(&ecm_db_lock);
8185
Gareth Williamsd5618a82015-05-20 11:13:32 +01008186 if ((result = ecm_state_prefix_add(sfi, "pppoe"))) {
8187 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008188 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008189 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
8190 return result;
8191 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008192
Gareth Williamsd5618a82015-05-20 11:13:32 +01008193 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
8194 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008195 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008196
Gareth Williamsd5618a82015-05-20 11:13:32 +01008197 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00008198}
8199
8200/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008201 * ecm_db_iface_loopback_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00008202 * Return interface type specific state
8203 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008204static 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 +00008205{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008206 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008207 uint32_t os_specific_ident;
8208
8209 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8210 spin_lock_bh(&ecm_db_lock);
8211 os_specific_ident = ii->type_info.loopback.os_specific_ident;
8212 spin_unlock_bh(&ecm_db_lock);
8213
Gareth Williamsd5618a82015-05-20 11:13:32 +01008214 if ((result = ecm_state_prefix_add(sfi, "loopback"))) {
8215 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008216 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008217 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
8218 return result;
8219 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008220
Gareth Williamsd5618a82015-05-20 11:13:32 +01008221 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
8222 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008223 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008224
Gareth Williamsd5618a82015-05-20 11:13:32 +01008225 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00008226}
8227
Murat Sezgin69a27532015-03-12 14:09:40 -07008228#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00008229/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008230 * ecm_db_iface_ipsec_tunnel_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00008231 * Return interface type specific state
8232 *
8233 * GGG TODO Output state on ipsec tunnel specific data
8234 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008235static 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 +00008236{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008237 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008238 uint32_t os_specific_ident;
8239
8240 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8241 spin_lock_bh(&ecm_db_lock);
8242 os_specific_ident = ii->type_info.ipsec_tunnel.os_specific_ident;
8243 spin_unlock_bh(&ecm_db_lock);
8244
Gareth Williamsd5618a82015-05-20 11:13:32 +01008245 if ((result = ecm_state_prefix_add(sfi, "ipsec"))) {
8246 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008247 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008248 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
8249 return result;
8250 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008251
Gareth Williamsd5618a82015-05-20 11:13:32 +01008252 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
8253 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00008254 }
Ben Menchaca84f36632014-02-28 20:57:38 +00008255
Gareth Williamsd5618a82015-05-20 11:13:32 +01008256 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00008257}
Murat Sezgin69a27532015-03-12 14:09:40 -07008258#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00008259
Gareth Williamsf98d4192015-03-11 16:55:41 +00008260#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +00008261#ifdef ECM_IPV6_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008262/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008263 * ecm_db_iface_tunipip6_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008264 * Return interface type specific state
8265 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008266static 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 +00008267{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008268 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008269 uint32_t os_specific_ident;
8270
8271 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8272 spin_lock_bh(&ecm_db_lock);
8273 os_specific_ident = ii->type_info.ipsec_tunnel.os_specific_ident;
8274 spin_unlock_bh(&ecm_db_lock);
8275
Gareth Williamsd5618a82015-05-20 11:13:32 +01008276 if ((result = ecm_state_prefix_add(sfi, "tunipip6"))) {
8277 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008278 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008279 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
8280 return result;
8281 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008282
Gareth Williamsd5618a82015-05-20 11:13:32 +01008283 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
8284 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008285 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008286
Gareth Williamsd5618a82015-05-20 11:13:32 +01008287 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008288}
8289#endif
Gareth Williams8ac34292015-03-17 14:06:58 +00008290#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008291
8292#ifdef ECM_INTERFACE_SIT_ENABLE
8293/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008294 * ecm_db_iface_sit_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008295 * Return interface type specific state
8296 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008297static 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 +00008298{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008299 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008300 uint32_t os_specific_ident;
8301
8302 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8303 spin_lock_bh(&ecm_db_lock);
8304 os_specific_ident = ii->type_info.ipsec_tunnel.os_specific_ident;
8305 spin_unlock_bh(&ecm_db_lock);
8306
Gareth Williamsd5618a82015-05-20 11:13:32 +01008307 if ((result = ecm_state_prefix_add(sfi, "sit"))) {
8308 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008309 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008310 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
8311 return result;
8312 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008313
Gareth Williamsd5618a82015-05-20 11:13:32 +01008314 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
8315 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008316 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008317
Gareth Williamsd5618a82015-05-20 11:13:32 +01008318 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008319}
8320#endif
8321
8322/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008323 * ecm_db_iface_state_get()
8324 * Obtain state for the interface.
Gareth Williamsf98d4192015-03-11 16:55:41 +00008325 *
8326 * State specific to the interface type will be returned.
8327 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008328int ecm_db_iface_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_iface_instance *ii)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008329{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008330 int result;
8331
Gareth Williamsf98d4192015-03-11 16:55:41 +00008332 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008333
8334 if ((result = ecm_state_prefix_add(sfi, "iface"))) {
8335 return result;
8336 }
8337
8338 if ((result = ii->state_get(ii, sfi))) {
8339 return result;
8340 }
8341
8342 return ecm_state_prefix_remove(sfi);
8343
Gareth Williamsf98d4192015-03-11 16:55:41 +00008344}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008345EXPORT_SYMBOL(ecm_db_iface_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008346
8347/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008348 * ecm_db_connection_heirarchy_state_get()
8349 * Output state for an interface heirarchy list.
Gareth Williamsf98d4192015-03-11 16:55:41 +00008350 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008351static 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 +00008352{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008353 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008354 int count;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008355 int i;
Gareth Williamsd5618a82015-05-20 11:13:32 +01008356 int j;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008357
Gareth Williamsd5618a82015-05-20 11:13:32 +01008358 count = ECM_DB_IFACE_HEIRARCHY_MAX - first_interface;
8359 if ((result = ecm_state_write(sfi, "interface_count", "%d", count))) {
8360 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008361 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008362
8363 /*
8364 * Iterate the interface heirarchy list and output the information
8365 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008366 for (i = first_interface, j = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i, ++j) {
Gareth Williamsf98d4192015-03-11 16:55:41 +00008367 struct ecm_db_iface_instance *ii = interfaces[i];
Gareth Williamsd5618a82015-05-20 11:13:32 +01008368 DEBUG_TRACE("Output interface @ %d: %p\n", i, ii);
8369
8370 if ((result = ecm_state_prefix_index_add(sfi, j))) {
8371 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008372 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008373 result = ii->state_get(ii, sfi);
8374 if (result) {
8375 return result;
8376 }
8377 if ((result = ecm_state_prefix_remove(sfi))) {
8378 return result;
8379 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008380 }
8381
Gareth Williamsd5618a82015-05-20 11:13:32 +01008382 return 0;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008383}
8384
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308385#ifdef ECM_MULTICAST_ENABLE
8386/*
8387 * ecm_db_multicast_to_interfaces_xml_state_get()
8388 * Obtain XML state for the multicast destination interfaces list
8389 */
8390static int ecm_db_multicast_to_interfaces_xml_state_get(struct ecm_db_connection_instance *ci, struct ecm_state_file_instance *sfi)
8391{
8392 struct ecm_db_iface_instance *mc_ifaces;
8393 struct ecm_db_iface_instance *mc_ifaces_single[ECM_DB_IFACE_HEIRARCHY_MAX];
8394 struct ecm_db_iface_instance *ii_temp;
8395 int32_t *mc_ifaces_first;
8396 int32_t *ifaces_first;
8397 int32_t heirarchy_index;
8398 int ret;
8399
8400 ret = ecm_db_multicast_connection_to_interfaces_get_and_ref_all(ci, &mc_ifaces, &mc_ifaces_first);
8401 if (ret == 0) {
Shyam Sunder3af86a52015-08-28 18:04:10 +05308402 return ret;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308403 }
8404
8405 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
8406
8407 ii_temp = ecm_db_multicast_if_heirarchy_get(mc_ifaces, heirarchy_index);
8408 ecm_db_multicast_copy_if_heirarchy(mc_ifaces_single, ii_temp);
8409 ifaces_first = ecm_db_multicast_if_first_get_at_index(mc_ifaces_first, heirarchy_index);
8410
8411 if (ci->to_mcast_interface_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
8412 ret = ecm_db_connection_heirarchy_state_get(sfi, mc_ifaces_single, *ifaces_first);
8413 if (ret) {
8414 ecm_db_multicast_connection_to_interfaces_deref_all(mc_ifaces, mc_ifaces_first);
8415 return ret;
8416 }
8417
8418 }
8419 }
8420 ecm_db_multicast_connection_to_interfaces_deref_all(mc_ifaces, mc_ifaces_first);
8421
8422 return ret;
8423}
8424#endif
8425
Gareth Williamsf98d4192015-03-11 16:55:41 +00008426/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008427 * ecm_db_connection_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008428 * Prepare a connection message
8429 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008430int ecm_db_connection_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_connection_instance *ci)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008431{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008432 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008433 long int expires_in;
8434 int sport;
8435 int sport_nat;
Murat Sezginf21210e2016-04-04 13:58:20 -07008436 char snode_address[ECM_MAC_ADDR_STR_BUFF_SIZE];
8437 char snode_address_nat[ECM_MAC_ADDR_STR_BUFF_SIZE];
8438 char sip_address[ECM_IP_ADDR_STR_BUFF_SIZE];
8439 char sip_address_nat[ECM_IP_ADDR_STR_BUFF_SIZE];
8440 char dnode_address[ECM_MAC_ADDR_STR_BUFF_SIZE];
8441 char dnode_address_nat[ECM_MAC_ADDR_STR_BUFF_SIZE];
Gareth Williamsf98d4192015-03-11 16:55:41 +00008442 int dport;
8443 int dport_nat;
Murat Sezginf21210e2016-04-04 13:58:20 -07008444 char dip_address[ECM_IP_ADDR_STR_BUFF_SIZE];
8445 char dip_address_nat[ECM_IP_ADDR_STR_BUFF_SIZE];
Gareth Williamsf98d4192015-03-11 16:55:41 +00008446 ecm_db_direction_t direction;
Gareth Williams3e5b37f2015-05-13 10:04:12 +01008447 int ip_version;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008448 int protocol;
8449 bool is_routed;
Tushar Mathurd38cacd2015-07-28 12:19:10 +05308450 uint32_t regen_success;
8451 uint32_t regen_fail;
8452 uint16_t regen_required;
8453 uint16_t regen_occurances;
8454 bool regen_in_progress;
8455 uint16_t generation;
8456 uint16_t global_generation;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008457 uint32_t time_added;
8458 uint32_t serial;
8459 uint64_t from_data_total;
8460 uint64_t to_data_total;
8461 uint64_t from_packet_total;
8462 uint64_t to_packet_total;
8463 uint64_t from_data_total_dropped;
8464 uint64_t to_data_total_dropped;
8465 uint64_t from_packet_total_dropped;
8466 uint64_t to_packet_total_dropped;
8467 struct ecm_db_host_instance *hi;
8468 struct ecm_db_node_instance *ni;
8469 int aci_index;
8470 int aci_count;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308471 ip_addr_t __attribute__((unused)) group_ip;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008472 struct ecm_front_end_connection_instance *feci;
8473 struct ecm_classifier_instance *assignments[ECM_CLASSIFIER_TYPES];
8474 int32_t first_interface;
8475 struct ecm_db_iface_instance *interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
8476
8477 DEBUG_TRACE("Prep conn msg for %p\n", ci);
8478
8479 /*
8480 * Identify expiration
8481 */
8482 spin_lock_bh(&ecm_db_lock);
8483 if (ci->defunct_timer.group == ECM_DB_TIMER_GROUPS_MAX) {
8484 expires_in = -1;
8485 } else {
8486 expires_in = (long int)(ci->defunct_timer.timeout - ecm_db_time);
8487 if (expires_in <= 0) {
8488 expires_in = 0;
8489 }
8490 }
Tushar Mathurd38cacd2015-07-28 12:19:10 +05308491
8492 regen_success = ci->regen_success;
8493 regen_fail = ci->regen_fail;
8494 regen_required = ci->regen_required;
8495 regen_occurances = ci->regen_occurances;
8496 regen_in_progress = ci->regen_in_progress;
8497 generation = ci->generation;
8498 global_generation = ecm_db_connection_generation;
8499
Gareth Williamsf98d4192015-03-11 16:55:41 +00008500 spin_unlock_bh(&ecm_db_lock);
8501
8502 /*
8503 * Extract information from the connection for inclusion into the message
8504 */
8505 sport = ci->mapping_from->port;
8506 sport_nat = ci->mapping_nat_from->port;
8507 dport = ci->mapping_to->port;
8508 dport_nat = ci->mapping_nat_to->port;
8509
8510 hi = ci->mapping_to->host;
8511 ecm_ip_addr_to_string(dip_address, hi->address);
8512 ni = ci->to_node;
Murat Sezginf21210e2016-04-04 13:58:20 -07008513 snprintf(dnode_address, sizeof(dnode_address), "%pM", ni->address);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008514 hi = ci->mapping_nat_to->host;
8515 ecm_ip_addr_to_string(dip_address_nat, hi->address);
8516
8517 hi = ci->mapping_from->host;
8518 ecm_ip_addr_to_string(sip_address, hi->address);
8519 ni = ci->from_node;
Murat Sezginf21210e2016-04-04 13:58:20 -07008520 snprintf(snode_address, sizeof(snode_address), "%pM", ni->address);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008521 hi = ci->mapping_nat_from->host;
8522 ecm_ip_addr_to_string(sip_address_nat, hi->address);
8523
8524 ni = ci->to_nat_node;
Murat Sezginf21210e2016-04-04 13:58:20 -07008525 snprintf(dnode_address_nat, sizeof(dnode_address_nat), "%pM", ni->address);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008526
8527 ni = ci->from_nat_node;
Murat Sezginf21210e2016-04-04 13:58:20 -07008528 snprintf(snode_address_nat, sizeof(snode_address_nat), "%pM", ni->address);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008529
8530 direction = ci->direction;
Gareth Williams3e5b37f2015-05-13 10:04:12 +01008531 ip_version = ci->ip_version;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008532 protocol = ci->protocol;
8533 is_routed = ci->is_routed;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008534 time_added = ci->time_added;
8535 serial = ci->serial;
8536 ecm_db_connection_data_stats_get(ci, &from_data_total, &to_data_total,
8537 &from_packet_total, &to_packet_total,
8538 &from_data_total_dropped, &to_data_total_dropped,
8539 &from_packet_total_dropped, &to_packet_total_dropped);
8540
Gareth Williamsd5618a82015-05-20 11:13:32 +01008541 if ((result = ecm_state_prefix_add(sfi, "conn"))) {
8542 return result;
8543 }
8544 if ((result = ecm_state_prefix_index_add(sfi, serial))) {
8545 return result;
8546 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008547
Gareth Williamsd5618a82015-05-20 11:13:32 +01008548 if ((result = ecm_state_write(sfi, "serial", "%u", serial))) {
8549 return result;
8550 }
8551
8552 if ((result = ecm_state_write(sfi, "sip_address", "%s", sip_address))) {
8553 return result;
8554 }
8555
8556 if ((result = ecm_state_write(sfi, "sip_address_nat", "%s", sip_address_nat))) {
8557 return result;
8558 }
8559
8560 if ((result = ecm_state_write(sfi, "sport", "%d", sport))) {
8561 return result;
8562 }
8563
8564 if ((result = ecm_state_write(sfi, "sport_nat", "%d", sport_nat))) {
8565 return result;
8566 }
8567
8568 if ((result = ecm_state_write(sfi, "snode_address", "%s", snode_address))) {
8569 return result;
8570 }
8571
8572 if ((result = ecm_state_write(sfi, "snode_address_nat", "%s", snode_address_nat))) {
8573 return result;
8574 }
8575
8576 if ((result = ecm_state_write(sfi, "dip_address", "%s", dip_address))) {
8577 return result;
8578 }
8579
8580 if ((result = ecm_state_write(sfi, "dip_address_nat", "%s", dip_address_nat))) {
8581 return result;
8582 }
8583
8584 if ((result = ecm_state_write(sfi, "dport", "%d", dport))) {
8585 return result;
8586 }
8587
8588 if ((result = ecm_state_write(sfi, "dport_nat", "%d", dport_nat))) {
8589 return result;
8590 }
8591
8592 if ((result = ecm_state_write(sfi, "dnode_address", "%s", dnode_address))) {
8593 return result;
8594 }
8595
8596 if ((result = ecm_state_write(sfi, "dnode_address_nat", "%s", dnode_address_nat))) {
8597 return result;
8598 }
8599
Gareth Williams3e5b37f2015-05-13 10:04:12 +01008600 if ((result = ecm_state_write(sfi, "ip_version", "%d", ip_version))) {
8601 return result;
8602 }
8603
Gareth Williamsd5618a82015-05-20 11:13:32 +01008604 if ((result = ecm_state_write(sfi, "protocol", "%d", protocol))) {
8605 return result;
8606 }
8607
8608 if ((result = ecm_state_write(sfi, "is_routed", "%d", is_routed))) {
8609 return result;
8610 }
8611
8612 if ((result = ecm_state_write(sfi, "expires", "%ld", expires_in))) {
8613 return result;
8614 }
8615
8616 if ((result = ecm_state_write(sfi, "direction", "%d", direction))) {
8617 return result;
8618 }
8619
8620 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
8621 return result;
8622 }
8623
Tushar Mathurd38cacd2015-07-28 12:19:10 +05308624 if ((result = ecm_state_write(sfi, "regen_success", "%u", regen_success))) {
8625 return result;
8626 }
8627 if ((result = ecm_state_write(sfi, "regen_fail", "%u", regen_fail))) {
8628 return result;
8629 }
8630 if ((result = ecm_state_write(sfi, "regen_required", "%u", regen_required))) {
8631 return result;
8632 }
8633 if ((result = ecm_state_write(sfi, "regen_occurances", "%u", regen_occurances))) {
8634 return result;
8635 }
8636 if ((result = ecm_state_write(sfi, "regen_in_progress", "%u", regen_in_progress))) {
8637 return result;
8638 }
8639 if ((result = ecm_state_write(sfi, "generation", "%u/%u", generation, global_generation))) {
Gareth Williamsd5618a82015-05-20 11:13:32 +01008640 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008641 }
8642
8643 /*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008644 * NOTE: These advanced stats are not conditional compiled.
8645 * Connections always contain these stats
Gareth Williamsf98d4192015-03-11 16:55:41 +00008646 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008647 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
8648 from_packet_total, to_packet_total, from_data_total_dropped,
8649 to_data_total_dropped, from_packet_total_dropped,
8650 to_packet_total_dropped))) {
8651 return result;
8652 }
8653
8654 if ((result = ecm_state_prefix_add(sfi, "from_interfaces"))) {
8655 return result;
8656 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008657 first_interface = ecm_db_connection_from_interfaces_get_and_ref(ci, interfaces);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008658 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008659 ecm_db_connection_interfaces_deref(interfaces, first_interface);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008660 if (result) {
8661 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008662 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008663 if ((result = ecm_state_prefix_remove(sfi))) {
8664 return result;
8665 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008666
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308667#ifdef ECM_MULTICAST_ENABLE
8668 ecm_db_connection_to_address_get(ci, group_ip);
8669 if (ecm_ip_addr_is_multicast(group_ip)) {
8670 if ((result = ecm_state_prefix_add(sfi, "to_mc_interfaces"))) {
8671 return result;
8672 }
8673
8674 if ((result = ecm_db_multicast_to_interfaces_xml_state_get(ci, sfi))) {
8675 return result;
8676 }
8677
8678 if ((result = ecm_state_prefix_remove(sfi))) {
8679 return result;
8680 }
8681 }
8682 else {
8683 if ((result = ecm_state_prefix_add(sfi, "to_interfaces"))) {
8684 return result;
8685 }
8686
8687 first_interface = ecm_db_connection_to_interfaces_get_and_ref(ci, interfaces);
8688 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
8689 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8690 if (result) {
8691 return result;
8692 }
8693
8694 if ((result = ecm_state_prefix_remove(sfi))) {
8695 return result;
8696 }
8697 }
8698#else
Gareth Williamsd5618a82015-05-20 11:13:32 +01008699 if ((result = ecm_state_prefix_add(sfi, "to_interfaces"))) {
8700 return result;
8701 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008702 first_interface = ecm_db_connection_to_interfaces_get_and_ref(ci, interfaces);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008703 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008704 ecm_db_connection_interfaces_deref(interfaces, first_interface);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008705 if (result) {
8706 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008707 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008708 if ((result = ecm_state_prefix_remove(sfi))) {
8709 return result;
8710 }
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308711#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008712
Gareth Williamsd5618a82015-05-20 11:13:32 +01008713 if ((result = ecm_state_prefix_add(sfi, "from_nat_interfaces"))) {
8714 return result;
8715 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008716 first_interface = ecm_db_connection_from_nat_interfaces_get_and_ref(ci, interfaces);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008717 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008718 ecm_db_connection_interfaces_deref(interfaces, first_interface);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008719 if (result) {
8720 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008721 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008722 if ((result = ecm_state_prefix_remove(sfi))) {
8723 return result;
8724 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008725
Gareth Williamsd5618a82015-05-20 11:13:32 +01008726 if ((result = ecm_state_prefix_add(sfi, "to_nat_interfaces"))) {
8727 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008728 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008729 first_interface = ecm_db_connection_to_nat_interfaces_get_and_ref(ci, interfaces);
8730 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
8731 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8732 if (result) {
8733 return result;
8734 }
8735 if ((result = ecm_state_prefix_remove(sfi))) {
8736 return result;
8737 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008738
8739 /*
8740 * Output front end state
8741 */
8742 feci = ecm_db_connection_front_end_get_and_ref(ci);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008743 result = feci->state_get(feci, sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008744 feci->deref(feci);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008745 if (result) {
8746 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008747 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008748
8749 if ((result = ecm_state_prefix_add(sfi, "classifiers"))) {
8750 return result;
8751 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008752
8753 /*
8754 * Grab references to the assigned classifiers so we can produce state for them
8755 */
8756 aci_count = ecm_db_connection_classifier_assignments_get_and_ref(ci, assignments);
8757
8758 /*
8759 * Iterate the assigned classifiers and provide a state record for each
8760 */
8761 for (aci_index = 0; aci_index < aci_count; ++aci_index) {
8762 struct ecm_classifier_instance *aci;
8763
8764 aci = assignments[aci_index];
Gareth Williamsd5618a82015-05-20 11:13:32 +01008765 result = aci->state_get(aci, sfi);
8766 if (result) {
Gareth Williamsf98d4192015-03-11 16:55:41 +00008767 ecm_db_connection_assignments_release(aci_count, assignments);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008768 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008769 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008770 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008771
Gareth Williamsf98d4192015-03-11 16:55:41 +00008772 ecm_db_connection_assignments_release(aci_count, assignments);
8773
Gareth Williamsd5618a82015-05-20 11:13:32 +01008774 if ((result = ecm_state_prefix_remove(sfi))) {
8775 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008776 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008777
8778 if ((result = ecm_state_prefix_remove(sfi))) {
8779 return result;
8780 }
8781
8782 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008783}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008784EXPORT_SYMBOL(ecm_db_connection_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008785
8786/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008787 * ecm_db_mapping_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008788 * Prepare a mapping message
8789 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008790int ecm_db_mapping_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_mapping_instance *mi)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008791{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008792 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008793 int port;
Murat Sezginf21210e2016-04-04 13:58:20 -07008794 char address[ECM_IP_ADDR_STR_BUFF_SIZE];
Gareth Williamsf98d4192015-03-11 16:55:41 +00008795 int tcp_from;
8796 int tcp_to;
8797 int udp_from;
8798 int udp_to;
8799 int from;
8800 int to;
8801 int tcp_nat_from;
8802 int tcp_nat_to;
8803 int udp_nat_from;
8804 int udp_nat_to;
8805 int nat_from;
8806 int nat_to;
8807 uint32_t time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008808 struct ecm_db_host_instance *hi;
8809#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008810 uint64_t from_data_total;
8811 uint64_t to_data_total;
8812 uint64_t from_packet_total;
8813 uint64_t to_packet_total;
8814 uint64_t from_data_total_dropped;
8815 uint64_t to_data_total_dropped;
8816 uint64_t from_packet_total_dropped;
8817 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00008818#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008819
8820 DEBUG_TRACE("Prep mapping msg for %p\n", mi);
8821
8822 /*
8823 * Create a small xml stats element for our mapping.
8824 * Extract information from the mapping for inclusion into the message
8825 */
8826 ecm_db_mapping_port_count_get(mi, &tcp_from, &tcp_to, &udp_from, &udp_to, &from, &to,
8827 &tcp_nat_from, &tcp_nat_to, &udp_nat_from, &udp_nat_to, &nat_from, &nat_to);
8828 port = mi->port;
8829 time_added = mi->time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008830 hi = mi->host;
8831 ecm_ip_addr_to_string(address, hi->address);
8832
8833#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008834 ecm_db_mapping_data_stats_get(mi, &from_data_total, &to_data_total,
8835 &from_packet_total, &to_packet_total,
8836 &from_data_total_dropped, &to_data_total_dropped,
8837 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williams85331c92015-03-11 20:39:18 +00008838#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008839
Gareth Williamsd5618a82015-05-20 11:13:32 +01008840 if ((result = ecm_state_prefix_add(sfi, "mapping"))) {
8841 return result;
8842 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008843
Gareth Williamsd5618a82015-05-20 11:13:32 +01008844 if ((result = ecm_state_write(sfi, "port", "%d", port))) {
8845 return result;
8846 }
8847
8848 if ((result = ecm_state_write(sfi, "from", "%d", from))) {
8849 return result;
8850 }
8851
8852 if ((result = ecm_state_write(sfi, "to", "%d", to))) {
8853 return result;
8854 }
8855
8856 if ((result = ecm_state_write(sfi, "tcp_from", "%d", tcp_from))) {
8857 return result;
8858 }
8859
8860 if ((result = ecm_state_write(sfi, "tcp_to", "%d", tcp_to))) {
8861 return result;
8862 }
8863
8864 if ((result = ecm_state_write(sfi, "udp_from", "%d", udp_from))) {
8865 return result;
8866 }
8867
8868 if ((result = ecm_state_write(sfi, "udp_to", "%d", udp_to))) {
8869 return result;
8870 }
8871
8872 if ((result = ecm_state_write(sfi, "nat_from", "%d", nat_from))) {
8873 return result;
8874 }
8875
8876 if ((result = ecm_state_write(sfi, "nat_to", "%d", nat_to))) {
8877 return result;
8878 }
8879
8880 if ((result = ecm_state_write(sfi, "tcp_nat_from", "%d", tcp_nat_from))) {
8881 return result;
8882 }
8883
8884 if ((result = ecm_state_write(sfi, "tcp_nat_to", "%d", tcp_nat_to))) {
8885 return result;
8886 }
8887
8888 if ((result = ecm_state_write(sfi, "udp_nat_from", "%d", udp_nat_from))) {
8889 return result;
8890 }
8891
8892 if ((result = ecm_state_write(sfi, "udp_nat_to", "%d", udp_nat_to))) {
8893 return result;
8894 }
8895
8896 if ((result = ecm_state_write(sfi, "address", "%s", address))) {
8897 return result;
8898 }
8899
8900 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
8901 return result;
8902 }
8903
8904#ifdef ECM_DB_ADVANCED_STATS_ENABLE
8905 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
8906 from_packet_total, to_packet_total, from_data_total_dropped,
8907 to_data_total_dropped, from_packet_total_dropped,
8908 to_packet_total_dropped))) {
8909 return result;
8910 }
8911#endif
8912
8913 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008914}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008915EXPORT_SYMBOL(ecm_db_mapping_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008916
8917/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008918 * ecm_db_host_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008919 * Prepare a host message
8920 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008921int ecm_db_host_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_host_instance *hi)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008922{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008923 int result;
Murat Sezginf21210e2016-04-04 13:58:20 -07008924 char address[ECM_IP_ADDR_STR_BUFF_SIZE];
Gareth Williamsb5903892015-03-20 15:13:07 +00008925#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008926 int mapping_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 bool on_link;
8930#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008931 uint64_t from_data_total;
8932 uint64_t to_data_total;
8933 uint64_t from_packet_total;
8934 uint64_t to_packet_total;
8935 uint64_t from_data_total_dropped;
8936 uint64_t to_data_total_dropped;
8937 uint64_t from_packet_total_dropped;
8938 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00008939#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008940
8941 DEBUG_TRACE("Prep host msg for %p\n", hi);
8942
8943 /*
8944 * Create a small xml stats element for our host.
8945 * Extract information from the host for inclusion into the message
8946 */
Gareth Williamsb5903892015-03-20 15:13:07 +00008947#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008948 mapping_count = ecm_db_host_mapping_count_get(hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00008949#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008950 ecm_ip_addr_to_string(address, hi->address);
8951 time_added = hi->time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008952 on_link = hi->on_link;
8953
8954#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008955 ecm_db_host_data_stats_get(hi, &from_data_total, &to_data_total,
8956 &from_packet_total, &to_packet_total,
8957 &from_data_total_dropped, &to_data_total_dropped,
8958 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williams85331c92015-03-11 20:39:18 +00008959#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008960
Gareth Williamsd5618a82015-05-20 11:13:32 +01008961 if ((result = ecm_state_prefix_add(sfi, "host"))) {
8962 return result;
8963 }
8964
8965 if ((result = ecm_state_write(sfi, "address", "%s", address))) {
8966 return result;
8967 }
8968 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
8969 return result;
8970 }
8971 if ((result = ecm_state_write(sfi, "on_link", "%d", on_link))) {
8972 return result;
8973 }
8974
Gareth Williamsb5903892015-03-20 15:13:07 +00008975#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008976 if ((result = ecm_state_write(sfi, "mappings", "%d", mapping_count))) {
8977 return result;
8978 }
Gareth Williamsb5903892015-03-20 15:13:07 +00008979#endif
Gareth Williamsd5618a82015-05-20 11:13:32 +01008980
Gareth Williams85331c92015-03-11 20:39:18 +00008981#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008982 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
8983 from_packet_total, to_packet_total, from_data_total_dropped,
8984 to_data_total_dropped, from_packet_total_dropped,
8985 to_packet_total_dropped))) {
8986 return result;
8987 }
Gareth Williams85331c92015-03-11 20:39:18 +00008988#endif
Gareth Williamsd5618a82015-05-20 11:13:32 +01008989
8990 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008991}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008992EXPORT_SYMBOL(ecm_db_host_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008993
8994/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008995 * ecm_db_node_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008996 * Prepare a node message
8997 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008998int ecm_db_node_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_node_instance *ni)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008999{
Gareth Williamsd5618a82015-05-20 11:13:32 +01009000 int result;
Murat Sezginf21210e2016-04-04 13:58:20 -07009001 char address[ECM_MAC_ADDR_STR_BUFF_SIZE];
Gareth Williamsb5903892015-03-20 15:13:07 +00009002#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009003 int from_connections_count;
9004 int to_connections_count;
9005 int from_nat_connections_count;
9006 int to_nat_connections_count;
Gareth Williamsb5903892015-03-20 15:13:07 +00009007#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009008 uint32_t time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00009009#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009010 uint64_t from_data_total;
9011 uint64_t to_data_total;
9012 uint64_t from_packet_total;
9013 uint64_t to_packet_total;
9014 uint64_t from_data_total_dropped;
9015 uint64_t to_data_total_dropped;
9016 uint64_t from_packet_total_dropped;
9017 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00009018#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009019
9020 DEBUG_TRACE("Prep node msg for %p\n", ni);
9021
9022 /*
9023 * Create a small xml stats block for our managed node, like:
9024 * <node address="" hosts="" time_added="" from_data_total="" to_data_total="" />
9025 *
9026 * Extract information from the node for inclusion into the message
9027 */
Gareth Williamsb5903892015-03-20 15:13:07 +00009028#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009029 spin_lock_bh(&ecm_db_lock);
9030 from_connections_count = ni->from_connections_count;
9031 to_connections_count = ni->to_connections_count;
9032 from_nat_connections_count = ni->from_nat_connections_count;
9033 to_nat_connections_count = ni->to_nat_connections_count;
9034 spin_unlock_bh(&ecm_db_lock);
Gareth Williamsb5903892015-03-20 15:13:07 +00009035#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009036 time_added = ni->time_added;
Murat Sezginf21210e2016-04-04 13:58:20 -07009037 snprintf(address, sizeof(address), "%pM", ni->address);
Gareth Williams85331c92015-03-11 20:39:18 +00009038
9039#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009040 ecm_db_node_data_stats_get(ni, &from_data_total, &to_data_total,
9041 &from_packet_total, &to_packet_total,
9042 &from_data_total_dropped, &to_data_total_dropped,
9043 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williams85331c92015-03-11 20:39:18 +00009044
9045#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009046
Gareth Williamsd5618a82015-05-20 11:13:32 +01009047 if ((result = ecm_state_prefix_add(sfi, "node"))) {
9048 return result;
9049 }
9050 if ((result = ecm_state_write(sfi, "address", "%s", address))) {
9051 return result;
9052 }
9053 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
9054 return result;
9055 }
Gareth Williamsb5903892015-03-20 15:13:07 +00009056#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009057 if ((result = ecm_state_write(sfi, "from_connections_count", "%d", from_connections_count))) {
9058 return result;
9059 }
9060 if ((result = ecm_state_write(sfi, "to_connections_count", "%d", to_connections_count))) {
9061 return result;
9062 }
9063 if ((result = ecm_state_write(sfi, "from_nat_connections_count", "%d", from_nat_connections_count))) {
9064 return result;
9065 }
9066 if ((result = ecm_state_write(sfi, "to_nat_connections_count", "%d", to_nat_connections_count))) {
9067 return result;
9068 }
Gareth Williamsb5903892015-03-20 15:13:07 +00009069#endif
Gareth Williams85331c92015-03-11 20:39:18 +00009070#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009071 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
9072 from_packet_total, to_packet_total, from_data_total_dropped,
9073 to_data_total_dropped, from_packet_total_dropped,
9074 to_packet_total_dropped))) {
9075 return result;
9076 }
Gareth Williams85331c92015-03-11 20:39:18 +00009077#endif
Gareth Williamsd5618a82015-05-20 11:13:32 +01009078 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00009079}
Gareth Williamsd5618a82015-05-20 11:13:32 +01009080EXPORT_SYMBOL(ecm_db_node_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00009081
9082/*
9083 * ecm_db_connection_hash_table_lengths_get()
9084 * Return hash table length
9085 */
9086int ecm_db_connection_hash_table_lengths_get(int index)
9087{
9088 int length;
9089
9090 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_MAPPING_HASH_SLOTS), "Bad protocol: %d\n", index);
9091 spin_lock_bh(&ecm_db_lock);
9092 length = ecm_db_connection_table_lengths[index];
9093 spin_unlock_bh(&ecm_db_lock);
9094 return length;
9095}
9096EXPORT_SYMBOL(ecm_db_connection_hash_table_lengths_get);
9097
9098/*
9099 * ecm_db_connection_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_connection_hash_index_get_next(int index)
9103{
9104 index++;
9105 if (index >= ECM_DB_CONNECTION_SERIAL_HASH_SLOTS) {
9106 return -1;
9107 }
9108 return index;
9109}
9110EXPORT_SYMBOL(ecm_db_connection_hash_index_get_next);
9111
9112/*
9113 * ecm_db_connection_hash_index_get_first()
9114 * Return first hash index
9115 */
9116int ecm_db_connection_hash_index_get_first(void)
9117{
9118 return 0;
9119}
9120EXPORT_SYMBOL(ecm_db_connection_hash_index_get_first);
9121
9122/*
9123 * ecm_db_mapping_hash_table_lengths_get()
9124 * Return hash table length
9125 */
9126int ecm_db_mapping_hash_table_lengths_get(int index)
9127{
9128 int length;
9129
9130 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_MAPPING_HASH_SLOTS), "Bad protocol: %d\n", index);
9131 spin_lock_bh(&ecm_db_lock);
9132 length = ecm_db_mapping_table_lengths[index];
9133 spin_unlock_bh(&ecm_db_lock);
9134 return length;
9135}
9136EXPORT_SYMBOL(ecm_db_mapping_hash_table_lengths_get);
9137
9138/*
9139 * ecm_db_mapping_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_mapping_hash_index_get_next(int index)
9143{
9144 index++;
9145 if (index >= ECM_DB_MAPPING_HASH_SLOTS) {
9146 return -1;
9147 }
9148 return index;
9149}
9150EXPORT_SYMBOL(ecm_db_mapping_hash_index_get_next);
9151
9152/*
9153 * ecm_db_mapping_hash_index_get_first()
9154 * Return first hash index
9155 */
9156int ecm_db_mapping_hash_index_get_first(void)
9157{
9158 return 0;
9159}
9160EXPORT_SYMBOL(ecm_db_mapping_hash_index_get_first);
9161
9162/*
9163 * ecm_db_host_hash_table_lengths_get()
9164 * Return hash table length
9165 */
9166int ecm_db_host_hash_table_lengths_get(int index)
9167{
9168 int length;
9169
9170 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_HOST_HASH_SLOTS), "Bad protocol: %d\n", index);
9171 spin_lock_bh(&ecm_db_lock);
9172 length = ecm_db_host_table_lengths[index];
9173 spin_unlock_bh(&ecm_db_lock);
9174 return length;
9175}
9176EXPORT_SYMBOL(ecm_db_host_hash_table_lengths_get);
9177
9178/*
9179 * ecm_db_host_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_host_hash_index_get_next(int index)
9183{
9184 index++;
9185 if (index >= ECM_DB_HOST_HASH_SLOTS) {
9186 return -1;
9187 }
9188 return index;
9189}
9190EXPORT_SYMBOL(ecm_db_host_hash_index_get_next);
9191
9192/*
9193 * ecm_db_host_hash_index_get_first()
9194 * Return first hash index
9195 */
9196int ecm_db_host_hash_index_get_first(void)
9197{
9198 return 0;
9199}
9200EXPORT_SYMBOL(ecm_db_host_hash_index_get_first);
9201
9202/*
9203 * ecm_db_node_hash_table_lengths_get()
9204 * Return hash table length
9205 */
9206int ecm_db_node_hash_table_lengths_get(int index)
9207{
9208 int length;
9209
9210 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_NODE_HASH_SLOTS), "Bad protocol: %d\n", index);
9211 spin_lock_bh(&ecm_db_lock);
9212 length = ecm_db_node_table_lengths[index];
9213 spin_unlock_bh(&ecm_db_lock);
9214 return length;
9215}
9216EXPORT_SYMBOL(ecm_db_node_hash_table_lengths_get);
9217
9218/*
9219 * ecm_db_node_hash_index_get_next()
9220 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
9221 */
9222int ecm_db_node_hash_index_get_next(int index)
9223{
9224 index++;
9225 if (index >= ECM_DB_NODE_HASH_SLOTS) {
9226 return -1;
9227 }
9228 return index;
9229}
9230EXPORT_SYMBOL(ecm_db_node_hash_index_get_next);
9231
9232/*
9233 * ecm_db_node_hash_index_get_first()
9234 * Return first hash index
9235 */
9236int ecm_db_node_hash_index_get_first(void)
9237{
9238 return 0;
9239}
9240EXPORT_SYMBOL(ecm_db_node_hash_index_get_first);
9241
9242/*
9243 * ecm_db_iface_hash_table_lengths_get()
9244 * Return hash table length
9245 */
9246int ecm_db_iface_hash_table_lengths_get(int index)
9247{
9248 int length;
9249
9250 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_IFACE_HASH_SLOTS), "Bad protocol: %d\n", index);
9251 spin_lock_bh(&ecm_db_lock);
9252 length = ecm_db_iface_table_lengths[index];
9253 spin_unlock_bh(&ecm_db_lock);
9254 return length;
9255}
9256EXPORT_SYMBOL(ecm_db_iface_hash_table_lengths_get);
9257
9258/*
9259 * ecm_db_iface_hash_index_get_next()
9260 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
9261 */
9262int ecm_db_iface_hash_index_get_next(int index)
9263{
9264 index++;
9265 if (index >= ECM_DB_IFACE_HASH_SLOTS) {
9266 return -1;
9267 }
9268 return index;
9269}
9270EXPORT_SYMBOL(ecm_db_iface_hash_index_get_next);
9271
9272/*
9273 * ecm_db_iface_hash_index_get_first()
9274 * Return first hash index
9275 */
9276int ecm_db_iface_hash_index_get_first(void)
9277{
9278 return 0;
9279}
9280EXPORT_SYMBOL(ecm_db_iface_hash_index_get_first);
9281
9282/*
9283 * ecm_db_protocol_get_next()
9284 * Given a number, return the next one OR return -1 for no more protocol numbers to return.
9285 */
9286int ecm_db_protocol_get_next(int protocol)
9287{
9288 protocol++;
9289 if (protocol >= ECM_DB_PROTOCOL_COUNT) {
9290 return -1;
9291 }
9292 return protocol;
9293}
9294EXPORT_SYMBOL(ecm_db_protocol_get_next);
9295
9296/*
9297 * ecm_db_protocol_get_first()
9298 * Return first protocol number
9299 */
9300int ecm_db_protocol_get_first(void)
9301{
9302 return 0;
9303}
9304EXPORT_SYMBOL(ecm_db_protocol_get_first);
9305#endif
9306
9307/*
9308 * ecm_db_iface_add_ethernet()
9309 * Add a iface instance into the database
9310 */
9311void 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 -07009312 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009313 ecm_db_iface_final_callback_t final, void *arg)
9314{
9315 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009316 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009317 struct ecm_db_listener_instance *li;
9318 struct ecm_db_interface_info_ethernet *type_info;
9319
9320 spin_lock_bh(&ecm_db_lock);
9321 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9322 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009323#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009324 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009325#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009326 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9327 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9328 spin_unlock_bh(&ecm_db_lock);
9329
9330 /*
9331 * Record general info
9332 */
9333 ii->type = ECM_DB_IFACE_TYPE_ETHERNET;
9334#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009335 ii->state_get = ecm_db_iface_ethernet_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009336#endif
9337 ii->arg = arg;
9338 ii->final = final;
9339 strcpy(ii->name, name);
9340 ii->mtu = mtu;
9341 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009342 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009343
9344 /*
9345 * Type specific info
9346 */
9347 type_info = &ii->type_info.ethernet;
9348 memcpy(type_info->address, address, ETH_ALEN);
9349
9350 /*
9351 * Compute hash chain for insertion
9352 */
9353 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
9354 ii->hash_index = hash_index;
9355
Murat Sezgin91c5d712015-06-12 15:16:22 -07009356 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9357 ii->iface_id_hash_index = iface_id_hash_index;
9358
Gareth Williamsf98d4192015-03-11 16:55:41 +00009359 /*
9360 * Add into the global list
9361 */
9362 spin_lock_bh(&ecm_db_lock);
9363 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9364 ii->prev = NULL;
9365 ii->next = ecm_db_interfaces;
9366 if (ecm_db_interfaces) {
9367 ecm_db_interfaces->prev = ii;
9368 }
9369 ecm_db_interfaces = ii;
9370
9371 /*
9372 * Insert into chain
9373 */
9374 ii->hash_next = ecm_db_iface_table[hash_index];
9375 if (ecm_db_iface_table[hash_index]) {
9376 ecm_db_iface_table[hash_index]->hash_prev = ii;
9377 }
9378 ecm_db_iface_table[hash_index] = ii;
9379 ecm_db_iface_table_lengths[hash_index]++;
9380 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9381
9382 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);
9383
9384 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009385 * Insert into interface identifier chain
9386 */
9387 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9388 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9389 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9390 }
9391 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9392 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9393 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]);
9394
9395 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009396 * Set time of addition
9397 */
9398 ii->time_added = ecm_db_time;
9399 spin_unlock_bh(&ecm_db_lock);
9400
9401 /*
9402 * Throw add event to the listeners
9403 */
9404 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9405 li = ecm_db_listeners_get_and_ref_first();
9406 while (li) {
9407 struct ecm_db_listener_instance *lin;
9408 if (li->iface_added) {
9409 li->iface_added(li->arg, ii);
9410 }
9411
9412 /*
9413 * Get next listener
9414 */
9415 lin = ecm_db_listener_get_and_ref_next(li);
9416 ecm_db_listener_deref(li);
9417 li = lin;
9418 }
9419}
9420EXPORT_SYMBOL(ecm_db_iface_add_ethernet);
9421
9422#ifdef ECM_INTERFACE_BOND_ENABLE
9423/*
9424 * ecm_db_iface_add_lag()
9425 * Add a iface instance into the database
9426 */
9427void 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 -07009428 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009429 ecm_db_iface_final_callback_t final, void *arg)
9430{
9431 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009432 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009433 struct ecm_db_listener_instance *li;
9434 struct ecm_db_interface_info_lag *type_info;
9435
9436 spin_lock_bh(&ecm_db_lock);
9437 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9438 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009439#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009440 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009441#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009442 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9443 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9444 spin_unlock_bh(&ecm_db_lock);
9445
9446 /*
9447 * Record general info
9448 */
9449 ii->type = ECM_DB_IFACE_TYPE_LAG;
9450#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009451 ii->state_get = ecm_db_iface_lag_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009452#endif
9453 ii->arg = arg;
9454 ii->final = final;
9455 strcpy(ii->name, name);
9456 ii->mtu = mtu;
9457 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009458 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009459
9460 /*
9461 * Type specific info
9462 */
9463 type_info = &ii->type_info.lag;
9464 memcpy(type_info->address, address, ETH_ALEN);
9465
9466 /*
9467 * Compute hash chain for insertion
9468 */
9469 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
9470 ii->hash_index = hash_index;
9471
Murat Sezgin91c5d712015-06-12 15:16:22 -07009472 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9473 ii->iface_id_hash_index = iface_id_hash_index;
9474
Gareth Williamsf98d4192015-03-11 16:55:41 +00009475 /*
9476 * Add into the global list
9477 */
9478 spin_lock_bh(&ecm_db_lock);
9479 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9480 ii->prev = NULL;
9481 ii->next = ecm_db_interfaces;
9482 if (ecm_db_interfaces) {
9483 ecm_db_interfaces->prev = ii;
9484 }
9485 ecm_db_interfaces = ii;
9486
9487 /*
9488 * Insert into chain
9489 */
9490 ii->hash_next = ecm_db_iface_table[hash_index];
9491 if (ecm_db_iface_table[hash_index]) {
9492 ecm_db_iface_table[hash_index]->hash_prev = ii;
9493 }
9494 ecm_db_iface_table[hash_index] = ii;
9495 ecm_db_iface_table_lengths[hash_index]++;
9496 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9497
9498 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);
9499
9500 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009501 * Insert into interface identifier chain
9502 */
9503 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9504 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9505 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9506 }
9507 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9508 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9509 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]);
9510
9511 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009512 * Set time of addition
9513 */
9514 ii->time_added = ecm_db_time;
9515 spin_unlock_bh(&ecm_db_lock);
9516
9517 /*
9518 * Throw add event to the listeners
9519 */
9520 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9521 li = ecm_db_listeners_get_and_ref_first();
9522 while (li) {
9523 struct ecm_db_listener_instance *lin;
9524 if (li->iface_added) {
9525 li->iface_added(li->arg, ii);
9526 }
9527
9528 /*
9529 * Get next listener
9530 */
9531 lin = ecm_db_listener_get_and_ref_next(li);
9532 ecm_db_listener_deref(li);
9533 li = lin;
9534 }
9535}
9536EXPORT_SYMBOL(ecm_db_iface_add_lag);
9537#endif
9538
9539/*
9540 * ecm_db_iface_add_bridge()
9541 * Add a iface instance into the database
9542 */
9543void 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 -07009544 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009545 ecm_db_iface_final_callback_t final, void *arg)
9546{
9547 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009548 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009549 struct ecm_db_listener_instance *li;
9550 struct ecm_db_interface_info_bridge *type_info;
9551
9552 spin_lock_bh(&ecm_db_lock);
9553 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9554 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009555#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009556 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009557#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009558 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9559 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9560 spin_unlock_bh(&ecm_db_lock);
9561
9562 /*
9563 * Record general info
9564 */
9565 ii->type = ECM_DB_IFACE_TYPE_BRIDGE;
9566#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009567 ii->state_get = ecm_db_iface_bridge_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009568#endif
9569 ii->arg = arg;
9570 ii->final = final;
9571 strcpy(ii->name, name);
9572 ii->mtu = mtu;
9573 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009574 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009575
9576 /*
9577 * Type specific info
9578 */
9579 type_info = &ii->type_info.bridge;
9580 memcpy(type_info->address, address, ETH_ALEN);
9581
9582 /*
9583 * Compute hash chain for insertion
9584 */
9585 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
9586 ii->hash_index = hash_index;
9587
Murat Sezgin91c5d712015-06-12 15:16:22 -07009588 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9589 ii->iface_id_hash_index = iface_id_hash_index;
9590
Gareth Williamsf98d4192015-03-11 16:55:41 +00009591 /*
9592 * Add into the global list
9593 */
9594 spin_lock_bh(&ecm_db_lock);
9595 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9596 ii->prev = NULL;
9597 ii->next = ecm_db_interfaces;
9598 if (ecm_db_interfaces) {
9599 ecm_db_interfaces->prev = ii;
9600 }
9601 ecm_db_interfaces = ii;
9602
9603 /*
9604 * Insert into chain
9605 */
9606 ii->hash_next = ecm_db_iface_table[hash_index];
9607 if (ecm_db_iface_table[hash_index]) {
9608 ecm_db_iface_table[hash_index]->hash_prev = ii;
9609 }
9610 ecm_db_iface_table[hash_index] = ii;
9611 ecm_db_iface_table_lengths[hash_index]++;
9612 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9613
9614 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);
9615
9616 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009617 * Insert into interface identifier chain
9618 */
9619 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9620 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9621 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9622 }
9623 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9624 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9625 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]);
9626
9627 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009628 * Set time of addition
9629 */
9630 ii->time_added = ecm_db_time;
9631 spin_unlock_bh(&ecm_db_lock);
9632
9633 /*
9634 * Throw add event to the listeners
9635 */
9636 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9637 li = ecm_db_listeners_get_and_ref_first();
9638 while (li) {
9639 struct ecm_db_listener_instance *lin;
9640 if (li->iface_added) {
9641 li->iface_added(li->arg, ii);
9642 }
9643
9644 /*
9645 * Get next listener
9646 */
9647 lin = ecm_db_listener_get_and_ref_next(li);
9648 ecm_db_listener_deref(li);
9649 li = lin;
9650 }
9651}
9652EXPORT_SYMBOL(ecm_db_iface_add_bridge);
9653
9654#ifdef ECM_INTERFACE_VLAN_ENABLE
9655/*
9656 * ecm_db_iface_add_vlan()
9657 * Add a iface instance into the database
9658 */
9659void 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 -07009660 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009661 ecm_db_iface_final_callback_t final, void *arg)
9662{
9663 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009664 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009665 struct ecm_db_listener_instance *li;
9666 struct ecm_db_interface_info_vlan *type_info;
9667
9668 spin_lock_bh(&ecm_db_lock);
9669 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9670 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009671#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009672 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009673#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009674 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9675 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9676 spin_unlock_bh(&ecm_db_lock);
9677
9678 /*
9679 * Record general info
9680 */
9681 ii->type = ECM_DB_IFACE_TYPE_VLAN;
9682#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009683 ii->state_get = ecm_db_iface_vlan_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009684#endif
9685 ii->arg = arg;
9686 ii->final = final;
9687 strcpy(ii->name, name);
9688 ii->mtu = mtu;
9689 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009690 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009691
9692 /*
9693 * Type specific info
9694 */
9695 type_info = &ii->type_info.vlan;
9696 type_info->vlan_tag = vlan_tag;
9697 type_info->vlan_tpid = vlan_tpid;
9698 memcpy(type_info->address, address, ETH_ALEN);
9699
9700 /*
9701 * Compute hash chain for insertion
9702 */
9703 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
9704 ii->hash_index = hash_index;
9705
Murat Sezgin91c5d712015-06-12 15:16:22 -07009706 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9707 ii->iface_id_hash_index = iface_id_hash_index;
9708
Gareth Williamsf98d4192015-03-11 16:55:41 +00009709 /*
9710 * Add into the global list
9711 */
9712 spin_lock_bh(&ecm_db_lock);
9713 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9714 ii->prev = NULL;
9715 ii->next = ecm_db_interfaces;
9716 if (ecm_db_interfaces) {
9717 ecm_db_interfaces->prev = ii;
9718 }
9719 ecm_db_interfaces = ii;
9720
9721 /*
9722 * Insert into chain
9723 */
9724 ii->hash_next = ecm_db_iface_table[hash_index];
9725 if (ecm_db_iface_table[hash_index]) {
9726 ecm_db_iface_table[hash_index]->hash_prev = ii;
9727 }
9728 ecm_db_iface_table[hash_index] = ii;
9729 ecm_db_iface_table_lengths[hash_index]++;
9730 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9731
9732 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);
9733
9734 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009735 * Insert into interface identifier chain
9736 */
9737 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9738 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9739 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9740 }
9741 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9742 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9743 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]);
9744
9745 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009746 * Set time of addition
9747 */
9748 ii->time_added = ecm_db_time;
9749 spin_unlock_bh(&ecm_db_lock);
9750
9751 /*
9752 * Throw add event to the listeners
9753 */
9754 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9755 li = ecm_db_listeners_get_and_ref_first();
9756 while (li) {
9757 struct ecm_db_listener_instance *lin;
9758 if (li->iface_added) {
9759 li->iface_added(li->arg, ii);
9760 }
9761
9762 /*
9763 * Get next listener
9764 */
9765 lin = ecm_db_listener_get_and_ref_next(li);
9766 ecm_db_listener_deref(li);
9767 li = lin;
9768 }
9769}
9770EXPORT_SYMBOL(ecm_db_iface_add_vlan);
9771#endif
9772
ratheesh kannothcfdcb332015-12-24 07:19:18 +05309773#ifdef ECM_INTERFACE_MAP_T_ENABLE
9774/*
9775 * ecm_db_iface_add_map_t()
9776 * Add a iface instance into the database
9777 */
9778void ecm_db_iface_add_map_t(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_map_t *map_t_info,
9779 char *name, int32_t mtu, int32_t interface_identifier,
9780 int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
9781 void *arg)
9782{
9783 ecm_db_iface_hash_t hash_index;
9784 ecm_db_iface_id_hash_t iface_id_hash_index;
9785 struct ecm_db_listener_instance *li;
9786 struct ecm_db_interface_info_map_t *type_info;
9787
9788 spin_lock_bh(&ecm_db_lock);
9789 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9790#ifdef ECM_DB_XREF_ENABLE
9791 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
9792#endif
9793 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9794 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9795 spin_unlock_bh(&ecm_db_lock);
9796
9797 /*
9798 * Record general info
9799 */
9800 ii->type = ECM_DB_IFACE_TYPE_MAP_T;
9801#ifdef ECM_STATE_OUTPUT_ENABLE
9802 ii->state_get = ecm_db_iface_map_t_state_get;
9803#endif
9804 ii->arg = arg;
9805 ii->final = final;
9806 strlcpy(ii->name, name, IFNAMSIZ);
9807 ii->mtu = mtu;
9808 ii->interface_identifier = interface_identifier;
9809 ii->ae_interface_identifier = ae_interface_identifier;
9810
9811 /*
9812 * Type specific info
9813 */
9814 type_info = &ii->type_info.map_t;
9815 memcpy(type_info, map_t_info, sizeof(struct ecm_db_interface_info_map_t));
9816
9817 /*
9818 * Compute hash chain for insertion
9819 */
9820 hash_index = ecm_db_iface_generate_hash_index_map_t(type_info->if_index);
9821 ii->hash_index = hash_index;
9822
9823 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9824 ii->iface_id_hash_index = iface_id_hash_index;
9825 /*
9826 * Add into the global list
9827 */
9828 spin_lock_bh(&ecm_db_lock);
9829 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9830 ii->prev = NULL;
9831 ii->next = ecm_db_interfaces;
9832 if (ecm_db_interfaces) {
9833 ecm_db_interfaces->prev = ii;
9834 }
9835 ecm_db_interfaces = ii;
9836
9837 /*
9838 * Insert into chain
9839 */
9840 ii->hash_next = ecm_db_iface_table[hash_index];
9841 if (ecm_db_iface_table[hash_index]) {
9842 ecm_db_iface_table[hash_index]->hash_prev = ii;
9843 }
9844 ecm_db_iface_table[hash_index] = ii;
9845 ecm_db_iface_table_lengths[hash_index]++;
9846 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9847
9848 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);
9849
9850 /*
9851 * Insert into interface identifier chain
9852 */
9853 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9854 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9855 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9856 }
9857 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9858 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9859 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]);
9860
9861 /*
9862 * Set time of addition
9863 */
9864 ii->time_added = ecm_db_time;
9865 spin_unlock_bh(&ecm_db_lock);
9866
9867 /*
9868 * Throw add event to the listeners
9869 */
9870 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9871 li = ecm_db_listeners_get_and_ref_first();
9872 while (li) {
9873 struct ecm_db_listener_instance *lin;
9874 if (li->iface_added) {
9875 li->iface_added(li->arg, ii);
9876 }
9877
9878 /*
9879 * Get next listener
9880 */
9881 lin = ecm_db_listener_get_and_ref_next(li);
9882 ecm_db_listener_deref(li);
9883 li = lin;
9884 }
9885}
9886EXPORT_SYMBOL(ecm_db_iface_add_map_t);
9887#endif
9888
ratheesh kannotha32fdd12015-09-09 08:02:58 +05309889#ifdef ECM_INTERFACE_PPPOE_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009890/*
9891 * ecm_db_iface_add_pppoe()
9892 * Add a iface instance into the database
9893 */
9894void ecm_db_iface_add_pppoe(struct ecm_db_iface_instance *ii, uint16_t pppoe_session_id, uint8_t *remote_mac,
9895 char *name, int32_t mtu, int32_t interface_identifier,
Murat Sezgin91c5d712015-06-12 15:16:22 -07009896 int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009897 void *arg)
9898{
9899 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009900 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009901 struct ecm_db_listener_instance *li;
9902 struct ecm_db_interface_info_pppoe *type_info;
9903
9904 spin_lock_bh(&ecm_db_lock);
9905 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009906#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009907 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009908#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009909 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9910 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9911 spin_unlock_bh(&ecm_db_lock);
9912
9913 /*
9914 * Record general info
9915 */
9916 ii->type = ECM_DB_IFACE_TYPE_PPPOE;
9917#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009918 ii->state_get = ecm_db_iface_pppoe_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009919#endif
9920 ii->arg = arg;
9921 ii->final = final;
9922 strcpy(ii->name, name);
9923 ii->mtu = mtu;
9924 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009925 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009926
9927 /*
9928 * Type specific info
9929 */
9930 type_info = &ii->type_info.pppoe;
9931 type_info->pppoe_session_id = pppoe_session_id;
9932 memcpy(type_info->remote_mac, remote_mac, ETH_ALEN);
9933
9934 /*
9935 * Compute hash chain for insertion
9936 */
9937 hash_index = ecm_db_iface_generate_hash_index_pppoe(pppoe_session_id);
9938 ii->hash_index = hash_index;
9939
Murat Sezgin91c5d712015-06-12 15:16:22 -07009940 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9941 ii->iface_id_hash_index = iface_id_hash_index;
9942
Gareth Williamsf98d4192015-03-11 16:55:41 +00009943 /*
9944 * Add into the global list
9945 */
9946 spin_lock_bh(&ecm_db_lock);
9947 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9948 ii->prev = NULL;
9949 ii->next = ecm_db_interfaces;
9950 if (ecm_db_interfaces) {
9951 ecm_db_interfaces->prev = ii;
9952 }
9953 ecm_db_interfaces = ii;
9954
9955 /*
9956 * Insert into chain
9957 */
9958 ii->hash_next = ecm_db_iface_table[hash_index];
9959 if (ecm_db_iface_table[hash_index]) {
9960 ecm_db_iface_table[hash_index]->hash_prev = ii;
9961 }
9962 ecm_db_iface_table[hash_index] = ii;
9963 ecm_db_iface_table_lengths[hash_index]++;
9964 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9965
9966 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);
9967
9968 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009969 * Insert into interface identifier chain
9970 */
9971 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9972 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9973 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9974 }
9975 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9976 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9977 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]);
9978
9979 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009980 * Set time of addition
9981 */
9982 ii->time_added = ecm_db_time;
9983 spin_unlock_bh(&ecm_db_lock);
9984
9985 /*
9986 * Throw add event to the listeners
9987 */
9988 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9989 li = ecm_db_listeners_get_and_ref_first();
9990 while (li) {
9991 struct ecm_db_listener_instance *lin;
9992 if (li->iface_added) {
9993 li->iface_added(li->arg, ii);
9994 }
9995
9996 /*
9997 * Get next listener
9998 */
9999 lin = ecm_db_listener_get_and_ref_next(li);
10000 ecm_db_listener_deref(li);
10001 li = lin;
10002 }
10003}
10004EXPORT_SYMBOL(ecm_db_iface_add_pppoe);
10005#endif
10006
ratheesh kannotha32fdd12015-09-09 08:02:58 +053010007#ifdef ECM_INTERFACE_L2TPV2_ENABLE
10008/*
10009 * ecm_db_iface_add_pppol2tpv2()
10010 * Add a iface instance into the database
10011 */
10012void ecm_db_iface_add_pppol2tpv2(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppol2tpv2 *pppol2tpv2_info,
10013 char *name, int32_t mtu, int32_t interface_identifier,
10014 int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
10015 void *arg)
10016{
10017 ecm_db_iface_hash_t hash_index;
10018 ecm_db_iface_id_hash_t iface_id_hash_index;
10019 struct ecm_db_listener_instance *li;
10020 struct ecm_db_interface_info_pppol2tpv2 *type_info;
10021
10022 spin_lock_bh(&ecm_db_lock);
10023 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
10024#ifdef ECM_DB_XREF_ENABLE
10025 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
10026#endif
10027 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10028 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10029 spin_unlock_bh(&ecm_db_lock);
10030
10031 /*
10032 * Record general info
10033 */
10034 ii->type = ECM_DB_IFACE_TYPE_PPPOL2TPV2;
10035#ifdef ECM_STATE_OUTPUT_ENABLE
10036 ii->state_get = ecm_db_iface_pppol2tpv2_state_get;
10037#endif
10038 ii->arg = arg;
10039 ii->final = final;
10040 strlcpy(ii->name, name, IFNAMSIZ);
10041 ii->mtu = mtu;
10042 ii->interface_identifier = interface_identifier;
10043 ii->ae_interface_identifier = ae_interface_identifier;
10044
10045 /*
10046 * Type specific info
10047 */
10048 type_info = &ii->type_info.pppol2tpv2;
10049 memcpy(type_info, pppol2tpv2_info, sizeof(struct ecm_db_interface_info_pppol2tpv2));
10050
10051 /*
10052 * Compute hash chain for insertion
10053 */
10054 hash_index = ecm_db_iface_generate_hash_index_pppol2tpv2(type_info->l2tp.tunnel.tunnel_id,
10055 type_info->l2tp.session.session_id);
10056 ii->hash_index = hash_index;
10057
10058 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10059 ii->iface_id_hash_index = iface_id_hash_index;
10060 /*
10061 * Add into the global list
10062 */
10063 spin_lock_bh(&ecm_db_lock);
10064 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10065 ii->prev = NULL;
10066 ii->next = ecm_db_interfaces;
10067 if (ecm_db_interfaces) {
10068 ecm_db_interfaces->prev = ii;
10069 }
10070 ecm_db_interfaces = ii;
10071
10072 /*
10073 * Insert into chain
10074 */
10075 ii->hash_next = ecm_db_iface_table[hash_index];
10076 if (ecm_db_iface_table[hash_index]) {
10077 ecm_db_iface_table[hash_index]->hash_prev = ii;
10078 }
10079 ecm_db_iface_table[hash_index] = ii;
10080 ecm_db_iface_table_lengths[hash_index]++;
10081 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10082
10083 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);
10084
10085 /*
10086 * Insert into interface identifier chain
10087 */
10088 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10089 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10090 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10091 }
10092 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10093 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10094 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]);
10095
10096 /*
10097 * Set time of addition
10098 */
10099 ii->time_added = ecm_db_time;
10100 spin_unlock_bh(&ecm_db_lock);
10101
10102 /*
10103 * Throw add event to the listeners
10104 */
10105 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10106 li = ecm_db_listeners_get_and_ref_first();
10107 while (li) {
10108 struct ecm_db_listener_instance *lin;
10109 if (li->iface_added) {
10110 li->iface_added(li->arg, ii);
10111 }
10112
10113 /*
10114 * Get next listener
10115 */
10116 lin = ecm_db_listener_get_and_ref_next(li);
10117 ecm_db_listener_deref(li);
10118 li = lin;
10119 }
10120}
10121EXPORT_SYMBOL(ecm_db_iface_add_pppol2tpv2);
10122
10123#endif
10124
Shyam Sunder23f2e542015-09-28 14:56:49 +053010125#ifdef ECM_INTERFACE_PPTP_ENABLE
10126/*
10127 * ecm_db_iface_add_pptp()
10128 * Add a iface instance into the database
10129 */
10130void ecm_db_iface_add_pptp(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info,
10131 char *name, int32_t mtu, int32_t interface_identifier,
10132 int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
10133 void *arg)
10134{
10135 ecm_db_iface_hash_t hash_index;
10136 ecm_db_iface_id_hash_t iface_id_hash_index;
10137 struct ecm_db_listener_instance *li;
10138 struct ecm_db_interface_info_pptp *type_info;
10139
10140 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
10141 spin_lock_bh(&ecm_db_lock);
10142#ifdef ECM_DB_XREF_ENABLE
10143 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
10144#endif
10145 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10146 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10147 spin_unlock_bh(&ecm_db_lock);
10148
10149 /*
10150 * Record general info
10151 */
10152 ii->type = ECM_DB_IFACE_TYPE_PPTP;
10153#ifdef ECM_STATE_OUTPUT_ENABLE
10154 ii->state_get = ecm_db_iface_pptp_state_get;
10155#endif
10156 ii->arg = arg;
10157 ii->final = final;
10158 strlcpy(ii->name, name, IFNAMSIZ);
10159 ii->mtu = mtu;
10160 ii->interface_identifier = interface_identifier;
10161 ii->ae_interface_identifier = ae_interface_identifier;
10162
10163 /*
10164 * Type specific info
10165 */
10166 type_info = &ii->type_info.pptp;
10167 memcpy(type_info, pptp_info, sizeof(struct ecm_db_interface_info_pptp));
10168
10169 /*
10170 * Compute hash chain for insertion
10171 */
10172 hash_index = ecm_db_iface_generate_hash_index_pptp(type_info->src_call_id,
10173 type_info->dst_call_id);
10174 ii->hash_index = hash_index;
10175
10176 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10177 ii->iface_id_hash_index = iface_id_hash_index;
10178 /*
10179 * Add into the global list
10180 */
10181 spin_lock_bh(&ecm_db_lock);
10182 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10183 ii->prev = NULL;
10184 ii->next = ecm_db_interfaces;
10185 if (ecm_db_interfaces) {
10186 ecm_db_interfaces->prev = ii;
10187 }
10188 ecm_db_interfaces = ii;
10189
10190 /*
10191 * Insert into chain
10192 */
10193 ii->hash_next = ecm_db_iface_table[hash_index];
10194 if (ecm_db_iface_table[hash_index]) {
10195 ecm_db_iface_table[hash_index]->hash_prev = ii;
10196 }
10197 ecm_db_iface_table[hash_index] = ii;
10198 ecm_db_iface_table_lengths[hash_index]++;
10199 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10200
10201 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);
10202
10203 /*
10204 * Insert into interface identifier chain
10205 */
10206 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10207 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10208 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10209 }
10210 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10211 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10212 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]);
10213
10214 /*
10215 * Set time of addition
10216 */
10217 ii->time_added = ecm_db_time;
10218 spin_unlock_bh(&ecm_db_lock);
10219
10220 /*
10221 * Throw add event to the listeners
10222 */
10223 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10224 li = ecm_db_listeners_get_and_ref_first();
10225 while (li) {
10226 struct ecm_db_listener_instance *lin;
10227 if (li->iface_added) {
10228 li->iface_added(li->arg, ii);
10229 }
10230
10231 /*
10232 * Get next listener
10233 */
10234 lin = ecm_db_listener_get_and_ref_next(li);
10235 ecm_db_listener_deref(li);
10236 li = lin;
10237 }
10238}
10239EXPORT_SYMBOL(ecm_db_iface_add_pptp);
10240#endif
10241
Ben Menchaca84f36632014-02-28 20:57:38 +000010242/*
10243 * ecm_db_iface_add_unknown()
10244 * Add a iface instance into the database
10245 */
10246void 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 -070010247 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +000010248 ecm_db_iface_final_callback_t final, void *arg)
10249{
10250 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010251 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +000010252 struct ecm_db_listener_instance *li;
10253 struct ecm_db_interface_info_unknown *type_info;
10254
10255 spin_lock_bh(&ecm_db_lock);
10256 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010257#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010258 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010259#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010260 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10261 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10262 spin_unlock_bh(&ecm_db_lock);
10263
10264 /*
10265 * Record general info
10266 */
10267 ii->type = ECM_DB_IFACE_TYPE_UNKNOWN;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010268#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +010010269 ii->state_get = ecm_db_iface_unknown_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010270#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010271 ii->arg = arg;
10272 ii->final = final;
10273 strcpy(ii->name, name);
10274 ii->mtu = mtu;
10275 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010276 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +000010277
10278 /*
10279 * Type specific info
10280 */
10281 type_info = &ii->type_info.unknown;
10282 type_info->os_specific_ident = os_specific_ident;
10283
10284 /*
10285 * Compute hash chain for insertion
10286 */
10287 hash_index = ecm_db_iface_generate_hash_index_unknown(os_specific_ident);
10288 ii->hash_index = hash_index;
10289
Murat Sezgin91c5d712015-06-12 15:16:22 -070010290 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10291 ii->iface_id_hash_index = iface_id_hash_index;
10292
Ben Menchaca84f36632014-02-28 20:57:38 +000010293 /*
10294 * Add into the global list
10295 */
10296 spin_lock_bh(&ecm_db_lock);
10297 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10298 ii->prev = NULL;
10299 ii->next = ecm_db_interfaces;
10300 if (ecm_db_interfaces) {
10301 ecm_db_interfaces->prev = ii;
10302 }
10303 ecm_db_interfaces = ii;
10304
10305 /*
10306 * Insert into chain
10307 */
10308 ii->hash_next = ecm_db_iface_table[hash_index];
10309 if (ecm_db_iface_table[hash_index]) {
10310 ecm_db_iface_table[hash_index]->hash_prev = ii;
10311 }
10312 ecm_db_iface_table[hash_index] = ii;
10313 ecm_db_iface_table_lengths[hash_index]++;
10314 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10315
10316 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);
10317
10318 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -070010319 * Insert into interface identifier chain
10320 */
10321 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10322 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10323 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10324 }
10325 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10326 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10327 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]);
10328
10329 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010330 * Set time of addition
10331 */
10332 ii->time_added = ecm_db_time;
10333 spin_unlock_bh(&ecm_db_lock);
10334
10335 /*
10336 * Throw add event to the listeners
10337 */
10338 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10339 li = ecm_db_listeners_get_and_ref_first();
10340 while (li) {
10341 struct ecm_db_listener_instance *lin;
10342 if (li->iface_added) {
10343 li->iface_added(li->arg, ii);
10344 }
10345
10346 /*
10347 * Get next listener
10348 */
10349 lin = ecm_db_listener_get_and_ref_next(li);
10350 ecm_db_listener_deref(li);
10351 li = lin;
10352 }
10353}
10354EXPORT_SYMBOL(ecm_db_iface_add_unknown);
10355
10356/*
10357 * ecm_db_iface_add_loopback()
10358 * Add a iface instance into the database
10359 */
10360void 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 -070010361 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +000010362 ecm_db_iface_final_callback_t final, void *arg)
10363{
10364 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010365 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +000010366 struct ecm_db_listener_instance *li;
10367 struct ecm_db_interface_info_loopback *type_info;
10368
10369 spin_lock_bh(&ecm_db_lock);
10370 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010371#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010372 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010373#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010374 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10375 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10376 spin_unlock_bh(&ecm_db_lock);
10377
10378 /*
10379 * Record general info
10380 */
10381 ii->type = ECM_DB_IFACE_TYPE_LOOPBACK;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010382#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +010010383 ii->state_get = ecm_db_iface_loopback_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010384#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010385 ii->arg = arg;
10386 ii->final = final;
10387 strcpy(ii->name, name);
10388 ii->mtu = mtu;
10389 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010390 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +000010391
10392 /*
10393 * Type specific info
10394 */
10395 type_info = &ii->type_info.loopback;
10396 type_info->os_specific_ident = os_specific_ident;
10397
10398 /*
10399 * Compute hash chain for insertion
10400 */
10401 hash_index = ecm_db_iface_generate_hash_index_loopback(os_specific_ident);
10402 ii->hash_index = hash_index;
10403
Murat Sezgin91c5d712015-06-12 15:16:22 -070010404 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10405 ii->iface_id_hash_index = iface_id_hash_index;
10406
Ben Menchaca84f36632014-02-28 20:57:38 +000010407 /*
10408 * Add into the global list
10409 */
10410 spin_lock_bh(&ecm_db_lock);
10411 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10412 ii->prev = NULL;
10413 ii->next = ecm_db_interfaces;
10414 if (ecm_db_interfaces) {
10415 ecm_db_interfaces->prev = ii;
10416 }
10417 ecm_db_interfaces = ii;
10418
10419 /*
10420 * Insert into chain
10421 */
10422 ii->hash_next = ecm_db_iface_table[hash_index];
10423 if (ecm_db_iface_table[hash_index]) {
10424 ecm_db_iface_table[hash_index]->hash_prev = ii;
10425 }
10426 ecm_db_iface_table[hash_index] = ii;
10427 ecm_db_iface_table_lengths[hash_index]++;
10428 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10429
10430 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);
10431
10432 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -070010433 * Insert into interface identifier chain
10434 */
10435 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10436 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10437 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10438 }
10439 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10440 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10441 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]);
10442
10443 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010444 * Set time of addition
10445 */
10446 ii->time_added = ecm_db_time;
10447 spin_unlock_bh(&ecm_db_lock);
10448
10449 /*
10450 * Throw add event to the listeners
10451 */
10452 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10453 li = ecm_db_listeners_get_and_ref_first();
10454 while (li) {
10455 struct ecm_db_listener_instance *lin;
10456 if (li->iface_added) {
10457 li->iface_added(li->arg, ii);
10458 }
10459
10460 /*
10461 * Get next listener
10462 */
10463 lin = ecm_db_listener_get_and_ref_next(li);
10464 ecm_db_listener_deref(li);
10465 li = lin;
10466 }
10467}
10468EXPORT_SYMBOL(ecm_db_iface_add_loopback);
10469
Murat Sezginbde55f92015-03-11 16:44:11 -070010470#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010471/*
Zhu Ken56477be2014-08-05 17:50:28 +080010472 * ecm_db_iface_sit_daddr_is_null()
10473 * The sit addr is null or not
10474 */
10475bool ecm_db_iface_sit_daddr_is_null(struct ecm_db_iface_instance *ii)
10476{
10477 return ii->type_info.sit.daddr[0] == 0;
10478}
10479EXPORT_SYMBOL(ecm_db_iface_sit_daddr_is_null);
10480
10481/*
Ben Menchaca84f36632014-02-28 20:57:38 +000010482 * ecm_db_iface_add_sit()
10483 * Add a iface instance into the database
10484 */
10485void 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 -070010486 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +000010487 ecm_db_iface_final_callback_t final, void *arg)
10488{
10489 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010490 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +000010491 struct ecm_db_listener_instance *li;
10492
10493 spin_lock_bh(&ecm_db_lock);
10494 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010495#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010496 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010497#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010498 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10499 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10500 spin_unlock_bh(&ecm_db_lock);
10501
10502 /*
10503 * Record general info
10504 */
10505 ii->type = ECM_DB_IFACE_TYPE_SIT;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010506#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +010010507 ii->state_get = ecm_db_iface_sit_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010508#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010509 ii->arg = arg;
10510 ii->final = final;
10511 strcpy(ii->name, name);
10512 ii->mtu = mtu;
10513 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010514 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +000010515
10516 /*
10517 * Type specific info to be copied
10518 */
10519 ii->type_info.sit = *type_info;
10520
10521 /*
10522 * Compute hash chain for insertion
10523 */
10524 hash_index = ecm_db_iface_generate_hash_index_sit(type_info->saddr, type_info->daddr);
10525 ii->hash_index = hash_index;
10526
Murat Sezgin91c5d712015-06-12 15:16:22 -070010527 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10528 ii->iface_id_hash_index = iface_id_hash_index;
10529
Ben Menchaca84f36632014-02-28 20:57:38 +000010530 /*
10531 * Add into the global list
10532 */
10533 spin_lock_bh(&ecm_db_lock);
10534 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10535 ii->prev = NULL;
10536 ii->next = ecm_db_interfaces;
10537 if (ecm_db_interfaces) {
10538 ecm_db_interfaces->prev = ii;
10539 }
10540 ecm_db_interfaces = ii;
10541
10542 /*
10543 * Insert into chain
10544 */
10545 ii->hash_next = ecm_db_iface_table[hash_index];
10546 if (ecm_db_iface_table[hash_index]) {
10547 ecm_db_iface_table[hash_index]->hash_prev = ii;
10548 }
10549 ecm_db_iface_table[hash_index] = ii;
10550 ecm_db_iface_table_lengths[hash_index]++;
10551 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10552
10553 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);
10554
10555 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -070010556 * Insert into interface identifier chain
10557 */
10558 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10559 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10560 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10561 }
10562 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10563 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10564 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]);
10565
10566 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010567 * Set time of addition
10568 */
10569 ii->time_added = ecm_db_time;
10570 spin_unlock_bh(&ecm_db_lock);
10571
10572 /*
10573 * Throw add event to the listeners
10574 */
10575 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10576 li = ecm_db_listeners_get_and_ref_first();
10577 while (li) {
10578 struct ecm_db_listener_instance *lin;
10579 if (li->iface_added) {
10580 li->iface_added(li->arg, ii);
10581 }
10582
10583 /*
10584 * Get next listener
10585 */
10586 lin = ecm_db_listener_get_and_ref_next(li);
10587 ecm_db_listener_deref(li);
10588 li = lin;
10589 }
10590}
10591EXPORT_SYMBOL(ecm_db_iface_add_sit);
Murat Sezginbde55f92015-03-11 16:44:11 -070010592#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010593
Murat Sezginc1402562015-03-12 12:32:20 -070010594#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +000010595#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010596/*
10597 * ecm_db_iface_add_tunipip6()
10598 * Add a iface instance into the database
10599 */
10600void 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 -070010601 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +000010602 ecm_db_iface_final_callback_t final, void *arg)
10603{
10604 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010605 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +000010606 struct ecm_db_listener_instance *li;
10607
10608 spin_lock_bh(&ecm_db_lock);
10609 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010610#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010611 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010612#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010613 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10614 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10615 spin_unlock_bh(&ecm_db_lock);
10616
10617 /*
10618 * Record general info
10619 */
10620 ii->type = ECM_DB_IFACE_TYPE_TUNIPIP6;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010621#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +010010622 ii->state_get = ecm_db_iface_tunipip6_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010623#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010624 ii->arg = arg;
10625 ii->final = final;
10626 strcpy(ii->name, name);
10627 ii->mtu = mtu;
10628 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010629 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +000010630
10631 /*
10632 * Type specific info to be copied
10633 */
10634 ii->type_info.tunipip6 = *type_info;
10635
10636 /*
10637 * Compute hash chain for insertion
10638 */
10639 hash_index = ecm_db_iface_generate_hash_index_tunipip6(type_info->saddr, type_info->daddr);
10640 ii->hash_index = hash_index;
10641
Murat Sezgin91c5d712015-06-12 15:16:22 -070010642 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10643 ii->iface_id_hash_index = iface_id_hash_index;
10644
Ben Menchaca84f36632014-02-28 20:57:38 +000010645 /*
10646 * Add into the global list
10647 */
10648 spin_lock_bh(&ecm_db_lock);
10649 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10650 ii->prev = NULL;
10651 ii->next = ecm_db_interfaces;
10652 if (ecm_db_interfaces) {
10653 ecm_db_interfaces->prev = ii;
10654 }
10655 ecm_db_interfaces = ii;
10656
10657 /*
10658 * Insert into chain
10659 */
10660 ii->hash_next = ecm_db_iface_table[hash_index];
10661 if (ecm_db_iface_table[hash_index]) {
10662 ecm_db_iface_table[hash_index]->hash_prev = ii;
10663 }
10664 ecm_db_iface_table[hash_index] = ii;
10665 ecm_db_iface_table_lengths[hash_index]++;
10666 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10667
10668 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);
10669
10670 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -070010671 * Insert into interface identifier chain
10672 */
10673 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10674 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10675 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10676 }
10677 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10678 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10679 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]);
10680
10681 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010682 * Set time of addition
10683 */
10684 ii->time_added = ecm_db_time;
10685 spin_unlock_bh(&ecm_db_lock);
10686
10687 /*
10688 * Throw add event to the listeners
10689 */
10690 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10691 li = ecm_db_listeners_get_and_ref_first();
10692 while (li) {
10693 struct ecm_db_listener_instance *lin;
10694 if (li->iface_added) {
10695 li->iface_added(li->arg, ii);
10696 }
10697
10698 /*
10699 * Get next listener
10700 */
10701 lin = ecm_db_listener_get_and_ref_next(li);
10702 ecm_db_listener_deref(li);
10703 li = lin;
10704 }
10705}
10706EXPORT_SYMBOL(ecm_db_iface_add_tunipip6);
Murat Sezginc1402562015-03-12 12:32:20 -070010707#endif
Gareth Williams8ac34292015-03-17 14:06:58 +000010708#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010709
Murat Sezgin69a27532015-03-12 14:09:40 -070010710#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010711/*
10712 * ecm_db_iface_add_ipsec_tunnel()
10713 * Add a iface instance into the database
10714 *
10715 * GGG TODO This needs to take ipsec tunnel endpoint information etc. something very appropriate for ipsec tunnels, anyhow.
10716 */
10717void 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 -070010718 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +000010719 ecm_db_iface_final_callback_t final, void *arg)
10720{
10721 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010722 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +000010723 struct ecm_db_listener_instance *li;
10724 struct ecm_db_interface_info_ipsec_tunnel *type_info;
10725
10726 spin_lock_bh(&ecm_db_lock);
10727 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010728#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010729 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010730#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010731 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10732 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10733 spin_unlock_bh(&ecm_db_lock);
10734
10735 /*
10736 * Record general info
10737 */
Ankit Dhanuka60683c52014-06-09 17:43:38 +053010738 ii->type = ECM_DB_IFACE_TYPE_IPSEC_TUNNEL;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010739#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +010010740 ii->state_get = ecm_db_iface_ipsec_tunnel_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010741#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010742 ii->arg = arg;
10743 ii->final = final;
10744 strcpy(ii->name, name);
10745 ii->mtu = mtu;
10746 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010747 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +000010748
10749 /*
10750 * Type specific info
10751 */
10752 type_info = &ii->type_info.ipsec_tunnel;
10753 type_info->os_specific_ident = os_specific_ident;
10754
10755 /*
10756 * Compute hash chain for insertion
10757 */
10758 hash_index = ecm_db_iface_generate_hash_index_ipsec_tunnel(os_specific_ident);
10759 ii->hash_index = hash_index;
10760
Murat Sezgin91c5d712015-06-12 15:16:22 -070010761 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10762 ii->iface_id_hash_index = iface_id_hash_index;
10763
Ben Menchaca84f36632014-02-28 20:57:38 +000010764 /*
10765 * Add into the global list
10766 */
10767 spin_lock_bh(&ecm_db_lock);
10768 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10769 ii->prev = NULL;
10770 ii->next = ecm_db_interfaces;
10771 if (ecm_db_interfaces) {
10772 ecm_db_interfaces->prev = ii;
10773 }
10774 ecm_db_interfaces = ii;
10775
10776 /*
10777 * Insert into chain
10778 */
10779 ii->hash_next = ecm_db_iface_table[hash_index];
10780 if (ecm_db_iface_table[hash_index]) {
10781 ecm_db_iface_table[hash_index]->hash_prev = ii;
10782 }
10783 ecm_db_iface_table[hash_index] = ii;
10784 ecm_db_iface_table_lengths[hash_index]++;
10785 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10786
10787 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);
10788
10789 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -070010790 * Insert into interface identifier chain
10791 */
10792 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10793 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10794 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10795 }
10796 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10797 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10798 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]);
10799
10800 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010801 * Set time of addition
10802 */
10803 ii->time_added = ecm_db_time;
10804 spin_unlock_bh(&ecm_db_lock);
10805
10806 /*
10807 * Throw add event to the listeners
10808 */
10809 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10810 li = ecm_db_listeners_get_and_ref_first();
10811 while (li) {
10812 struct ecm_db_listener_instance *lin;
10813 if (li->iface_added) {
10814 li->iface_added(li->arg, ii);
10815 }
10816
10817 /*
10818 * Get next listener
10819 */
10820 lin = ecm_db_listener_get_and_ref_next(li);
10821 ecm_db_listener_deref(li);
10822 li = lin;
10823 }
10824}
10825EXPORT_SYMBOL(ecm_db_iface_add_ipsec_tunnel);
Murat Sezgin69a27532015-03-12 14:09:40 -070010826#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010827
10828/*
10829 * ecm_db_listener_add()
10830 * Add a listener instance into the database.
10831 */
10832void ecm_db_listener_add(struct ecm_db_listener_instance *li,
10833 ecm_db_iface_listener_added_callback_t iface_added,
10834 ecm_db_iface_listener_removed_callback_t iface_removed,
10835 ecm_db_node_listener_added_callback_t node_added,
10836 ecm_db_node_listener_removed_callback_t node_removed,
10837 ecm_db_host_listener_added_callback_t host_added,
10838 ecm_db_host_listener_removed_callback_t host_removed,
10839 ecm_db_mapping_listener_added_callback_t mapping_added,
10840 ecm_db_mapping_listener_removed_callback_t mapping_removed,
10841 ecm_db_connection_listener_added_callback_t connection_added,
10842 ecm_db_connection_listener_removed_callback_t connection_removed,
10843 ecm_db_listener_final_callback_t final,
10844 void *arg)
10845{
10846 spin_lock_bh(&ecm_db_lock);
10847 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed\n", li);
10848 DEBUG_ASSERT(!(li->flags & ECM_DB_LISTENER_FLAGS_INSERTED), "%p: inserted\n", li);
10849 spin_unlock_bh(&ecm_db_lock);
10850
10851 li->arg = arg;
10852 li->final = final;
10853 li->iface_added = iface_added;
10854 li->iface_removed = iface_removed;
10855 li->node_added = node_added;
10856 li->node_removed = node_removed;
10857 li->host_added = host_added;
10858 li->host_removed = host_removed;
10859 li->mapping_added = mapping_added;
10860 li->mapping_removed = mapping_removed;
10861 li->connection_added = connection_added;
10862 li->connection_removed = connection_removed;
10863
10864 /*
10865 * Add instance into listener list
10866 */
10867 spin_lock_bh(&ecm_db_lock);
10868 li->flags |= ECM_DB_LISTENER_FLAGS_INSERTED;
10869 li->next = ecm_db_listeners;
10870 ecm_db_listeners = li;
10871 spin_unlock_bh(&ecm_db_lock);
10872}
10873EXPORT_SYMBOL(ecm_db_listener_add);
10874
10875/*
10876 * ecm_db_connection_alloc()
10877 * Allocate a connection instance
10878 */
10879struct ecm_db_connection_instance *ecm_db_connection_alloc(void)
10880{
10881 struct ecm_db_connection_instance *ci;
Shyam Sunder3b049ff2015-05-18 20:44:30 +053010882 int __attribute__((unused)) i;
Murat Sezgin66d19912016-09-20 13:55:25 -070010883 unsigned int conn_count;
10884
10885 /*
10886 * If we have exceeded the conntrack connection limit then do not allocate new instance.
10887 */
10888 conn_count = (unsigned int)ecm_db_connection_count_get();
10889 if (conn_count >= nf_conntrack_max) {
10890 DEBUG_WARN("ECM Connection count limit reached: db: %u, ct: %u\n", conn_count, nf_conntrack_max);
10891 return NULL;
10892 }
Ben Menchaca84f36632014-02-28 20:57:38 +000010893
10894 /*
10895 * Allocate the connection
10896 */
10897 ci = (struct ecm_db_connection_instance *)kzalloc(sizeof(struct ecm_db_connection_instance), GFP_ATOMIC | __GFP_NOWARN);
10898 if (!ci) {
10899 DEBUG_WARN("Connection alloc failed\n");
10900 return NULL;
10901 }
10902
10903 /*
10904 * Initialise the defunct timer entry
10905 */
10906 ecm_db_timer_group_entry_init(&ci->defunct_timer, ecm_db_connection_defunct_callback, ci);
10907
10908 /*
10909 * Refs is 1 for the creator of the connection
10910 */
10911 ci->refs = 1;
10912 DEBUG_SET_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC);
10913
10914 /*
Nicolas Costaf46c33b2014-05-15 10:02:00 -050010915 * Initialise the interfaces from/to lists.
10916 * Interfaces are added from end of array.
10917 */
10918 ci->from_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10919 ci->to_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10920 ci->from_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10921 ci->to_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10922
Shyam Sunder3b049ff2015-05-18 20:44:30 +053010923#ifdef ECM_MULTICAST_ENABLE
10924 for (i = 0; i < ECM_DB_MULTICAST_IF_MAX; ++i) {
10925 ci->to_mcast_interface_first[i] = ECM_DB_IFACE_HEIRARCHY_MAX;
10926 }
10927#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -050010928 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010929 * If the master thread is terminating then we cannot create new instances
10930 */
10931 spin_lock_bh(&ecm_db_lock);
10932 if (ecm_db_terminate_pending) {
10933 spin_unlock_bh(&ecm_db_lock);
10934 DEBUG_WARN("Thread terminating\n");
10935 kfree(ci);
10936 return NULL;
10937 }
10938
10939 /*
10940 * Assign runtime unique serial
10941 */
10942 ci->serial = ecm_db_connection_serial++;
10943
Ben Menchaca84f36632014-02-28 20:57:38 +000010944 ecm_db_connection_count++;
10945 DEBUG_ASSERT(ecm_db_connection_count > 0, "%p: connection count wrap\n", ci);
10946 spin_unlock_bh(&ecm_db_lock);
10947
10948 DEBUG_TRACE("Connection created %p\n", ci);
10949 return ci;
10950}
10951EXPORT_SYMBOL(ecm_db_connection_alloc);
10952
10953/*
10954 * ecm_db_mapping_alloc()
10955 * Allocate a mapping instance
10956 */
10957struct ecm_db_mapping_instance *ecm_db_mapping_alloc(void)
10958{
10959 struct ecm_db_mapping_instance *mi;
10960
10961 mi = (struct ecm_db_mapping_instance *)kzalloc(sizeof(struct ecm_db_mapping_instance), GFP_ATOMIC | __GFP_NOWARN);
10962 if (!mi) {
10963 DEBUG_WARN("Alloc failed\n");
10964 return NULL;
10965 }
10966
10967 mi->refs = 1;
10968 DEBUG_SET_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC);
10969
10970 /*
10971 * Alloc operation must be atomic to ensure thread and module can be held
10972 */
10973 spin_lock_bh(&ecm_db_lock);
10974
10975 /*
10976 * If the event processing thread is terminating then we cannot create new instances
10977 */
10978 if (ecm_db_terminate_pending) {
10979 spin_unlock_bh(&ecm_db_lock);
10980 DEBUG_WARN("Thread terminating\n");
10981 kfree(mi);
10982 return NULL;
10983 }
10984
Ben Menchaca84f36632014-02-28 20:57:38 +000010985 ecm_db_mapping_count++;
10986 spin_unlock_bh(&ecm_db_lock);
10987
10988 DEBUG_TRACE("Mapping created %p\n", mi);
10989 return mi;
10990}
10991EXPORT_SYMBOL(ecm_db_mapping_alloc);
10992
Ben Menchaca84f36632014-02-28 20:57:38 +000010993/*
10994 * ecm_db_host_alloc()
10995 * Allocate a host instance
10996 */
10997struct ecm_db_host_instance *ecm_db_host_alloc(void)
10998{
10999 struct ecm_db_host_instance *hi;
11000 hi = (struct ecm_db_host_instance *)kzalloc(sizeof(struct ecm_db_host_instance), GFP_ATOMIC | __GFP_NOWARN);
11001 if (!hi) {
11002 DEBUG_WARN("Alloc failed\n");
11003 return NULL;
11004 }
11005
11006 hi->refs = 1;
11007 DEBUG_SET_MAGIC(hi, ECM_DB_HOST_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(hi);
11021 return NULL;
11022 }
11023
Ben Menchaca84f36632014-02-28 20:57:38 +000011024 ecm_db_host_count++;
11025 spin_unlock_bh(&ecm_db_lock);
11026
11027 DEBUG_TRACE("Host created %p\n", hi);
11028 return hi;
11029}
11030EXPORT_SYMBOL(ecm_db_host_alloc);
11031
11032/*
11033 * ecm_db_node_alloc()
11034 * Allocate a node instance
11035 */
11036struct ecm_db_node_instance *ecm_db_node_alloc(void)
11037{
11038 struct ecm_db_node_instance *ni;
11039
11040 ni = (struct ecm_db_node_instance *)kzalloc(sizeof(struct ecm_db_node_instance), GFP_ATOMIC | __GFP_NOWARN);
11041 if (!ni) {
11042 DEBUG_WARN("Alloc failed\n");
11043 return NULL;
11044 }
11045
11046 ni->refs = 1;
11047 DEBUG_SET_MAGIC(ni, ECM_DB_NODE_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(ni);
11061 return NULL;
11062 }
11063
Ben Menchaca84f36632014-02-28 20:57:38 +000011064 ecm_db_node_count++;
11065 spin_unlock_bh(&ecm_db_lock);
11066
11067 DEBUG_TRACE("Node created %p\n", ni);
11068 return ni;
11069}
11070EXPORT_SYMBOL(ecm_db_node_alloc);
11071
11072/*
11073 * ecm_db_iface_alloc()
11074 * Allocate a iface instance
11075 */
11076struct ecm_db_iface_instance *ecm_db_iface_alloc(void)
11077{
11078 struct ecm_db_iface_instance *ii;
11079
11080 ii = (struct ecm_db_iface_instance *)kzalloc(sizeof(struct ecm_db_iface_instance), GFP_ATOMIC | __GFP_NOWARN);
11081 if (!ii) {
11082 DEBUG_WARN("Alloc failed\n");
11083 return NULL;
11084 }
11085
11086 ii->refs = 1;
11087 DEBUG_SET_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC);
11088
11089 /*
11090 * Alloc operation must be atomic to ensure thread and module can be held
11091 */
11092 spin_lock_bh(&ecm_db_lock);
11093
11094 /*
11095 * If the event processing thread is terminating then we cannot create new instances
11096 */
11097 if (ecm_db_terminate_pending) {
11098 spin_unlock_bh(&ecm_db_lock);
11099 DEBUG_WARN("Thread terminating\n");
11100 kfree(ii);
11101 return NULL;
11102 }
11103
Ben Menchaca84f36632014-02-28 20:57:38 +000011104 ecm_db_iface_count++;
11105 spin_unlock_bh(&ecm_db_lock);
11106
11107 DEBUG_TRACE("iface created %p\n", ii);
11108 return ii;
11109}
11110EXPORT_SYMBOL(ecm_db_iface_alloc);
11111
11112/*
11113 * ecm_db_listener_alloc()
11114 * Allocate a listener instance
11115 */
11116struct ecm_db_listener_instance *ecm_db_listener_alloc(void)
11117{
11118 struct ecm_db_listener_instance *li;
11119
11120 li = (struct ecm_db_listener_instance *)kzalloc(sizeof(struct ecm_db_listener_instance), GFP_ATOMIC | __GFP_NOWARN);
11121 if (!li) {
11122 DEBUG_WARN("Alloc failed\n");
11123 return NULL;
11124 }
11125
11126 li->refs = 1;
11127 DEBUG_SET_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC);
11128
11129 /*
11130 * Alloc operation must be atomic to ensure thread and module can be held
11131 */
11132 spin_lock_bh(&ecm_db_lock);
11133
11134 /*
11135 * If the event processing thread is terminating then we cannot create new instances
11136 */
11137 if (ecm_db_terminate_pending) {
11138 spin_unlock_bh(&ecm_db_lock);
11139 DEBUG_WARN("Thread terminating\n");
11140 kfree(li);
11141 return NULL;
11142 }
11143
Ben Menchaca84f36632014-02-28 20:57:38 +000011144 ecm_db_listeners_count++;
11145 DEBUG_ASSERT(ecm_db_listeners_count > 0, "%p: listener count wrap\n", li);
Nicolas Costaf46c33b2014-05-15 10:02:00 -050011146 spin_unlock_bh(&ecm_db_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +000011147
11148 DEBUG_TRACE("Listener created %p\n", li);
Ben Menchaca84f36632014-02-28 20:57:38 +000011149 return li;
11150}
11151EXPORT_SYMBOL(ecm_db_listener_alloc);
11152
Shyam Sunder1f037262015-05-18 20:04:13 +053011153#ifdef ECM_MULTICAST_ENABLE
11154/*
11155 * _ecm_db_multicast_tuple_instance_ref()
11156 * Increment tuple reference count by one
11157 */
11158static void _ecm_db_multicast_tuple_instance_ref(struct ecm_db_multicast_tuple_instance *ti)
11159{
11160 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
11161 ti->refs++;
11162 DEBUG_TRACE("%p: ti ref %d\n", ti, ti->refs);
11163 DEBUG_ASSERT(ti->refs > 0, "%p: ref wrap\n", ti)
11164}
11165
11166/*
11167 * ecm_db_multicast_alloc_connection()
11168 * Allocate memory for the connection structure.
11169 */
11170struct 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)
11171{
11172 struct ecm_db_multicast_tuple_instance *ti;
11173 ti = (struct ecm_db_multicast_tuple_instance *)kzalloc(sizeof(struct ecm_db_multicast_tuple_instance), GFP_ATOMIC | __GFP_NOWARN);
11174 if (!ti) {
11175 DEBUG_WARN("ti: Alloc failed\n");
11176 return NULL;
11177 }
11178 ti->src_port = src_port;
11179 ti->dst_port = dst_port;
11180 ECM_IP_ADDR_COPY(ti->src_ip, origin);
11181 ECM_IP_ADDR_COPY(ti->grp_ip, group);
11182 ti->proto = IPPROTO_UDP;
11183 ti->hash_index = ecm_db_multicast_generate_hash_index(group);
11184 ti->flags = 0;
11185 ti->refs = 1;
11186 ti->next = NULL;
11187 ti->prev = NULL;
11188 DEBUG_SET_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC);
11189
11190 return ti;
11191}
11192EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_alloc);
11193
11194/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053011195 * ecm_db_multicast_connection_find_and_ref()
Shyam Sunder1f037262015-05-18 20:04:13 +053011196 * Called by MFC event update to fetch connection from the table
Shyam Sunder3af86a52015-08-28 18:04:10 +053011197 * This function takes a ref count for both tuple_instance and 'ci'
11198 * Call ecm_db_multicast_connection_deref function for deref both
11199 * 'ti' and 'ci'
Shyam Sunder1f037262015-05-18 20:04:13 +053011200 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053011201struct 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 +053011202{
11203 ecm_db_multicast_tuple_instance_hash_t hash_index;
11204 struct ecm_db_multicast_tuple_instance *ti;
11205
11206 /*
11207 * Compute the hash chain index
11208 */
11209 hash_index = ecm_db_multicast_generate_hash_index(group);
11210
11211 spin_lock_bh(&ecm_db_lock);
11212 ti = ecm_db_multicast_tuple_instance_table[hash_index];
11213
11214 /*
11215 * Traverse through the list and find the ti
11216 */
11217 while (ti) {
11218 if (!(ECM_IP_ADDR_MATCH(ti->src_ip, origin) && ECM_IP_ADDR_MATCH(ti->grp_ip, group))) {
11219 ti = ti->next;
11220 continue;
11221 }
11222
11223 _ecm_db_multicast_tuple_instance_ref(ti);
Shyam Sunder3af86a52015-08-28 18:04:10 +053011224 _ecm_db_connection_ref(ti->ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053011225 spin_unlock_bh(&ecm_db_lock);
11226 DEBUG_TRACE("multicast tuple instance found %p\n", ti);
11227 return ti;
11228 }
11229
11230 spin_unlock_bh(&ecm_db_lock);
11231 DEBUG_TRACE("multicast tuple instance not found\n");
11232 return NULL;
11233}
Shyam Sunder3af86a52015-08-28 18:04:10 +053011234EXPORT_SYMBOL(ecm_db_multicast_connection_find_and_ref);
Shyam Sunder1f037262015-05-18 20:04:13 +053011235
11236/*
11237 * ecm_db_multicast_tuple_instance_deref()
11238 * Deref the reference count or
Shyam Sunder3af86a52015-08-28 18:04:10 +053011239 * Free the tuple_instance struct, when the multicast connection dies
Shyam Sunder1f037262015-05-18 20:04:13 +053011240 */
11241int ecm_db_multicast_tuple_instance_deref(struct ecm_db_multicast_tuple_instance *ti)
11242{
Shyam Sunder317ca912016-01-22 16:51:28 +053011243 int refs;
Shyam Sunder1f037262015-05-18 20:04:13 +053011244 spin_lock_bh(&ecm_db_lock);
Shyam Sunder317ca912016-01-22 16:51:28 +053011245 refs = _ecm_db_multicast_tuple_instance_deref(ti);
Shyam Sunder1f037262015-05-18 20:04:13 +053011246 spin_unlock_bh(&ecm_db_lock);
Shyam Sunder317ca912016-01-22 16:51:28 +053011247 return refs;
Shyam Sunder1f037262015-05-18 20:04:13 +053011248}
11249EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_deref);
11250
11251/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053011252 * ecm_db_multicast_connection_deref()
11253 * Deref both 'ti' and 'ci'
11254 * call this function after ecm_db_multicast_connection_find_and_ref()
11255 */
11256void ecm_db_multicast_connection_deref(struct ecm_db_multicast_tuple_instance *ti)
11257{
11258 struct ecm_db_connection_instance *ci;
11259 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
11260
11261 ci = ti->ci;
11262 ecm_db_multicast_tuple_instance_deref(ti);
11263 ecm_db_connection_deref(ci);
11264
11265}
11266EXPORT_SYMBOL(ecm_db_multicast_connection_deref);
11267
11268/*
Shyam Sunder1f037262015-05-18 20:04:13 +053011269 * ecm_db_multicast_tuple_instance_add()
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011270 * Add the tuple instance into the hash table. Also, attach the tuple instance
11271 * with connection instance.
11272 *
Shyam Sunder1f037262015-05-18 20:04:13 +053011273 * Note: This function takes a reference count and caller has to also call
11274 * ecm_db_multicast_tuple_instance_deref() after this function.
11275 */
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011276void 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 +053011277{
11278 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
11279
11280 spin_lock_bh(&ecm_db_lock);
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011281 DEBUG_ASSERT(!(ti->flags & ECM_DB_MULTICAST_TUPLE_INSTANCE_FLAGS_INSERTED), "%p: inserted\n", ti);
11282
11283 /*
11284 * Attach the multicast tuple instance with the connection instance
11285 */
11286 ci->ti = ti;
Shyam Sunder3af86a52015-08-28 18:04:10 +053011287 ti->ci = ci;
Shyam Sunder1f037262015-05-18 20:04:13 +053011288
11289 /*
11290 * Take a local reference to ti
11291 */
11292 _ecm_db_multicast_tuple_instance_ref(ti);
11293 ti->next = ecm_db_multicast_tuple_instance_table[ti->hash_index];
11294 if (ecm_db_multicast_tuple_instance_table[ti->hash_index]) {
11295 ecm_db_multicast_tuple_instance_table[ti->hash_index]->prev = ti;
11296 }
11297
11298 ecm_db_multicast_tuple_instance_table[ti->hash_index] = ti;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011299
11300 ti->flags |= ECM_DB_MULTICAST_TUPLE_INSTANCE_FLAGS_INSERTED;
Shyam Sunder1f037262015-05-18 20:04:13 +053011301 spin_unlock_bh(&ecm_db_lock);
11302
11303}
11304EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_add);
11305
11306/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053011307 * ecm_db_multicast_connection_get_and_ref_first()
Shyam Sunder1f037262015-05-18 20:04:13 +053011308 * Return the first tuple instance from the table when given a group
Shyam Sunder3af86a52015-08-28 18:04:10 +053011309 * Also take a ref count for 'ci', once done call ecm_db_multicast_connection_deref()
11310 * to deref both 'ti' and 'ci'
Shyam Sunder1f037262015-05-18 20:04:13 +053011311 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053011312struct ecm_db_multicast_tuple_instance *ecm_db_multicast_connection_get_and_ref_first(ip_addr_t group)
Shyam Sunder1f037262015-05-18 20:04:13 +053011313{
11314 ecm_db_multicast_tuple_instance_hash_t hash_index;
11315 struct ecm_db_multicast_tuple_instance *ti;
11316
11317 hash_index = ecm_db_multicast_generate_hash_index(group);
11318
11319 spin_lock_bh(&ecm_db_lock);
11320 ti = ecm_db_multicast_tuple_instance_table[hash_index];
11321 if (ti) {
11322 _ecm_db_multicast_tuple_instance_ref(ti);
Shyam Sunder3af86a52015-08-28 18:04:10 +053011323 _ecm_db_connection_ref(ti->ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053011324 }
11325 spin_unlock_bh(&ecm_db_lock);
11326
11327 return ti;
11328}
Shyam Sunder3af86a52015-08-28 18:04:10 +053011329EXPORT_SYMBOL(ecm_db_multicast_connection_get_and_ref_first);
Shyam Sunder1f037262015-05-18 20:04:13 +053011330
11331/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053011332 * ecm_db_multicast_connection_get_and_ref_next()
11333 * Return the next tuple instance node and
11334 * take a ref count for 'ci', once done call ecm_db_multicast_connection_deref()
11335 * to deref both 'ti' and 'ci'
Shyam Sunder1f037262015-05-18 20:04:13 +053011336 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053011337struct 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 +053011338{
11339 struct ecm_db_multicast_tuple_instance *tin;
11340 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
11341 spin_lock_bh(&ecm_db_lock);
11342 tin = ti->next;
11343 if (tin) {
11344 _ecm_db_multicast_tuple_instance_ref(tin);
Shyam Sunder3af86a52015-08-28 18:04:10 +053011345 _ecm_db_connection_ref(tin->ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053011346 }
11347 spin_unlock_bh(&ecm_db_lock);
11348 return tin;
11349}
Shyam Sunder3af86a52015-08-28 18:04:10 +053011350EXPORT_SYMBOL(ecm_db_multicast_connection_get_and_ref_next);
Shyam Sunder1f037262015-05-18 20:04:13 +053011351
11352/*
11353 * ecm_db_multicast_tuple_instance_source_ip_get()
11354 * This function return the source IP for a connection object
11355 */
11356void ecm_db_multicast_tuple_instance_source_ip_get(struct ecm_db_multicast_tuple_instance *ti, ip_addr_t origin)
11357{
11358 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
11359 ECM_IP_ADDR_COPY(origin, ti->src_ip);
11360}
11361EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_source_ip_get);
11362
11363/*
Shyam Sunderf34c25b2015-06-11 21:14:50 +053011364 * ecm_db_multicast_tuple_instance_group_ip_get()
11365 * This function return the group IP for a connection object
11366 */
11367void ecm_db_multicast_tuple_instance_group_ip_get(struct ecm_db_multicast_tuple_instance *ti, ip_addr_t group)
11368{
11369 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
11370 ECM_IP_ADDR_COPY(group, ti->grp_ip);
11371}
11372EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_group_ip_get);
11373
11374/*
Shyam Sunder1f037262015-05-18 20:04:13 +053011375 * ecm_db_multicast_tuple_instance_flags_get()
11376 * Return flags related to Multicast connection
11377 */
11378uint32_t ecm_db_multicast_tuple_instance_flags_get(struct ecm_db_multicast_tuple_instance *ti)
11379{
11380 uint32_t flags;
11381
11382 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed\n", ti);
11383 spin_lock_bh(&ecm_db_lock);
11384 flags = ti->flags;
11385 spin_unlock_bh(&ecm_db_lock);
11386 return flags;
11387}
11388EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_flags_get);
11389
11390/*
11391 * ecm_db_multicast_tuple_instance_flags_set()
11392 * Set the multicast connection flags
11393 */
11394void ecm_db_multicast_tuple_instance_flags_set(struct ecm_db_multicast_tuple_instance *ti, uint32_t flags)
11395{
11396 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed\n", ti);
11397
11398 spin_lock_bh(&ecm_db_lock);
11399 ti->flags |= flags;
11400 spin_unlock_bh(&ecm_db_lock);
11401}
11402EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_flags_set);
11403
11404/*
11405 * ecm_db_multicast_tuple_instance_flags_clear()
11406 * Clear the multicast connection flags
11407 */
11408void ecm_db_multicast_tuple_instance_flags_clear(struct ecm_db_multicast_tuple_instance *ti, uint32_t flags)
11409{
11410 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed\n", ti);
11411
11412 spin_lock_bh(&ecm_db_lock);
11413 ti->flags &= ~flags;
11414 spin_unlock_bh(&ecm_db_lock);
11415}
11416EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_flags_clear);
11417
11418/*
11419 * ecm_db_multicast_connection_to_interfaces_get_and_ref_all()
11420 * Return the list of multicast destination interface heirarchies to which this connection is established.
11421 * The function returns the heirarchies using the 'interface' pointer passed to it. It also returns the first
11422 * index in the interface heirarchy for each of the heirarchies using the 'ifaces_first' pointer.
11423 *
11424 * NOTE: This function allocates the memory for the destination interface heirachy. This memory is expected to be
11425 * freed only by making a call to ecm_db_multicast_connection_interfaces_deref_all().
11426 *
11427 * The size of the buffer allocated for the heirarchies and pointed to by 'interfaces' is as large as
11428 * sizeof(struct ecm_db_iface_instance *) * ECM_DB_MULTICAST_IF_MAX * ECM_DB_IFACE_HEIRARCHY_MAX.
11429 * Returns the number of interface heirarchies in the list as a return value.
11430 *
11431 * Each interface is referenced on return, be sure to release them using ecm_db_multicast_connection_interfaces_deref_all().
11432 */
11433int32_t ecm_db_multicast_connection_to_interfaces_get_and_ref_all(struct ecm_db_connection_instance *ci,
11434 struct ecm_db_iface_instance **interfaces, int32_t **ifaces_first)
11435{
11436 struct ecm_db_iface_instance *heirarchy_base;
11437 struct ecm_db_iface_instance *heirarchy_temp;
11438 struct ecm_db_iface_instance *ii_single;
11439 struct ecm_db_iface_instance **ifaces;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011440 struct ecm_db_iface_instance *ii_db;
11441 struct ecm_db_iface_instance *ii_db_single;
11442 struct ecm_db_iface_instance **ifaces_db;
Shyam Sunder1f037262015-05-18 20:04:13 +053011443 int32_t *ii_first_base;
11444 int32_t *ii_first;
11445 int32_t heirarchy_index;
11446 int32_t ii_index;
11447 int32_t if_count = 0;
11448
11449 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
11450
11451 heirarchy_base = (struct ecm_db_iface_instance *)kzalloc(ECM_DB_TO_MCAST_INTERFACES_SIZE, GFP_ATOMIC | __GFP_NOWARN);
11452 if (!heirarchy_base) {
11453 DEBUG_WARN("%p: No memory for interface hierarchies \n", ci);
11454 return if_count;
11455 }
11456
11457 ii_first_base = (int32_t *)kzalloc(sizeof(int32_t *) * ECM_DB_MULTICAST_IF_MAX, GFP_ATOMIC | __GFP_NOWARN);
11458 if (!ii_first_base) {
11459 DEBUG_WARN("%p: No memory for first interface \n", ci);
11460 kfree(heirarchy_base);
11461 return if_count;
11462 }
11463
11464 spin_lock_bh(&ecm_db_lock);
11465 if (!ci->to_mcast_interfaces_set) {
11466 spin_unlock_bh(&ecm_db_lock);
11467 kfree(ii_first_base);
11468 kfree(heirarchy_base);
11469 return if_count;
11470 }
11471
11472 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
11473
11474 heirarchy_temp = ecm_db_multicast_if_heirarchy_get(heirarchy_base, heirarchy_index);
11475
11476 if (ci->to_mcast_interface_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
11477 if_count++;
11478 }
11479
11480 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 +053011481 ii_db = ecm_db_multicast_if_heirarchy_get(ci->to_mcast_interfaces, heirarchy_index);
11482 ii_db_single = ecm_db_multicast_if_instance_get_at_index(ii_db, ii_index);
11483 ifaces_db = (struct ecm_db_iface_instance **)ii_db_single;
Shyam Sunder1f037262015-05-18 20:04:13 +053011484
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011485 /*
11486 * Take a reference count
11487 */
11488 _ecm_db_iface_ref(*ifaces_db);
11489
Shyam Sunder1f037262015-05-18 20:04:13 +053011490 ii_single = ecm_db_multicast_if_instance_get_at_index(heirarchy_temp, ii_index);
11491 ifaces = (struct ecm_db_iface_instance **)ii_single;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011492 *ifaces = *ifaces_db;
Shyam Sunder1f037262015-05-18 20:04:13 +053011493 }
11494
11495 ii_first = ecm_db_multicast_if_first_get_at_index(ii_first_base, heirarchy_index);
11496 *ii_first = ci->to_mcast_interface_first[heirarchy_index];
11497 }
11498
11499 *interfaces = heirarchy_base;
11500 *ifaces_first = ii_first_base;
11501
11502 spin_unlock_bh(&ecm_db_lock);
11503 return if_count;
11504}
11505EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_get_and_ref_all);
11506
11507/*
11508 * ecm_db_multicast_connection_to_interfaces_set_check()
11509 * Returns true if the multicast destination interfaces list has been set.
11510 */
11511bool ecm_db_multicast_connection_to_interfaces_set_check(struct ecm_db_connection_instance *ci)
11512{
11513 bool set;
11514
11515 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
11516 spin_lock_bh(&ecm_db_lock);
11517 set = ci->to_mcast_interfaces_set;
11518 spin_unlock_bh(&ecm_db_lock);
11519 return set;
11520}
11521EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_set_check);
11522
11523/*
11524 * ecm_db_multicast_connection_to_interfaces_set_clear()
11525 * Clear the to_mcast_interfaces_set flag if the multicast destination interfaces list has been freed.
11526 */
11527static void _ecm_db_multicast_connection_to_interfaces_set_clear(struct ecm_db_connection_instance *ci)
11528{
11529 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053011530 ci->to_mcast_interfaces_set = false;
Shyam Sunder1f037262015-05-18 20:04:13 +053011531}
11532
11533/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053011534 * ecm_db_multicast_connection_get_from_tuple()
Shyam Sunder1f037262015-05-18 20:04:13 +053011535 * Return the connection instance
11536 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053011537struct 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 +053011538{
Shyam Sunder3af86a52015-08-28 18:04:10 +053011539 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
11540 DEBUG_ASSERT(ti->ci, "%p: Bad multicast connection instance \n", ti);
11541
11542 return ti->ci;
Shyam Sunder1f037262015-05-18 20:04:13 +053011543}
Shyam Sunder3af86a52015-08-28 18:04:10 +053011544EXPORT_SYMBOL(ecm_db_multicast_connection_get_from_tuple);
Shyam Sunder1f037262015-05-18 20:04:13 +053011545
11546/*
11547 * ecm_db_multicast_connection_to_interfaces_deref_all()
11548 * Deref all destination multicast interface heirarchies at once
11549 */
11550void ecm_db_multicast_connection_to_interfaces_deref_all(struct ecm_db_iface_instance *interfaces, int32_t *ifaces_first)
11551{
11552 struct ecm_db_iface_instance *ifaces_single;
11553 struct ecm_db_iface_instance *ii_temp[ECM_DB_IFACE_HEIRARCHY_MAX];
11554 int32_t *to_first;
11555 int heirarchy_index;
Shyam Sunder1f037262015-05-18 20:04:13 +053011556 DEBUG_ASSERT(interfaces, "Bad memory, multicast interfaces list has been already freed\n");
11557 DEBUG_ASSERT(ifaces_first, "Bad memory, multicast interfaces first has been already freed\n");
11558
11559 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
11560 to_first = ecm_db_multicast_if_first_get_at_index(ifaces_first, heirarchy_index);
11561 if (*to_first < ECM_DB_IFACE_HEIRARCHY_MAX) {
11562 ifaces_single = ecm_db_multicast_if_heirarchy_get(interfaces, heirarchy_index);
11563 ecm_db_multicast_copy_if_heirarchy(ii_temp, ifaces_single);
11564 ecm_db_connection_interfaces_deref(ii_temp, *to_first);
11565 }
11566 }
11567
11568 /*
11569 * Free the temporary memory allocated by ecm_db_multicast_connection_to_interfaces_get_and_ref_all()
11570 */
11571 kfree(interfaces);
11572 kfree(ifaces_first);
11573
11574}
11575EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_deref_all);
11576
11577/*
11578 * _ecm_db_multicast_connection_to_interface_first_is_valid()
11579 * Check if destnation interfaces first list uphold a valid interface
11580 * first or all entries have discarded.
11581 */
11582static bool _ecm_db_multicast_connection_to_interface_first_is_valid(int32_t ifaces_first[])
11583{
11584 int heirarchy_index;
11585
11586 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
11587 if (ifaces_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
11588 return true;
11589 }
11590 }
11591
11592 return false;
11593}
11594
11595/*
11596 * ecm_db_multicast_connection_to_interfaces_clear_at_index()
11597 * Dereference and clear a interface heirarchy at 'index' position
11598 */
11599void ecm_db_multicast_connection_to_interfaces_clear_at_index(struct ecm_db_connection_instance *ci, uint32_t index)
11600{
11601 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011602 struct ecm_db_iface_instance *ifaces_db_single;
Shyam Sunder1f037262015-05-18 20:04:13 +053011603 int32_t discard_first;
Shyam Sunder1f037262015-05-18 20:04:13 +053011604
11605 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
11606
11607 /*
11608 * Invalid Index Value
11609 */
11610 DEBUG_ASSERT((index < ECM_DB_MULTICAST_IF_MAX), "%p: Invalid index for multicast interface heirarchies list %u\n", ci, index);
11611
11612 spin_lock_bh(&ecm_db_lock);
11613 if (ci->to_mcast_interface_first[index] == ECM_DB_IFACE_HEIRARCHY_MAX) {
11614 spin_unlock_bh(&ecm_db_lock);
11615 return;
11616 }
11617
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011618 ifaces_db_single = ecm_db_multicast_if_heirarchy_get(ci->to_mcast_interfaces, index);
11619 ecm_db_multicast_copy_if_heirarchy(discard, ifaces_db_single);
Shyam Sunder1f037262015-05-18 20:04:13 +053011620
11621 discard_first = ci->to_mcast_interface_first[index];
11622 ci->to_mcast_interface_first[index] = ECM_DB_IFACE_HEIRARCHY_MAX;
11623
11624 /*
11625 * If this is the only valid interface hierarchy left in the list of destination
11626 * interface hierarchies then clear the ci->to_mcast_interfaces_set flag here before
11627 * deleting this.
11628 */
11629 if (!_ecm_db_multicast_connection_to_interface_first_is_valid(ci->to_mcast_interface_first)) {
11630 ci->to_mcast_interfaces_set = false;
11631 }
11632
11633 spin_unlock_bh(&ecm_db_lock);
11634
11635 ecm_db_connection_interfaces_deref(discard, discard_first);
11636}
11637EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_clear_at_index);
11638
11639/*
11640 * ecm_db_multicast_connection_to_interfaces_clear()
11641 * Deref and clear all destination multicast interface heirarchies
11642 */
11643void ecm_db_multicast_connection_to_interfaces_clear(struct ecm_db_connection_instance *ci)
11644{
11645 int heirarchy_index;
11646 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
11647
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011648 spin_lock_bh(&ecm_db_lock);
11649 if (!ci->to_mcast_interfaces) {
11650 spin_unlock_bh(&ecm_db_lock);
11651 return;
11652 }
11653
Shyam Sunder1f037262015-05-18 20:04:13 +053011654 _ecm_db_multicast_connection_to_interfaces_set_clear(ci);
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011655 spin_unlock_bh(&ecm_db_lock);
11656
Shyam Sunder1f037262015-05-18 20:04:13 +053011657 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
11658 ecm_db_multicast_connection_to_interfaces_clear_at_index(ci, heirarchy_index);
11659 }
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011660
11661 kfree(ci->to_mcast_interfaces);
11662 ci->to_mcast_interfaces = NULL;
Shyam Sunder1f037262015-05-18 20:04:13 +053011663}
11664EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_clear);
11665#endif
11666
Ben Menchaca84f36632014-02-28 20:57:38 +000011667/*
11668 * ecm_db_time_get()
11669 * Return database time, in seconds since the database started.
11670 */
11671uint32_t ecm_db_time_get(void)
11672{
11673 uint32_t time_now;
11674 spin_lock_bh(&ecm_db_lock);
11675 time_now = ecm_db_time;
11676 spin_unlock_bh(&ecm_db_lock);
11677 return time_now;
11678}
11679EXPORT_SYMBOL(ecm_db_time_get);
11680
11681/*
Ben Menchaca84f36632014-02-28 20:57:38 +000011682 * ecm_db_get_defunct_all()
11683 * Reading this file returns the accumulated total of all objects
11684 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011685static ssize_t ecm_db_get_defunct_all(struct file *file,
11686 char __user *user_buf,
11687 size_t sz, loff_t *ppos)
Ben Menchaca84f36632014-02-28 20:57:38 +000011688{
Murat Sezgin908ecb32015-05-10 20:54:36 -070011689 int ret;
Ben Menchaca84f36632014-02-28 20:57:38 +000011690 int num;
Murat Sezgin908ecb32015-05-10 20:54:36 -070011691 char *buf;
11692
11693 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
11694 if (!buf) {
11695 return -ENOMEM;
11696 }
Ben Menchaca84f36632014-02-28 20:57:38 +000011697
11698 /*
11699 * Operate under our locks
11700 */
11701 spin_lock_bh(&ecm_db_lock);
11702 num = ecm_db_connection_count + ecm_db_mapping_count + ecm_db_host_count
11703 + ecm_db_node_count + ecm_db_iface_count;
11704 spin_unlock_bh(&ecm_db_lock);
11705
Murat Sezgin908ecb32015-05-10 20:54:36 -070011706 ret = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
11707 if (ret < 0) {
11708 kfree(buf);
11709 return ret;
11710 }
11711
11712 ret = simple_read_from_buffer(user_buf, sz, ppos, buf, ret);
11713 kfree(buf);
11714 return ret;
Ben Menchaca84f36632014-02-28 20:57:38 +000011715}
11716
11717/*
11718 * ecm_db_set_defunct_all()
11719 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011720static ssize_t ecm_db_set_defunct_all(struct file *file,
11721 const char __user *user_buf,
11722 size_t sz, loff_t *ppos)
Ben Menchaca84f36632014-02-28 20:57:38 +000011723{
11724 ecm_db_connection_defunct_all();
Murat Sezgin908ecb32015-05-10 20:54:36 -070011725 return sz;
Ben Menchaca84f36632014-02-28 20:57:38 +000011726}
11727
11728/*
Murat Sezgin908ecb32015-05-10 20:54:36 -070011729 * File operations for defunct_all.
11730 */
11731static struct file_operations ecm_db_defunct_all_fops = {
11732 .read = ecm_db_get_defunct_all,
11733 .write = ecm_db_set_defunct_all,
11734};
11735
11736/*
Ben Menchaca84f36632014-02-28 20:57:38 +000011737 * ecm_db_get_connection_counts_simple()
11738 * Return total of connections for each simple protocol (tcp, udp, other). Primarily for use by the luci-bwc service.
11739 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011740static ssize_t ecm_db_get_connection_counts_simple(struct file *file,
11741 char __user *user_buf,
11742 size_t sz, loff_t *ppos)
Ben Menchaca84f36632014-02-28 20:57:38 +000011743{
11744 int tcp_count;
11745 int udp_count;
11746 int other_count;
11747 int total_count;
Murat Sezgin908ecb32015-05-10 20:54:36 -070011748 int ret;
11749 char *buf;
11750
11751 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
11752 if (!buf) {
11753 return -ENOMEM;
11754 }
Ben Menchaca84f36632014-02-28 20:57:38 +000011755
11756 /*
11757 * Get snapshot of the protocol counts
11758 */
11759 spin_lock_bh(&ecm_db_lock);
11760 tcp_count = ecm_db_connection_count_by_protocol[IPPROTO_TCP];
11761 udp_count = ecm_db_connection_count_by_protocol[IPPROTO_UDP];
11762 total_count = ecm_db_connection_count;
11763 other_count = total_count - (tcp_count + udp_count);
11764 spin_unlock_bh(&ecm_db_lock);
11765
Murat Sezgin908ecb32015-05-10 20:54:36 -070011766 ret = snprintf(buf, (ssize_t)PAGE_SIZE, "tcp %d udp %d other %d total %d\n", tcp_count, udp_count, other_count, total_count);
11767 if (ret < 0) {
11768 kfree(buf);
11769 return -EFAULT;
11770 }
11771
11772 ret = simple_read_from_buffer(user_buf, sz, ppos, buf, ret);
11773 kfree(buf);
11774 return ret;
Ben Menchaca84f36632014-02-28 20:57:38 +000011775}
11776
Ben Menchaca84f36632014-02-28 20:57:38 +000011777/*
Murat Sezgin908ecb32015-05-10 20:54:36 -070011778 * File operations for simple connection counts.
Ben Menchaca84f36632014-02-28 20:57:38 +000011779 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011780static struct file_operations ecm_db_connection_count_simple_fops = {
11781 .read = ecm_db_get_connection_counts_simple,
Ben Menchaca84f36632014-02-28 20:57:38 +000011782};
11783
11784/*
Ben Menchaca84f36632014-02-28 20:57:38 +000011785 * ecm_db_timer_callback()
11786 * Manage expiration of connections
11787 * NOTE: This is softirq context
11788 */
11789static void ecm_db_timer_callback(unsigned long data)
11790{
11791 uint32_t timer;
11792
11793 /*
11794 * Increment timer.
11795 */
11796 spin_lock_bh(&ecm_db_lock);
11797 timer = ++ecm_db_time;
11798 spin_unlock_bh(&ecm_db_lock);
11799 DEBUG_TRACE("Garbage timer tick %d\n", timer);
11800
11801 /*
11802 * Check timer groups
11803 */
11804 ecm_db_timer_groups_check(timer);
11805
11806 /*
11807 * Set the timer for the next second
11808 */
11809 ecm_db_timer.expires += HZ;
11810 if (ecm_db_timer.expires <= jiffies) {
11811 DEBUG_WARN("losing time %lu, jiffies = %lu\n", ecm_db_timer.expires, jiffies);
11812 ecm_db_timer.expires = jiffies + HZ;
11813 }
11814 add_timer(&ecm_db_timer);
11815}
Gareth Williamsd5618a82015-05-20 11:13:32 +010011816#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000011817/*
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011818 * ecm_db_node_from_connections_get_and_ref_first()
11819 * Obtain a ref to the first connection instance of "from list" of node, if any
11820 */
11821static inline struct ecm_db_connection_instance *ecm_db_node_from_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11822{
11823 struct ecm_db_connection_instance *ci;
11824 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11825 spin_lock_bh(&ecm_db_lock);
11826 ci = node->from_connections;
11827 if (ci) {
11828 _ecm_db_connection_ref(ci);
11829 }
11830 spin_unlock_bh(&ecm_db_lock);
11831 return ci;
11832}
11833
11834/*
11835 * ecm_db_node_from_connection_get_and_ref_next()
11836 * Return the next connection in the "from list" of given a connection
11837 */
11838static inline struct ecm_db_connection_instance *ecm_db_node_from_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11839{
11840 struct ecm_db_connection_instance *cin;
11841 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11842 spin_lock_bh(&ecm_db_lock);
11843 cin = ci->node_from_next;
11844 if (cin) {
11845 _ecm_db_connection_ref(cin);
11846 }
11847 spin_unlock_bh(&ecm_db_lock);
11848 return cin;
11849}
11850
11851/*
11852 * ecm_db_node_to_connections_get_and_ref_first()
11853 * Obtain a ref to the first connection instance of a "to list" of node, if any
11854 */
11855static inline struct ecm_db_connection_instance *ecm_db_node_to_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11856{
11857 struct ecm_db_connection_instance *ci;
11858 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11859 spin_lock_bh(&ecm_db_lock);
11860 ci = node->to_connections;
11861 if (ci) {
11862 _ecm_db_connection_ref(ci);
11863 }
11864 spin_unlock_bh(&ecm_db_lock);
11865 return ci;
11866}
11867
11868/*
11869 * ecm_db_node_to_connection_get_and_ref_next()
11870 * Return the next connection in the "to list" of given a connection
11871 */
11872static inline struct ecm_db_connection_instance *ecm_db_node_to_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11873{
11874 struct ecm_db_connection_instance *cin;
11875 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11876 spin_lock_bh(&ecm_db_lock);
11877 cin = ci->node_to_next;
11878 if (cin) {
11879 _ecm_db_connection_ref(cin);
11880 }
11881 spin_unlock_bh(&ecm_db_lock);
11882 return cin;
11883}
11884
11885/*
11886 * ecm_db_node_from_nat_connections_get_and_ref_first()
11887 * Obtain a ref to the first connection instance of a "from_nat list" of node, if any
11888 */
11889static inline struct ecm_db_connection_instance *ecm_db_node_from_nat_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11890{
11891 struct ecm_db_connection_instance *ci;
11892 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11893 spin_lock_bh(&ecm_db_lock);
11894 ci = node->from_nat_connections;
11895 if (ci) {
11896 _ecm_db_connection_ref(ci);
11897 }
11898 spin_unlock_bh(&ecm_db_lock);
11899 return ci;
11900}
11901
11902/*
11903 * ecm_db_node_from_nat_connection_get_and_ref_next()
11904 * Return the next connection in the "from nat list" of given a connection
11905 */
11906static inline struct ecm_db_connection_instance *ecm_db_node_from_nat_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11907{
11908 struct ecm_db_connection_instance *cin;
11909 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11910 spin_lock_bh(&ecm_db_lock);
11911 cin = ci->node_from_nat_next;
11912 if (cin) {
11913 _ecm_db_connection_ref(cin);
11914 }
11915 spin_unlock_bh(&ecm_db_lock);
11916 return cin;
11917}
11918
11919/*
11920 * ecm_db_node_to_nat_connections_get_and_ref_first()
11921 * Obtain a ref to the first connection instance of a "to_nat list" of node, if any
11922 */
11923static inline struct ecm_db_connection_instance *ecm_db_node_to_nat_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11924{
11925 struct ecm_db_connection_instance *ci;
11926 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11927 spin_lock_bh(&ecm_db_lock);
11928 ci = node->to_nat_connections;
11929 if (ci) {
11930 _ecm_db_connection_ref(ci);
11931 }
11932 spin_unlock_bh(&ecm_db_lock);
11933 return ci;
11934}
11935
11936/*
11937 * ecm_db_node_to_nat_connection_get_and_ref_next()
11938 * Return the next connection in the "to nat list" of given a connection
11939 */
11940static inline struct ecm_db_connection_instance *ecm_db_node_to_nat_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11941{
11942 struct ecm_db_connection_instance *cin;
11943 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11944 spin_lock_bh(&ecm_db_lock);
11945 cin = ci->node_to_nat_next;
11946 if (cin) {
11947 _ecm_db_connection_ref(cin);
11948 }
11949 spin_unlock_bh(&ecm_db_lock);
11950 return cin;
11951}
11952
11953/*
Murat Sezgine34b0172015-11-05 21:58:14 -080011954 * ecm_db_should_keep_connection()
11955 * check if any classifier believes this connection should
11956 * be kept
11957 */
11958static bool ecm_db_should_keep_connection(
11959 struct ecm_db_connection_instance *ci, uint8_t *mac)
11960{
11961 bool should_keep_connection = false;
11962 int assignment_count;
11963 int aci_index;
11964 struct ecm_classifier_instance *assignments[ECM_CLASSIFIER_TYPES];
11965
11966 assignment_count =
11967 ecm_db_connection_classifier_assignments_get_and_ref(ci, assignments);
11968 for (aci_index = 0; aci_index < assignment_count; ++aci_index) {
11969 struct ecm_classifier_instance *aci;
11970 aci = assignments[aci_index];
11971 if (aci->should_keep_connection &&
11972 aci->should_keep_connection(aci, mac)) {
11973 should_keep_connection = true;
11974 break;
11975 }
11976 }
11977 ecm_db_connection_assignments_release(assignment_count, assignments);
11978
11979 return should_keep_connection;
11980}
11981
11982/*
Murat Sezgin9304d472017-04-14 10:16:52 -070011983 * ecm_db_traverse_node_from_connection_list_and_defunct()
11984 * traverse from_list of a node and calls ecm_db_connection_make_defunct()
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011985 * for each entry
11986 */
Murat Sezgin9304d472017-04-14 10:16:52 -070011987void ecm_db_traverse_node_from_connection_list_and_defunct(
Murat Sezgine34b0172015-11-05 21:58:14 -080011988 struct ecm_db_node_instance *node)
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011989{
11990 struct ecm_db_connection_instance *ci = NULL;
11991
11992 /*
11993 * Iterate all from connections
11994 */
11995 ci = ecm_db_node_from_connections_get_and_ref_first(node);
11996 while (ci) {
11997 struct ecm_db_connection_instance *cin;
11998
Murat Sezgine34b0172015-11-05 21:58:14 -080011999 if (!ecm_db_should_keep_connection(ci, node->address)) {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080012000 DEBUG_TRACE("%p: defunct %d\n", ci, ci->serial);
Murat Sezgin9304d472017-04-14 10:16:52 -070012001 ecm_db_connection_make_defunct(ci);
Murat Sezgine34b0172015-11-05 21:58:14 -080012002 } else {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080012003 DEBUG_TRACE("%p: keeping connection %d\n", ci, ci->serial);
Murat Sezgine34b0172015-11-05 21:58:14 -080012004 }
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012005
12006 cin = ecm_db_node_from_connection_get_and_ref_next(ci);
12007 ecm_db_connection_deref(ci);
12008 ci = cin;
12009 }
Murat Sezgin9304d472017-04-14 10:16:52 -070012010 DEBUG_INFO("%p: Defuncting from node connection list complete\n", node);
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012011}
12012
12013/*
Murat Sezgin9304d472017-04-14 10:16:52 -070012014 * ecm_db_traverse_node_to_connection_list_and_defunct()
12015 * traverse to_list of a node and calls ecm_db_connection_make_defunct()
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012016 * for each entry
12017 */
Murat Sezgin9304d472017-04-14 10:16:52 -070012018void ecm_db_traverse_node_to_connection_list_and_defunct(
Murat Sezgine34b0172015-11-05 21:58:14 -080012019 struct ecm_db_node_instance *node)
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012020{
12021 struct ecm_db_connection_instance *ci = NULL;
12022
12023 /*
12024 * Iterate all to connections
12025 */
12026 ci = ecm_db_node_to_connections_get_and_ref_first(node);
12027 while (ci) {
12028 struct ecm_db_connection_instance *cin;
12029
Murat Sezgine34b0172015-11-05 21:58:14 -080012030 if (!ecm_db_should_keep_connection(ci, node->address)) {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080012031 DEBUG_TRACE("%p: defunct %d\n", ci, ci->serial);
Murat Sezgin9304d472017-04-14 10:16:52 -070012032 ecm_db_connection_make_defunct(ci);
Murat Sezgine34b0172015-11-05 21:58:14 -080012033 } else {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080012034 DEBUG_TRACE("%p: keeping connection %d\n", ci, ci->serial);
Murat Sezgine34b0172015-11-05 21:58:14 -080012035 }
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012036
12037 cin = ecm_db_node_to_connection_get_and_ref_next(ci);
12038 ecm_db_connection_deref(ci);
12039 ci = cin;
12040 }
Murat Sezgin9304d472017-04-14 10:16:52 -070012041 DEBUG_INFO("%p: Defuncting to node connection list complete\n", node);
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012042}
12043
12044/*
Murat Sezgin9304d472017-04-14 10:16:52 -070012045 * ecm_db_traverse_node_from_nat_connection_list_and_defunct()
12046 * traverse from_nat_list of a node and calls ecm_db_connection_make_defunct()
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012047 * for each entry
12048 */
Murat Sezgin9304d472017-04-14 10:16:52 -070012049void ecm_db_traverse_node_from_nat_connection_list_and_defunct(
Murat Sezgine34b0172015-11-05 21:58:14 -080012050 struct ecm_db_node_instance *node)
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012051{
12052 struct ecm_db_connection_instance *ci = NULL;
12053
12054 /*
12055 * Iterate all from nat connections
12056 */
12057 ci = ecm_db_node_from_nat_connections_get_and_ref_first(node);
12058 while (ci) {
12059 struct ecm_db_connection_instance *cin;
12060
Murat Sezgine34b0172015-11-05 21:58:14 -080012061 if (!ecm_db_should_keep_connection(ci, node->address)) {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080012062 DEBUG_TRACE("%p: defunct %d\n", ci, ci->serial);
Murat Sezgin9304d472017-04-14 10:16:52 -070012063 ecm_db_connection_make_defunct(ci);
Murat Sezgine34b0172015-11-05 21:58:14 -080012064 } else {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080012065 DEBUG_TRACE("%p: keeping connection %d\n", ci, ci->serial);
Murat Sezgine34b0172015-11-05 21:58:14 -080012066 }
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012067
12068 cin = ecm_db_node_from_nat_connection_get_and_ref_next(ci);
12069 ecm_db_connection_deref(ci);
12070 ci = cin;
12071 }
Murat Sezgin9304d472017-04-14 10:16:52 -070012072 DEBUG_INFO("%p: Defuncting from_nat node connection list complete\n", node);
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012073}
12074
12075/*
Murat Sezgin9304d472017-04-14 10:16:52 -070012076 * ecm_db_traverse_node_to_nat_connection_list_and_defunct()
12077 * traverse to_nat_list of a node and calls ecm_db_connection_make_defunct()
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012078 * for each entry
12079 */
Murat Sezgin9304d472017-04-14 10:16:52 -070012080void ecm_db_traverse_node_to_nat_connection_list_and_defunct(
Murat Sezgine34b0172015-11-05 21:58:14 -080012081 struct ecm_db_node_instance *node)
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012082{
12083 struct ecm_db_connection_instance *ci = NULL;
12084
12085 /*
12086 * Iterate all to nat connections
12087 */
12088 ci = ecm_db_node_to_nat_connections_get_and_ref_first(node);
12089 while (ci) {
12090 struct ecm_db_connection_instance *cin;
12091
Murat Sezgine34b0172015-11-05 21:58:14 -080012092 if (!ecm_db_should_keep_connection(ci, node->address)) {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080012093 DEBUG_TRACE("%p: defunct %d\n", ci, ci->serial);
Murat Sezgin9304d472017-04-14 10:16:52 -070012094 ecm_db_connection_make_defunct(ci);
Murat Sezgine34b0172015-11-05 21:58:14 -080012095 } else {
Murat Sezgin3aea6c92015-11-13 13:14:12 -080012096 DEBUG_TRACE("%p: keeping connection %d\n", ci, ci->serial);
Murat Sezgine34b0172015-11-05 21:58:14 -080012097 }
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012098
12099 cin = ecm_db_node_to_nat_connection_get_and_ref_next(ci);
12100 ecm_db_connection_deref(ci);
12101 ci = cin;
12102 }
Murat Sezgin9304d472017-04-14 10:16:52 -070012103 DEBUG_INFO("%p: Defuncting to_nat node connection list complete\n", node);
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012104}
Murat Sezgin8c345822015-05-27 15:35:38 -070012105#endif
Murat Sezgin1134fb82015-10-06 14:03:49 -070012106
12107/*
12108 * ecm_db_connection_ipv6_from_ct_get_and_ref()
12109 * Return, if any, a connection given a ct
12110 */
12111struct ecm_db_connection_instance *ecm_db_connection_ipv6_from_ct_get_and_ref(struct nf_conn *ct)
12112{
12113 struct nf_conntrack_tuple orig_tuple;
12114 struct nf_conntrack_tuple reply_tuple;
12115 ip_addr_t host1_addr;
12116 ip_addr_t host2_addr;
12117 int host1_port;
12118 int host2_port;
12119 int protocol;
12120
12121 /*
12122 * Look up the associated connection for this conntrack connection
12123 */
12124 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
12125 reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
12126 ECM_NIN6_ADDR_TO_IP_ADDR(host1_addr, orig_tuple.src.u3.in6);
12127 ECM_NIN6_ADDR_TO_IP_ADDR(host2_addr, reply_tuple.src.u3.in6);
12128 protocol = orig_tuple.dst.protonum;
12129 if (protocol == IPPROTO_TCP) {
12130 host1_port = ntohs(orig_tuple.src.u.tcp.port);
12131 host2_port = ntohs(reply_tuple.src.u.tcp.port);
12132 } else if (protocol == IPPROTO_UDP) {
12133 host1_port = ntohs(orig_tuple.src.u.udp.port);
12134 host2_port = ntohs(reply_tuple.src.u.udp.port);
12135 } else if ((protocol == IPPROTO_IPIP)) {
12136 host1_port = 0;
12137 host2_port = 0;
12138 } else {
12139 host1_port = -protocol;
12140 host2_port = -protocol;
12141 }
12142
12143 DEBUG_TRACE("%p: lookup src: " ECM_IP_ADDR_OCTAL_FMT ":%d, "
12144 "dest: " ECM_IP_ADDR_OCTAL_FMT ":%d, "
12145 "protocol %d\n",
12146 ct,
12147 ECM_IP_ADDR_TO_OCTAL(host1_addr),
12148 host1_port,
12149 ECM_IP_ADDR_TO_OCTAL(host2_addr),
12150 host2_port,
12151 protocol);
12152
12153 return ecm_db_connection_find_and_ref(host1_addr,
12154 host2_addr,
12155 protocol,
12156 host1_port,
12157 host2_port);
12158}
12159
12160/*
12161 * ecm_db_connection_ipv4_from_ct_get_and_ref()
12162 * Return, if any, a connection given a ct
12163 */
12164struct ecm_db_connection_instance *ecm_db_connection_ipv4_from_ct_get_and_ref(struct nf_conn *ct)
12165{
12166 struct nf_conntrack_tuple orig_tuple;
12167 struct nf_conntrack_tuple reply_tuple;
12168 ip_addr_t host1_addr;
12169 ip_addr_t host2_addr;
12170 int host1_port;
12171 int host2_port;
12172 int protocol;
12173
12174 /*
12175 * Look up the associated connection for this conntrack connection
12176 */
12177 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
12178 reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
12179 ECM_NIN4_ADDR_TO_IP_ADDR(host1_addr, orig_tuple.src.u3.ip);
12180 ECM_NIN4_ADDR_TO_IP_ADDR(host2_addr, reply_tuple.src.u3.ip);
12181 protocol = orig_tuple.dst.protonum;
12182 if (protocol == IPPROTO_TCP) {
12183 host1_port = ntohs(orig_tuple.src.u.tcp.port);
12184 host2_port = ntohs(reply_tuple.src.u.tcp.port);
12185 } else if (protocol == IPPROTO_UDP) {
12186 host1_port = ntohs(orig_tuple.src.u.udp.port);
12187 host2_port = ntohs(reply_tuple.src.u.udp.port);
12188 } else if ((protocol == IPPROTO_IPV6) || (protocol == IPPROTO_ESP)) {
12189 host1_port = 0;
12190 host2_port = 0;
12191 } else {
12192 host1_port = -protocol;
12193 host2_port = -protocol;
12194 }
12195
12196 DEBUG_TRACE("%p: lookup src: " ECM_IP_ADDR_DOT_FMT ":%d, "
12197 "dest: " ECM_IP_ADDR_DOT_FMT ":%d, "
12198 "protocol %d\n",
12199 ct,
12200 ECM_IP_ADDR_TO_DOT(host1_addr),
12201 host1_port,
12202 ECM_IP_ADDR_TO_DOT(host2_addr),
12203 host2_port,
12204 protocol);
12205
12206 return ecm_db_connection_find_and_ref(host1_addr,
12207 host2_addr,
12208 protocol,
12209 host1_port,
12210 host2_port);
12211}
Murat Sezgin926ab4a2017-08-31 12:29:17 -070012212
12213/*
12214 * ecm_db_iproute_connection_cmp_and_kill()
12215 * This is the "iterate" function passed to the nf_ct_iterate_cleanup()
12216 * function.
12217 */
12218static int ecm_db_iproute_connection_cmp_and_kill(struct nf_conn *i, void *data)
Murat Sezgin1134fb82015-10-06 14:03:49 -070012219{
12220 struct ecm_db_connection_instance *ci;
12221
Murat Sezgince820c02017-09-29 09:32:44 -070012222 if (nf_ct_l3num(i) != AF_INET) {
12223 return 0;
12224 }
12225
Murat Sezgin1134fb82015-10-06 14:03:49 -070012226 /*
12227 * Go through the conntarck entries and if they are found in ECM db,
Murat Sezgin926ab4a2017-08-31 12:29:17 -070012228 * let the netfilter conntrack kill it..
Murat Sezgin1134fb82015-10-06 14:03:49 -070012229 */
12230 ci = ecm_db_connection_ipv4_from_ct_get_and_ref(i);
12231 if (ci) {
Murat Sezgin1134fb82015-10-06 14:03:49 -070012232 ecm_db_connection_deref(ci);
Murat Sezgin926ab4a2017-08-31 12:29:17 -070012233 return 1;
Murat Sezgin1134fb82015-10-06 14:03:49 -070012234 }
12235
12236 return 0;
12237}
12238
12239/*
12240 * ecm_db_iproute_table_update_event()
12241 * This is a call back for "routing table update event for IPv4"
12242 */
12243static int ecm_db_iproute_table_update_event(struct notifier_block *nb,
12244 unsigned long event,
12245 void *ptr)
12246{
12247 DEBUG_TRACE("iproute table update event\n");
12248
12249#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 11, 0))
Murat Sezgin926ab4a2017-08-31 12:29:17 -070012250 nf_ct_iterate_cleanup(&init_net, ecm_db_iproute_connection_cmp_and_kill, 0);
Murat Sezgin1134fb82015-10-06 14:03:49 -070012251#else
Murat Sezgin926ab4a2017-08-31 12:29:17 -070012252 nf_ct_iterate_cleanup(&init_net, ecm_db_iproute_connection_cmp_and_kill, 0, 0, 0);
Murat Sezgin1134fb82015-10-06 14:03:49 -070012253#endif
12254 return NOTIFY_DONE;
12255}
12256
12257static struct notifier_block ecm_db_iproute_table_update_nb = {
12258 .notifier_call = ecm_db_iproute_table_update_event,
12259};
12260
Murat Sezgin926ab4a2017-08-31 12:29:17 -070012261/*
12262 * ecm_db_ip6route_connection_cmp_and_kill()
12263 * This is the "iterate" function passed to the nf_ct_iterate_cleanup()
12264 * function.
12265 */
12266static int ecm_db_ip6route_connection_cmp_and_kill(struct nf_conn *i, void *data)
Murat Sezgin1134fb82015-10-06 14:03:49 -070012267{
12268 struct ecm_db_connection_instance *ci;
12269
Murat Sezgince820c02017-09-29 09:32:44 -070012270 if (nf_ct_l3num(i) != AF_INET6) {
12271 return 0;
12272 }
12273
Murat Sezgin1134fb82015-10-06 14:03:49 -070012274 /*
12275 * Go through the conntarck entries and if they are found in ECM db,
Murat Sezgin926ab4a2017-08-31 12:29:17 -070012276 * let the netfilter conntrack kill it..
Murat Sezgin1134fb82015-10-06 14:03:49 -070012277 */
12278 ci = ecm_db_connection_ipv6_from_ct_get_and_ref(i);
12279 if (ci) {
Murat Sezgin1134fb82015-10-06 14:03:49 -070012280 ecm_db_connection_deref(ci);
Murat Sezgin926ab4a2017-08-31 12:29:17 -070012281 return 1;
Murat Sezgin1134fb82015-10-06 14:03:49 -070012282 }
12283
12284 return 0;
12285}
12286
12287/*
Murat Sezgince820c02017-09-29 09:32:44 -070012288 * ecm_db_ip6route_table_iterate_cleanup_work()
12289 * Clean up work function for IPv6 route change event.
Murat Sezgin1134fb82015-10-06 14:03:49 -070012290 */
Murat Sezgince820c02017-09-29 09:32:44 -070012291static void ecm_db_ip6route_table_iterate_cleanup_work(struct work_struct *work)
Murat Sezgin1134fb82015-10-06 14:03:49 -070012292{
Murat Sezgince820c02017-09-29 09:32:44 -070012293 DEBUG_TRACE("ip6route table iterate cleanup work\n");
Murat Sezgin1134fb82015-10-06 14:03:49 -070012294
12295#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 11, 0))
Murat Sezgin926ab4a2017-08-31 12:29:17 -070012296 nf_ct_iterate_cleanup(&init_net, ecm_db_ip6route_connection_cmp_and_kill, 0);
Murat Sezgin1134fb82015-10-06 14:03:49 -070012297#else
Murat Sezgin926ab4a2017-08-31 12:29:17 -070012298 nf_ct_iterate_cleanup(&init_net, ecm_db_ip6route_connection_cmp_and_kill, 0, 0, 0);
Murat Sezgin1134fb82015-10-06 14:03:49 -070012299#endif
Murat Sezgince820c02017-09-29 09:32:44 -070012300 kfree(work);
12301 atomic_dec(&ecm_db_ip6route_work_count);
12302}
12303
12304/*
12305 * ecm_db_ip6route_table_update_event()
12306 * This is a callback for "routing table update event for IPv6"
12307 *
12308 * ipv6 route change notifier is an atomic notifier, i.e. we cannot
12309 * schedule.
12310 *
12311 * Unfortunately, nf_ct_iterate_cleanup can run for a long
12312 * time if there are lots of conntracks and the system
12313 * handles high softirq load, so it frequently calls cond_resched
12314 * while iterating the conntrack table.
12315 *
12316 * So we defer nf_ct_iterate_cleanup walk to the system workqueue.
12317 */
12318static int ecm_db_ip6route_table_update_event(struct notifier_block *nb,
12319 unsigned long event,
12320 void *ptr)
12321{
12322 struct work_struct *work;
12323
12324 DEBUG_TRACE("ip6route table update event\n");
12325
12326 if (atomic_read(&ecm_db_ip6route_work_count) >= ECM_DB_IP6ROUTE_MAX_WORK_COUNT)
12327 return NOTIFY_DONE;
12328
12329
12330 work = kmalloc(sizeof(*work), GFP_ATOMIC);
12331 if (work) {
12332 atomic_inc(&ecm_db_ip6route_work_count);
12333
12334 INIT_WORK(work, ecm_db_ip6route_table_iterate_cleanup_work);
12335 schedule_work(work);
12336 }
12337
Murat Sezgin1134fb82015-10-06 14:03:49 -070012338 return NOTIFY_DONE;
12339}
12340
12341static struct notifier_block ecm_db_ip6route_table_update_nb = {
12342 .notifier_call = ecm_db_ip6route_table_update_event,
12343};
12344
ratheesh kannoth37e35b02015-03-26 11:25:02 +053012345/*
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012346 * ecm_db_init()
Ben Menchaca84f36632014-02-28 20:57:38 +000012347 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070012348int ecm_db_init(struct dentry *dentry)
Ben Menchaca84f36632014-02-28 20:57:38 +000012349{
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012350 DEBUG_INFO("ECM Module init\n");
Ben Menchaca84f36632014-02-28 20:57:38 +000012351
Murat Sezgin908ecb32015-05-10 20:54:36 -070012352 ecm_db_dentry = debugfs_create_dir("ecm_db", dentry);
12353 if (!ecm_db_dentry) {
12354 DEBUG_ERROR("Failed to create ecm db directory in debugfs\n");
12355 return -1;
12356 }
Ben Menchaca84f36632014-02-28 20:57:38 +000012357
12358 /*
Gareth Williams54d15d92015-04-24 19:28:27 +010012359 * Get a random seed for jhash()
12360 */
12361 get_random_bytes(&ecm_db_jhash_rnd, sizeof(ecm_db_jhash_rnd));
Murat Sezgin18ed5d32016-04-13 15:43:17 -070012362 printk(KERN_INFO "ECM database jhash random seed: 0x%x\n", ecm_db_jhash_rnd);
Gareth Williams54d15d92015-04-24 19:28:27 +010012363
Murat Sezgin908ecb32015-05-10 20:54:36 -070012364 if (!debugfs_create_u32("connection_count", S_IRUGO, ecm_db_dentry,
12365 (u32 *)&ecm_db_connection_count)) {
12366 DEBUG_ERROR("Failed to create ecm db connection count file in debugfs\n");
12367 goto init_cleanup;
Ben Menchaca84f36632014-02-28 20:57:38 +000012368 }
12369
Murat Sezgin908ecb32015-05-10 20:54:36 -070012370 if (!debugfs_create_u32("host_count", S_IRUGO, ecm_db_dentry,
12371 (u32 *)&ecm_db_host_count)) {
12372 DEBUG_ERROR("Failed to create ecm db host count file in debugfs\n");
12373 goto init_cleanup;
Ben Menchaca84f36632014-02-28 20:57:38 +000012374 }
12375
Murat Sezgin908ecb32015-05-10 20:54:36 -070012376 if (!debugfs_create_u32("mapping_count", S_IRUGO, ecm_db_dentry,
12377 (u32 *)&ecm_db_mapping_count)) {
12378 DEBUG_ERROR("Failed to create ecm db mapping count file in debugfs\n");
12379 goto init_cleanup;
12380 }
12381
12382 if (!debugfs_create_u32("node_count", S_IRUGO, ecm_db_dentry,
12383 (u32 *)&ecm_db_node_count)) {
12384 DEBUG_ERROR("Failed to create ecm db node count file in debugfs\n");
12385 goto init_cleanup;
12386 }
12387
12388 if (!debugfs_create_u32("iface_count", S_IRUGO, ecm_db_dentry,
12389 (u32 *)&ecm_db_iface_count)) {
12390 DEBUG_ERROR("Failed to create ecm db iface count file in debugfs\n");
12391 goto init_cleanup;
12392 }
12393
12394 if (!debugfs_create_file("defunct_all", S_IRUGO | S_IWUSR, ecm_db_dentry,
12395 NULL, &ecm_db_defunct_all_fops)) {
12396 DEBUG_ERROR("Failed to create ecm db defunct_all file in debugfs\n");
12397 goto init_cleanup;
12398 }
12399
12400 if (!debugfs_create_file("connection_count_simple", S_IRUGO, ecm_db_dentry,
12401 NULL, &ecm_db_connection_count_simple_fops)) {
12402 DEBUG_ERROR("Failed to create ecm db connection count simple file in debugfs\n");
12403 goto init_cleanup;
Ben Menchaca84f36632014-02-28 20:57:38 +000012404 }
12405
Murat Sezgina89f7c02016-10-19 11:06:56 -070012406 ecm_db_connection_table = vzalloc(sizeof(struct ecm_db_connection_instance *) * ECM_DB_CONNECTION_HASH_SLOTS);
12407 if (!ecm_db_connection_table) {
12408 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_connection_table\n");
12409 goto init_cleanup;
12410 }
12411
12412 ecm_db_connection_table_lengths = vzalloc(sizeof(int) * ECM_DB_CONNECTION_HASH_SLOTS);
12413 if (!ecm_db_connection_table_lengths) {
12414 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_connection_table_lengths\n");
12415 goto init_cleanup_1;
12416 }
12417
12418 ecm_db_connection_serial_table = vzalloc(sizeof(struct ecm_db_connection_instance *) * ECM_DB_CONNECTION_SERIAL_HASH_SLOTS);
12419 if (!ecm_db_connection_serial_table) {
12420 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_connection_serial_table\n");
12421 goto init_cleanup_2;
12422 }
12423
12424 ecm_db_connection_serial_table_lengths = vzalloc(sizeof(int) * ECM_DB_CONNECTION_SERIAL_HASH_SLOTS);
12425 if (!ecm_db_connection_serial_table_lengths) {
12426 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_connection_serial_table_lengths\n");
12427 goto init_cleanup_3;
12428 }
12429
12430 ecm_db_mapping_table = vzalloc(sizeof(struct ecm_db_mapping_instance *) * ECM_DB_MAPPING_HASH_SLOTS);
12431 if (!ecm_db_mapping_table) {
12432 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_mapping_table\n");
12433 goto init_cleanup_4;
12434 }
12435
12436 ecm_db_mapping_table_lengths = vzalloc(sizeof(int) * ECM_DB_MAPPING_HASH_SLOTS);
12437 if (!ecm_db_mapping_table_lengths) {
12438 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_mapping_table_lengths\n");
12439 goto init_cleanup_5;
12440 }
12441
12442 ecm_db_host_table = vzalloc(sizeof(struct ecm_db_host_instance *) * ECM_DB_HOST_HASH_SLOTS);
12443 if (!ecm_db_host_table) {
12444 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_host_table\n");
12445 goto init_cleanup_6;
12446 }
12447
12448 ecm_db_host_table_lengths = vzalloc(sizeof(int) * ECM_DB_HOST_HASH_SLOTS);
12449 if (!ecm_db_host_table_lengths) {
12450 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_host_table_lengths\n");
12451 goto init_cleanup_7;
12452 }
12453
12454 ecm_db_node_table = vzalloc(sizeof(struct ecm_db_node_instance *) * ECM_DB_NODE_HASH_SLOTS);
12455 if (!ecm_db_node_table) {
12456 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_node_table\n");
12457 goto init_cleanup_8;
12458 }
12459
12460 ecm_db_node_table_lengths = vzalloc(sizeof(int) * ECM_DB_NODE_HASH_SLOTS);
12461 if (!ecm_db_node_table_lengths) {
12462 DEBUG_ERROR("Failed to allocate virtual memory for ecm_db_node_table_lengths\n");
12463 goto init_cleanup_9;
12464 }
12465
Ben Menchaca84f36632014-02-28 20:57:38 +000012466 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000012467 * Set a timer to manage cleanup of expired connections
12468 */
12469 init_timer(&ecm_db_timer);
12470 ecm_db_timer.function = ecm_db_timer_callback;
12471 ecm_db_timer.data = 0;
12472 ecm_db_timer.expires = jiffies + HZ;
12473 add_timer(&ecm_db_timer);
12474
12475 /*
12476 * Initialise timer groups with time values
12477 */
12478 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT].time = ECM_DB_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT;
12479 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT;
12480 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT].time = ECM_DB_CONNECTION_GENERIC_TIMEOUT;
12481 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT;
12482 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT].time = ECM_DB_CONNECTION_IGMP_TIMEOUT;
12483 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT;
12484 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT].time = ECM_DB_CONNECTION_UDP_TIMEOUT;
12485 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT;
12486 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT].time = ECM_DB_CONNECTION_UDP_TIMEOUT;
12487 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT;
12488 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT].time = ECM_DB_CONNECTION_ICMP_TIMEOUT;
12489 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT;
12490 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT].time = ECM_DB_CONNECTION_TCP_SHORT_TIMEOUT;
12491 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT;
12492 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT].time = ECM_DB_CONNECTION_TCP_RST_TIMEOUT;
12493 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT;
12494 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT].time = ECM_DB_CONNECTION_TCP_LONG_TIMEOUT;
12495 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT;
12496 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT].time = ECM_DB_CONNECTION_PPTP_DATA_TIMEOUT;
12497 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT;
12498 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT].time = ECM_DB_CONNECTION_RTCP_TIMEOUT;
12499 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT;
12500 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT].time = ECM_DB_CONNECTION_TCP_LONG_TIMEOUT;
12501 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT;
12502 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT].time = ECM_DB_CONNECTION_RTSP_FAST_TIMEOUT;
12503 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT;
12504 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT].time = ECM_DB_CONNECTION_RTSP_SLOW_TIMEOUT;
12505 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT;
12506 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT].time = ECM_DB_CONNECTION_DNS_TIMEOUT;
12507 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT;
12508 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT].time = ECM_DB_CONNECTION_FTP_TIMEOUT;
12509 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT;
12510 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT].time = ECM_DB_CONNECTION_BITTORRENT_TIMEOUT;
12511 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT;
12512
12513 /*
12514 * H323 timeout value is 8 hours (8h * 60m * 60s == 28800 seconds).
12515 */
12516 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT].time = ECM_DB_CONNECTION_H323_TIMEOUT;
12517 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT;
12518
12519 /*
12520 * IKE Timeout (seconds) = 15 hours
12521 */
12522 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT].time = ECM_DB_CONNECTION_IKE_TIMEOUT;
12523 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT;
12524
12525 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT].time = ECM_DB_CONNECTION_ESP_TIMEOUT;
12526 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT;
12527 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT].time = ECM_DB_CONNECTION_ESP_PENDING_TIMEOUT;
12528 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT;
12529
12530 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT].time = ECM_DB_CONNECTION_SDP_TIMEOUT;
12531 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT;
12532 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT].time = ECM_DB_CONNECTION_SIP_TIMEOUT;
12533 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT;
12534
12535 /*
Murat Sezgin56fa15a2017-08-25 17:45:38 -070012536 * Defunct re-try timeout (5 seconds)
12537 */
12538 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_DEFUNCT_RETRY_TIMEOUT].time = ECM_DB_CONNECTION_DEFUNCT_RETRY_TIMEOUT;
12539 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_DEFUNCT_RETRY_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_DEFUNCT_RETRY_TIMEOUT;
12540
12541 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000012542 * Reset connection by protocol counters
12543 */
12544 memset(ecm_db_connection_count_by_protocol, 0, sizeof(ecm_db_connection_count_by_protocol));
12545
Gareth Williamsb39e7c22015-03-25 10:15:33 +000012546#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +010012547 /*
12548 * Reset classifier type assignment lists
12549 */
12550 memset(ecm_db_connection_classifier_type_assignments, 0, sizeof(ecm_db_connection_classifier_type_assignments));
Gareth Williamsb39e7c22015-03-25 10:15:33 +000012551#endif
Murat Sezgin1134fb82015-10-06 14:03:49 -070012552 /*
12553 * register for route table modification events
12554 */
12555 ip_rt_register_notifier(&ecm_db_iproute_table_update_nb);
12556 rt6_register_notifier(&ecm_db_ip6route_table_update_nb);
12557
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012558 return 0;
Ben Menchaca84f36632014-02-28 20:57:38 +000012559
Murat Sezgina89f7c02016-10-19 11:06:56 -070012560init_cleanup_9:
12561 vfree(ecm_db_node_table);
12562init_cleanup_8:
12563 vfree(ecm_db_host_table_lengths);
12564init_cleanup_7:
12565 vfree(ecm_db_host_table);
12566init_cleanup_6:
12567 vfree(ecm_db_mapping_table_lengths);
12568init_cleanup_5:
12569 vfree(ecm_db_mapping_table);
12570init_cleanup_4:
12571 vfree(ecm_db_connection_serial_table_lengths);
12572init_cleanup_3:
12573 vfree(ecm_db_connection_serial_table);
12574init_cleanup_2:
12575 vfree(ecm_db_connection_table_lengths);
12576init_cleanup_1:
12577 vfree(ecm_db_connection_table);
Murat Sezgin908ecb32015-05-10 20:54:36 -070012578init_cleanup:
Murat Sezgin908ecb32015-05-10 20:54:36 -070012579 debugfs_remove_recursive(ecm_db_dentry);
12580 return -1;
Ben Menchaca84f36632014-02-28 20:57:38 +000012581}
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012582EXPORT_SYMBOL(ecm_db_init);
Ben Menchaca84f36632014-02-28 20:57:38 +000012583
12584/*
12585 * ecm_db_exit()
12586 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012587void ecm_db_exit(void)
Ben Menchaca84f36632014-02-28 20:57:38 +000012588{
12589 DEBUG_INFO("ECM DB Module exit\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012590
12591 spin_lock_bh(&ecm_db_lock);
12592 ecm_db_terminate_pending = true;
12593 spin_unlock_bh(&ecm_db_lock);
12594
12595 ecm_db_connection_defunct_all();
12596
12597 /*
12598 * Destroy garbage timer
12599 * Timer must be cancelled outside of holding db lock - if the
12600 * timer callback runs on another CPU we would deadlock
12601 * as we would wait for the callback to finish and it would wait
12602 * indefinately for the lock to be released!
12603 */
12604 del_timer_sync(&ecm_db_timer);
Murat Sezgin1f381852014-11-20 09:51:07 -080012605
Murat Sezgin908ecb32015-05-10 20:54:36 -070012606 /*
Murat Sezgina89f7c02016-10-19 11:06:56 -070012607 * Free the tables.
12608 */
12609 vfree(ecm_db_node_table);
12610 vfree(ecm_db_host_table_lengths);
12611 vfree(ecm_db_host_table);
12612 vfree(ecm_db_mapping_table_lengths);
12613 vfree(ecm_db_mapping_table);
12614 vfree(ecm_db_connection_serial_table_lengths);
12615 vfree(ecm_db_connection_serial_table);
12616 vfree(ecm_db_connection_table_lengths);
12617 vfree(ecm_db_connection_table);
12618
12619 /*
Murat Sezgin908ecb32015-05-10 20:54:36 -070012620 * Remove the debugfs files recursively.
12621 */
12622 if (ecm_db_dentry) {
12623 debugfs_remove_recursive(ecm_db_dentry);
Murat Sezgin1f381852014-11-20 09:51:07 -080012624 }
Murat Sezgin1134fb82015-10-06 14:03:49 -070012625
12626 /*
12627 * unregister for route table update events
12628 */
12629 ip_rt_unregister_notifier(&ecm_db_iproute_table_update_nb);
12630 rt6_unregister_notifier(&ecm_db_ip6route_table_update_nb);
Ben Menchaca84f36632014-02-28 20:57:38 +000012631}
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012632EXPORT_SYMBOL(ecm_db_exit);