blob: 53c254cd531f8d492852159fd214480c4f3a8df1 [file] [log] [blame]
/*
**************************************************************************
* Copyright (c) 2014-2021, The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**************************************************************************
*/
#include <linux/version.h>
#include <linux/types.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/icmp.h>
#include <linux/kthread.h>
#include <linux/debugfs.h>
#include <linux/pkt_sched.h>
#include <linux/string.h>
#include <linux/random.h>
#include <net/route.h>
#include <net/ip.h>
#include <net/tcp.h>
#include <asm/unaligned.h>
#include <asm/uaccess.h> /* for put_user */
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <linux/inet.h>
#include <linux/in.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_bridge.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
/*
* Debug output levels
* 0 = OFF
* 1 = ASSERTS / ERRORS
* 2 = 1 + WARN
* 3 = 2 + INFO
* 4 = 3 + TRACE
*/
#define DEBUG_LEVEL ECM_DB_DEBUG_LEVEL
#include "ecm_types.h"
#include "ecm_db_types.h"
#include "ecm_state.h"
#include "ecm_tracker.h"
#include "ecm_classifier.h"
#include "ecm_front_end_types.h"
#include "ecm_classifier_default.h"
#include "ecm_db.h"
/*
* Global list.
* All instances are inserted into global list - this allows easy iteration of all instances of a particular type.
* The list is doubly linked for fast removal. The list is in no particular order.
*/
struct ecm_db_iface_instance *ecm_db_interfaces = NULL;
/*
* Interface hash table
*/
#define ECM_DB_IFACE_HASH_SLOTS 8
static struct ecm_db_iface_instance *ecm_db_iface_table[ECM_DB_IFACE_HASH_SLOTS];
/* Slots of the interface hash table */
static int ecm_db_iface_table_lengths[ECM_DB_IFACE_HASH_SLOTS];
/* Tracks how long each chain is */
#define ECM_DB_IFACE_ID_HASH_SLOTS 8
static struct ecm_db_iface_instance *ecm_db_iface_id_table[ECM_DB_IFACE_ID_HASH_SLOTS];
/* Slots of the interface id hash table */
static int ecm_db_iface_id_table_lengths[ECM_DB_IFACE_ID_HASH_SLOTS];
/* Tracks how long each chain is */
static int ecm_db_iface_count = 0; /* Number of interfaces allocated */
/*
* Interface flags
*/
#define ECM_DB_IFACE_FLAGS_INSERTED 1 /* Interface is inserted into connection database tables */
/*
* ecm_db_interface_type_names[]
* Array that maps the interface type to a string
*/
static char *ecm_db_interface_type_names[ECM_DB_IFACE_TYPE_COUNT] = {
"ETHERNET",
"PPPoE",
"LINK-AGGREGATION",
"VLAN",
"BRIDGE",
"LOOPBACK",
"IPSEC_TUNNEL",
"UNKNOWN",
"SIT",
"TUNIPIP6",
"PPPoL2TPV2",
"PPTP",
"MAP_T",
"GRE_TUN",
"GRE_TAP",
"RAWIP",
"OVPN",
"VxLAN",
"OVS_BRIDGE",
"MACVLAN"
};
/*
* _ecm_db_iface_count_get()
* Return the iface count (lockless).
*/
int _ecm_db_iface_count_get(void)
{
return ecm_db_iface_count;
}
/*
* ecm_db_interface_type_to_string()
* Return a string buffer containing the type name of the interface
*/
char *ecm_db_interface_type_to_string(ecm_db_iface_type_t type)
{
DEBUG_ASSERT((type >= 0) && (type < ECM_DB_IFACE_TYPE_COUNT), "Invalid type: %d\n", type);
return ecm_db_interface_type_names[(int)type];
}
EXPORT_SYMBOL(ecm_db_interface_type_to_string);
/*
* ecm_db_iface_type_get()
* Return type of interface
*/
ecm_db_iface_type_t ecm_db_iface_type_get(struct ecm_db_iface_instance *ii)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
return ii->type;
}
EXPORT_SYMBOL(ecm_db_iface_type_get);
/*
* ecm_db_iface_id_generate_hash_index()
* Calculate the hash index based on interface identifier.
*/
static inline ecm_db_iface_id_hash_t ecm_db_iface_id_generate_hash_index(int32_t interface_id)
{
uint32_t hash_val;
hash_val = (uint32_t)jhash_1word((uint32_t)interface_id, ecm_db_jhash_rnd);
return (ecm_db_iface_id_hash_t)(hash_val & (ECM_DB_IFACE_ID_HASH_SLOTS - 1));
}
#ifdef ECM_DB_ADVANCED_STATS_ENABLE
/*
* ecm_db_iface_data_stats_get()
* Return data stats for the instance
*/
static void ecm_db_iface_data_stats_get(struct ecm_db_iface_instance *ii, uint64_t *from_data_total, uint64_t *to_data_total,
uint64_t *from_packet_total, uint64_t *to_packet_total,
uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
spin_lock_bh(&ecm_db_lock);
if (from_data_total) {
*from_data_total = ii->from_data_total;
}
if (to_data_total) {
*to_data_total = ii->to_data_total;
}
if (from_packet_total) {
*from_packet_total = ii->from_packet_total;
}
if (to_packet_total) {
*to_packet_total = ii->to_packet_total;
}
if (from_data_total_dropped) {
*from_data_total_dropped = ii->from_data_total_dropped;
}
if (to_data_total_dropped) {
*to_data_total_dropped = ii->to_data_total_dropped;
}
if (from_packet_total_dropped) {
*from_packet_total_dropped = ii->from_packet_total_dropped;
}
if (to_packet_total_dropped) {
*to_packet_total_dropped = ii->to_packet_total_dropped;
}
spin_unlock_bh(&ecm_db_lock);
}
#endif
#ifdef ECM_STATE_OUTPUT_ENABLE
/*
* ecm_db_iface_state_get_base()
* Get the basic state for an interface object
*/
static int ecm_db_iface_state_get_base(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
#ifdef ECM_DB_XREF_ENABLE
int node_count;
#endif
uint32_t time_added;
int32_t interface_identifier;
int32_t ae_interface_identifier;
char name[IFNAMSIZ];
int32_t mtu;
ecm_db_iface_type_t type;
#ifdef ECM_DB_ADVANCED_STATS_ENABLE
uint64_t from_data_total;
uint64_t to_data_total;
uint64_t from_packet_total;
uint64_t to_packet_total;
uint64_t from_data_total_dropped;
uint64_t to_data_total_dropped;
uint64_t from_packet_total_dropped;
uint64_t to_packet_total_dropped;
#endif
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
DEBUG_TRACE("%px: Open iface msg\n", ii);
if ((result = ecm_state_prefix_add(sfi, "iface"))) {
return result;
}
#ifdef ECM_DB_XREF_ENABLE
node_count = ecm_db_iface_node_count_get(ii);
#endif
time_added = ii->time_added;
type = ii->type;
interface_identifier = ii->interface_identifier;
ae_interface_identifier = ii->ae_interface_identifier;
spin_lock_bh(&ecm_db_lock);
strlcpy(name, ii->name, IFNAMSIZ);
mtu = ii->mtu;
spin_unlock_bh(&ecm_db_lock);
#ifdef ECM_DB_ADVANCED_STATS_ENABLE
ecm_db_iface_data_stats_get(ii, &from_data_total, &to_data_total,
&from_packet_total, &to_packet_total,
&from_data_total_dropped, &to_data_total_dropped,
&from_packet_total_dropped, &to_packet_total_dropped);
if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
from_packet_total, to_packet_total, from_data_total_dropped,
to_data_total_dropped, from_packet_total_dropped,
to_packet_total_dropped))) {
return result;
}
#endif
if ((result = ecm_state_write(sfi, "type", "%d", type))) {
return result;
}
if ((result = ecm_state_write(sfi, "name", "%s", name))) {
return result;
}
if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
return result;
}
if ((result = ecm_state_write(sfi, "mtu", "%d", mtu))) {
return result;
}
if ((result = ecm_state_write(sfi, "interface_identifier", "%d", interface_identifier))) {
return result;
}
if ((result = ecm_state_write(sfi, "ae_interface_identifier", "%d", ae_interface_identifier))) {
return result;
}
#ifdef ECM_DB_XREF_ENABLE
if ((result = ecm_state_write(sfi, "nodes", "%d", node_count))) {
return result;
}
#endif
return ecm_state_prefix_remove(sfi);
}
/*
* ecm_db_iface_ethernet_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_ethernet_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
uint8_t address[ETH_ALEN];
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
memcpy(address, ii->type_info.ethernet.address, ETH_ALEN);
spin_unlock_bh(&ecm_db_lock);
if ((result = ecm_state_prefix_add(sfi, "ethernet"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#ifdef ECM_INTERFACE_BOND_ENABLE
/*
* ecm_db_iface_lag_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_lag_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
uint8_t address[ETH_ALEN];
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
memcpy(address, ii->type_info.lag.address, ETH_ALEN);
spin_unlock_bh(&ecm_db_lock);
if ((result = ecm_state_prefix_add(sfi, "lag"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#endif
/*
* ecm_db_iface_bridge_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_bridge_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
uint8_t address[ETH_ALEN];
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
memcpy(address, ii->type_info.bridge.address, ETH_ALEN);
spin_unlock_bh(&ecm_db_lock);
if ((result = ecm_state_prefix_add(sfi, "bridge"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#ifdef ECM_INTERFACE_MACVLAN_ENABLE
/*
* ecm_db_iface_macvlan_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_macvlan_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
uint8_t address[ETH_ALEN];
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
memcpy(address, ii->type_info.macvlan.address, ETH_ALEN);
spin_unlock_bh(&ecm_db_lock);
if ((result = ecm_state_prefix_add(sfi, "macvlan"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
goto done;
}
if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
goto done;
}
done:
ecm_state_prefix_remove(sfi);
return result;
}
#endif
#ifdef ECM_INTERFACE_OVS_BRIDGE_ENABLE
/*
* ecm_db_iface_ovs_bridge_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_ovs_bridge_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
uint8_t address[ETH_ALEN];
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
memcpy(address, ii->type_info.ovsb.address, ETH_ALEN);
spin_unlock_bh(&ecm_db_lock);
if ((result = ecm_state_prefix_add(sfi, "ovs_bridge"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#endif
#ifdef ECM_INTERFACE_VLAN_ENABLE
/*
* ecm_db_iface_vlan_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_vlan_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
uint8_t address[ETH_ALEN];
uint16_t vlan_tag;
uint16_t vlan_tpid;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
memcpy(address, ii->type_info.vlan.address, ETH_ALEN);
vlan_tag = ii->type_info.vlan.vlan_tag;
vlan_tpid = ii->type_info.vlan.vlan_tpid;
spin_unlock_bh(&ecm_db_lock);
if ((result = ecm_state_prefix_add(sfi, "vlan"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
return result;
}
if ((result = ecm_state_write(sfi, "tag", "%x", vlan_tag))) {
return result;
}
if ((result = ecm_state_write(sfi, "tpid", "%x", vlan_tpid))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#endif
#ifdef ECM_INTERFACE_PPPOE_ENABLE
/*
* ecm_db_iface_pppoe_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_pppoe_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
uint16_t pppoe_session_id;
uint8_t remote_mac[ETH_ALEN];
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
pppoe_session_id = ii->type_info.pppoe.pppoe_session_id;
memcpy(remote_mac, ii->type_info.pppoe.remote_mac, ETH_ALEN);
spin_unlock_bh(&ecm_db_lock);
if ((result = ecm_state_prefix_add(sfi, "pppoe"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
if ((result = ecm_state_write(sfi, "remote_mac", "%pM", remote_mac))) {
return result;
}
if ((result = ecm_state_write(sfi, "session_id", "%u", pppoe_session_id))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#endif
#ifdef ECM_INTERFACE_MAP_T_ENABLE
/*
* ecm_db_iface_map_t_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_map_t_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
int32_t if_index;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
if_index = ii->type_info.map_t.if_index;
spin_unlock_bh(&ecm_db_lock);
if ((result = ecm_state_prefix_add(sfi, "map_t"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
if ((result = ecm_state_write(sfi, "if_index", "%d", if_index))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#endif
#ifdef ECM_INTERFACE_GRE_TUN_ENABLE
/*
* ecm_db_iface_gre_tun_state_get
* Return interface type specific state
*/
static int ecm_db_iface_gre_tun_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
int32_t if_index;
ip_addr_t local_ip, remote_ip;
char local_ipaddress[ECM_IP_ADDR_STR_BUFF_SIZE];
char remote_ipaddress[ECM_IP_ADDR_STR_BUFF_SIZE];
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
if_index = ii->type_info.gre_tun.if_index;
memcpy(local_ip, ii->type_info.gre_tun.local_ip, sizeof(ip_addr_t));
memcpy(remote_ip, ii->type_info.gre_tun.remote_ip, sizeof(ip_addr_t));
spin_unlock_bh(&ecm_db_lock);
ecm_ip_addr_to_string(local_ipaddress, local_ip);
ecm_ip_addr_to_string(remote_ipaddress, remote_ip);
if ((result = ecm_state_prefix_add(sfi, "gre_tun"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
if ((result = ecm_state_write(sfi, "if_index", "%d", if_index))) {
return result;
}
if ((result = ecm_state_write(sfi, "local_ip", "%s", local_ipaddress))) {
return result;
}
if ((result = ecm_state_write(sfi, "remote_ip", "%s", remote_ipaddress))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#endif
#ifdef ECM_INTERFACE_L2TPV2_ENABLE
/*
* ecm_db_iface_pppol2tpv2_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_pppol2tpv2_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
struct ecm_db_interface_info_pppol2tpv2 type_info;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
memcpy(&type_info, &ii->type_info, sizeof(struct ecm_db_interface_info_pppol2tpv2));
spin_unlock_bh(&ecm_db_lock);
if ((result = ecm_state_prefix_add(sfi, "pppol2tpv2"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
if ((result = ecm_state_write(sfi, "local_tunnel_id", "%u", type_info.l2tp.tunnel.tunnel_id))) {
return result;
}
if ((result = ecm_state_write(sfi, "local_session_id", "%u", type_info.l2tp.session.session_id))) {
return result;
}
if ((result = ecm_state_write(sfi, "peer_tunnnel_id", "%u", type_info.l2tp.tunnel.peer_tunnel_id))) {
return result;
}
if ((result = ecm_state_write(sfi, "peer_session_id", "%u", type_info.l2tp.session.peer_session_id))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#endif
#ifdef ECM_INTERFACE_PPTP_ENABLE
/*
* ecm_db_iface_pptp_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_pptp_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
struct ecm_db_interface_info_pptp type_info;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
memcpy(&type_info, &ii->type_info, sizeof(struct ecm_db_interface_info_pptp));
spin_unlock_bh(&ecm_db_lock);
result = ecm_state_prefix_add(sfi, "pptp");
if (result) {
return result;
}
result = ecm_db_iface_state_get_base(ii, sfi);
if (result) {
return result;
}
result = ecm_state_write(sfi, "local_call_id", "%u", type_info.src_call_id);
if (result) {
return result;
}
result = ecm_state_write(sfi, "peer_call_id", "%u", type_info.dst_call_id);
if (result) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#endif
/*
* ecm_db_iface_unknown_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_unknown_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
uint32_t os_specific_ident;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
os_specific_ident = ii->type_info.unknown.os_specific_ident;
spin_unlock_bh(&ecm_db_lock);
if ((result = ecm_state_prefix_add(sfi, "pppoe"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
/*
* ecm_db_iface_loopback_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_loopback_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
uint32_t os_specific_ident;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
os_specific_ident = ii->type_info.loopback.os_specific_ident;
spin_unlock_bh(&ecm_db_lock);
if ((result = ecm_state_prefix_add(sfi, "loopback"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#ifdef ECM_INTERFACE_IPSEC_ENABLE
/*
* ecm_db_iface_ipsec_tunnel_state_get()
* Return interface type specific state
*
* GGG TODO Output state on ipsec tunnel specific data
*/
static int ecm_db_iface_ipsec_tunnel_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
uint32_t os_specific_ident;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
os_specific_ident = ii->type_info.ipsec_tunnel.os_specific_ident;
spin_unlock_bh(&ecm_db_lock);
if ((result = ecm_state_prefix_add(sfi, "ipsec"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#endif
#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
#ifdef ECM_IPV6_ENABLE
/*
* ecm_db_iface_tunipip6_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_tunipip6_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
/*
* TODO: tunipip6 specific information needs to be added.
*/
if ((result = ecm_state_prefix_add(sfi, "tunipip6"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#endif
#endif
#ifdef ECM_INTERFACE_SIT_ENABLE
/*
* ecm_db_iface_sit_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_sit_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
/*
* TODO: SIT (6rd) specific information needs to be added.
*/
if ((result = ecm_state_prefix_add(sfi, "sit"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#endif
#ifdef ECM_INTERFACE_RAWIP_ENABLE
/*
* ecm_db_iface_rawip_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_rawip_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
uint8_t address[ETH_ALEN];
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
memcpy(address, ii->type_info.rawip.address, ETH_ALEN);
spin_unlock_bh(&ecm_db_lock);
if ((result = ecm_state_prefix_add(sfi, "rawip"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#endif
#ifdef ECM_INTERFACE_OVPN_ENABLE
/*
* ecm_db_iface_ovpn_state_get()
* Return OVPN interface state
*/
static int ecm_db_iface_ovpn_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
struct ecm_db_interface_info_ovpn type_info;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
memcpy(&type_info, &ii->type_info, sizeof(struct ecm_db_interface_info_ovpn));
spin_unlock_bh(&ecm_db_lock);
result = ecm_state_prefix_add(sfi, "ovpn");
if (result) {
return result;
}
result = ecm_db_iface_state_get_base(ii, sfi);
if (result) {
return result;
}
if ((result = ecm_state_write(sfi, "tun_ifnum", "%u", type_info.tun_ifnum))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#endif
#ifdef ECM_INTERFACE_VXLAN_ENABLE
/*
* ecm_db_iface_vxlan_state_get()
* Return interface type specific state
*/
static int ecm_db_iface_vxlan_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
{
int result;
uint32_t vni;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
vni = ii->type_info.vxlan.vni;
spin_unlock_bh(&ecm_db_lock);
if ((result = ecm_state_prefix_add(sfi, "vxlan"))) {
return result;
}
if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
return result;
}
if ((result = ecm_state_write(sfi, "vni", "%d", vni))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
#endif
/*
* ecm_db_iface_state_get()
* Obtain state for the interface.
*
* State specific to the interface type will be returned.
*/
int ecm_db_iface_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_iface_instance *ii)
{
int result;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
if ((result = ecm_state_prefix_add(sfi, "iface"))) {
return result;
}
if ((result = ii->state_get(ii, sfi))) {
return result;
}
return ecm_state_prefix_remove(sfi);
}
EXPORT_SYMBOL(ecm_db_iface_state_get);
/*
* ecm_db_iface_hash_table_lengths_get()
* Return hash table length
*/
int ecm_db_iface_hash_table_lengths_get(int index)
{
int length;
DEBUG_ASSERT((index >= 0) && (index < ECM_DB_IFACE_HASH_SLOTS), "Bad protocol: %d\n", index);
spin_lock_bh(&ecm_db_lock);
length = ecm_db_iface_table_lengths[index];
spin_unlock_bh(&ecm_db_lock);
return length;
}
EXPORT_SYMBOL(ecm_db_iface_hash_table_lengths_get);
/*
* ecm_db_iface_hash_index_get_next()
* Given a hash index, return the next one OR return -1 for no more hash indicies to return.
*/
int ecm_db_iface_hash_index_get_next(int index)
{
index++;
if (index >= ECM_DB_IFACE_HASH_SLOTS) {
return -1;
}
return index;
}
EXPORT_SYMBOL(ecm_db_iface_hash_index_get_next);
/*
* ecm_db_iface_hash_index_get_first()
* Return first hash index
*/
int ecm_db_iface_hash_index_get_first(void)
{
return 0;
}
EXPORT_SYMBOL(ecm_db_iface_hash_index_get_first);
#endif
/*
* _ecm_db_iface_ref()
*/
void _ecm_db_iface_ref(struct ecm_db_iface_instance *ii)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
ii->refs++;
DEBUG_TRACE("%px: iface ref %d\n", ii, ii->refs);
DEBUG_ASSERT(ii->refs > 0, "%px: ref wrap\n", ii);
}
/*
* ecm_db_iface_ref()
*/
void ecm_db_iface_ref(struct ecm_db_iface_instance *ii)
{
spin_lock_bh(&ecm_db_lock);
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
}
EXPORT_SYMBOL(ecm_db_iface_ref);
/*
* ecm_db_iface_deref()
* Deref a interface instance, removing it from the database on the last ref release
*/
int ecm_db_iface_deref(struct ecm_db_iface_instance *ii)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
/*
* Decrement reference count
*/
spin_lock_bh(&ecm_db_lock);
ii->refs--;
DEBUG_TRACE("%px: iface deref %d\n", ii, ii->refs);
DEBUG_ASSERT(ii->refs >= 0, "%px: ref wrap\n", ii);
if (ii->refs > 0) {
int refs = ii->refs;
spin_unlock_bh(&ecm_db_lock);
return refs;
}
#ifdef ECM_DB_XREF_ENABLE
DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%px: nodes not null\n", ii);
#endif
/*
* Remove from database if inserted
*/
if (!ii->flags & ECM_DB_IFACE_FLAGS_INSERTED) {
spin_unlock_bh(&ecm_db_lock);
} else {
struct ecm_db_listener_instance *li;
/*
* Remove from the global list
*/
if (!ii->prev) {
DEBUG_ASSERT(ecm_db_interfaces == ii, "%px: interface table bad\n", ii);
ecm_db_interfaces = ii->next;
} else {
ii->prev->next = ii->next;
}
if (ii->next) {
ii->next->prev = ii->prev;
}
ii->prev = NULL;
ii->next = NULL;
/*
* Link out of hash table
*/
if (!ii->hash_prev) {
DEBUG_ASSERT(ecm_db_iface_table[ii->hash_index] == ii, "%px: hash table bad got %px for hash index %u\n", ii, ecm_db_iface_table[ii->hash_index], ii->hash_index);
ecm_db_iface_table[ii->hash_index] = ii->hash_next;
} else {
ii->hash_prev->hash_next = ii->hash_next;
}
if (ii->hash_next) {
ii->hash_next->hash_prev = ii->hash_prev;
}
ii->hash_next = NULL;
ii->hash_prev = NULL;
ecm_db_iface_table_lengths[ii->hash_index]--;
DEBUG_ASSERT(ecm_db_iface_table_lengths[ii->hash_index] >= 0, "%px: invalid table len %d\n", ii, ecm_db_iface_table_lengths[ii->hash_index]);
/*
* Link out of interface identifier hash table
*/
if (!ii->iface_id_hash_prev) {
DEBUG_ASSERT(ecm_db_iface_id_table[ii->iface_id_hash_index] == ii, "%px: hash table bad got %px for hash index %u\n", ii, ecm_db_iface_id_table[ii->iface_id_hash_index], ii->iface_id_hash_index);
ecm_db_iface_id_table[ii->iface_id_hash_index] = ii->iface_id_hash_next;
} else {
ii->iface_id_hash_prev->iface_id_hash_next = ii->iface_id_hash_next;
}
if (ii->iface_id_hash_next) {
ii->iface_id_hash_next->iface_id_hash_prev = ii->iface_id_hash_prev;
}
ii->iface_id_hash_next = NULL;
ii->iface_id_hash_prev = NULL;
ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]--;
DEBUG_ASSERT(ecm_db_iface_id_table_lengths[ii->iface_id_hash_index] >= 0, "%px: invalid table len %d\n", ii, ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]);
spin_unlock_bh(&ecm_db_lock);
/*
* Throw removed event to listeners
*/
DEBUG_TRACE("%px: Throw iface removed event\n", ii);
li = ecm_db_listeners_get_and_ref_first();
while (li) {
struct ecm_db_listener_instance *lin;
if (li->iface_removed) {
li->iface_removed(li->arg, ii);
}
/*
* Get next listener
*/
lin = ecm_db_listener_get_and_ref_next(li);
ecm_db_listener_deref(li);
li = lin;
}
}
/*
* Throw final event
*/
if (ii->final) {
ii->final(ii->arg);
}
/*
* We can now destroy the instance
*/
DEBUG_CLEAR_MAGIC(ii);
kfree(ii);
/*
* Decrease global interface count
*/
spin_lock_bh(&ecm_db_lock);
ecm_db_iface_count--;
DEBUG_ASSERT(ecm_db_iface_count >= 0, "%px: iface count wrap\n", ii);
spin_unlock_bh(&ecm_db_lock);
return 0;
}
EXPORT_SYMBOL(ecm_db_iface_deref);
/*
* ecm_db_iface_ae_interface_identifier_get()
* Return the accel engine interface number of this ecm interface
*/
int32_t ecm_db_iface_ae_interface_identifier_get(struct ecm_db_iface_instance *ii)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
return ii->ae_interface_identifier;
}
EXPORT_SYMBOL(ecm_db_iface_ae_interface_identifier_get);
/*
* ecm_db_iface_ae_interface_identifier_set()
* Sets accel engine interface number of this ecm interface
*/
void ecm_db_iface_ae_interface_identifier_set(struct ecm_db_iface_instance *ii, uint32_t num)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
ii->ae_interface_identifier = num;
}
EXPORT_SYMBOL(ecm_db_iface_ae_interface_identifier_set);
/*
* ecm_db_iface_interface_identifier_get()
* Return the interface number of this ecm interface
*/
int32_t ecm_db_iface_interface_identifier_get(struct ecm_db_iface_instance *ii)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
return ii->interface_identifier;
}
EXPORT_SYMBOL(ecm_db_iface_interface_identifier_get);
/*
* ecm_db_iface_interface_name_get()
* Return the interface name of this ecm interface
*
* name_buffer should be at least of size IFNAMSIZ
*/
void ecm_db_iface_interface_name_get(struct ecm_db_iface_instance *ii, char *name_buffer)
{
DEBUG_CHECK_MAGIC(ii,
ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
strlcpy(name_buffer, ii->name, IFNAMSIZ);
}
EXPORT_SYMBOL(ecm_db_iface_interface_name_get);
/*
* ecm_db_iface_mtu_reset()
* Reset the mtu
*/
int32_t ecm_db_iface_mtu_reset(struct ecm_db_iface_instance *ii, int32_t mtu)
{
int32_t mtu_old;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
spin_lock_bh(&ecm_db_lock);
mtu_old = ii->mtu;
ii->mtu = mtu;
spin_unlock_bh(&ecm_db_lock);
DEBUG_INFO("%px: Mtu change from %d to %d\n", ii, mtu_old, mtu);
return mtu_old;
}
EXPORT_SYMBOL(ecm_db_iface_mtu_reset);
/*
* ecm_db_interfaces_get_and_ref_first()
* Obtain a ref to the first iface instance, if any
*/
struct ecm_db_iface_instance *ecm_db_interfaces_get_and_ref_first(void)
{
struct ecm_db_iface_instance *ii;
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_interfaces;
if (ii) {
_ecm_db_iface_ref(ii);
}
spin_unlock_bh(&ecm_db_lock);
return ii;
}
EXPORT_SYMBOL(ecm_db_interfaces_get_and_ref_first);
/*
* ecm_db_interface_get_and_ref_next()
* Return the next iface in the list given a iface
*/
struct ecm_db_iface_instance *ecm_db_interface_get_and_ref_next(struct ecm_db_iface_instance *ii)
{
struct ecm_db_iface_instance *iin;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
spin_lock_bh(&ecm_db_lock);
iin = ii->next;
if (iin) {
_ecm_db_iface_ref(iin);
}
spin_unlock_bh(&ecm_db_lock);
return iin;
}
EXPORT_SYMBOL(ecm_db_interface_get_and_ref_next);
#ifdef ECM_INTERFACE_SIT_ENABLE
/*
* ecm_db_iface_generate_hash_index_sit()
* Calculate the hash index.
*/
static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_sit(ip_addr_t saddr, ip_addr_t daddr)
{
uint32_t tuple1;
uint32_t tuple2;
uint32_t hash_val;
ECM_IP_ADDR_HASH(tuple1, saddr);
ECM_IP_ADDR_HASH(tuple2, daddr);
hash_val = (uint32_t)jhash_2words(tuple1, tuple2, ecm_db_jhash_rnd);
return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
}
#endif
#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
#ifdef ECM_IPV6_ENABLE
/*
* ecm_db_iface_generate_hash_index_tunipip6()
* Calculate the hash index.
*/
static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_tunipip6(ip_addr_t saddr, ip_addr_t daddr)
{
uint32_t tuple1;
uint32_t tuple2;
uint32_t hash_val;
ECM_IP_ADDR_HASH(tuple1, saddr);
ECM_IP_ADDR_HASH(tuple2, daddr);
hash_val = (uint32_t)jhash_2words(tuple1, tuple2, ecm_db_jhash_rnd);
return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
}
#endif
#endif
#ifdef ECM_INTERFACE_OVPN_ENABLE
/*
* ecm_db_iface_generate_hash_index_ovpn()
* Calculate the hash index.
*/
static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_ovpn(int32_t tun_ifnum)
{
uint32_t hash_val;
hash_val = (uint32_t)jhash_1word((uint32_t)tun_ifnum, ecm_db_jhash_rnd);
return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
}
#endif
/*
* ecm_db_iface_generate_hash_index_ethernet()
* Calculate the hash index.
*/
static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_ethernet(uint8_t *address)
{
uint32_t hash_val;
hash_val = (uint32_t)jhash(address, 6, ecm_db_jhash_rnd);
return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
}
#ifdef ECM_INTERFACE_PPPOE_ENABLE
/*
* ecm_db_iface_generate_hash_index_pppoe()
* Calculate the hash index.
*/
static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pppoe(uint16_t pppoe_session_id)
{
uint32_t hash_val;
hash_val = (uint32_t)jhash_1word((uint32_t)pppoe_session_id, ecm_db_jhash_rnd);
return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
}
#endif
#ifdef ECM_INTERFACE_L2TPV2_ENABLE
/*
* ecm_db_iface_generate_hash_index_pppol2tpv2()
* Calculate the hash index.
*/
static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pppol2tpv2(uint32_t pppol2tpv2_tunnel_id, uint32_t pppol2tpv2_session_id)
{
uint32_t hash_val;
hash_val = (uint32_t)jhash_2words(pppol2tpv2_tunnel_id, pppol2tpv2_session_id, ecm_db_jhash_rnd);
return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
}
#endif
#ifdef ECM_INTERFACE_PPTP_ENABLE
/*
* ecm_db_iface_generate_hash_index_pptp()
* Calculate the hash index.
*/
static 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)
{
uint32_t hash_val;
hash_val = (uint32_t)jhash_2words(pptp_src_call_id, pptp_dst_call_id, ecm_db_jhash_rnd);
return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
}
#endif
#ifdef ECM_INTERFACE_MAP_T_ENABLE
/*
* ecm_db_iface_generate_hash_index_map_t()
* Calculate the hash index.
*/
static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_map_t(int if_index)
{
uint32_t hash_val;
hash_val = (uint32_t)jhash_1word(if_index, ecm_db_jhash_rnd);
return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
}
#endif
#ifdef ECM_INTERFACE_GRE_TUN_ENABLE
/*
* ecm_db_iface_generate_hash_index_gre_tun()
* Calculate the hash index.
*/
static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_gre_tun(int if_index)
{
uint32_t hash_val;
hash_val = (uint32_t)jhash_1word(if_index, ecm_db_jhash_rnd);
return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
}
#endif
/*
* ecm_db_iface_generate_hash_index_unknown()
* Calculate the hash index.
*/
static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_unknown(uint32_t os_specific_ident)
{
uint32_t hash_val;
hash_val = (uint32_t)jhash_1word(os_specific_ident, ecm_db_jhash_rnd);
return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
}
/*
* ecm_db_iface_generate_hash_index_loopback()
* Calculate the hash index.
*/
static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_loopback(uint32_t os_specific_ident)
{
uint32_t hash_val;
hash_val = (uint32_t)jhash_1word(os_specific_ident, ecm_db_jhash_rnd);
return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
}
#ifdef ECM_INTERFACE_IPSEC_ENABLE
/*
* ecm_db_iface_generate_hash_index_ipsec_tunnel()
* Calculate the hash index.
* GGG TODO Flesh this out using actual tunnel endpoint keys
*/
static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_ipsec_tunnel(uint32_t os_specific_ident)
{
uint32_t hash_val;
hash_val = (uint32_t)jhash_1word(os_specific_ident, ecm_db_jhash_rnd);
return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
}
#endif
#ifdef ECM_INTERFACE_VXLAN_ENABLE
/*
* ecm_db_iface_generate_hash_index_vxlan()
* Calculate the hash index based on VxLAN network identifier and interface type.
*/
static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_vxlan(uint32_t vni, uint32_t if_type)
{
uint32_t hash_val;
hash_val = (uint32_t)jhash_2words(vni, if_type, ecm_db_jhash_rnd);
return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
}
#endif
/*
* ecm_db_iface_ethernet_address_get()
* Obtain the ethernet address for an ethernet interface
*/
void ecm_db_iface_ethernet_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_ETHERNET, "%px: Bad type, expected ethernet, actual: %d\n", ii, ii->type);
spin_lock_bh(&ecm_db_lock);
ether_addr_copy(address, ii->type_info.ethernet.address);
spin_unlock_bh(&ecm_db_lock);
}
EXPORT_SYMBOL(ecm_db_iface_ethernet_address_get);
/*
* ecm_db_iface_bridge_address_get()
* Obtain the ethernet address for a bridge interface
*/
void ecm_db_iface_bridge_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_BRIDGE, "%px: Bad type, expected bridge, actual: %d\n", ii, ii->type);
spin_lock_bh(&ecm_db_lock);
ether_addr_copy(address, ii->type_info.bridge.address);
spin_unlock_bh(&ecm_db_lock);
}
EXPORT_SYMBOL(ecm_db_iface_bridge_address_get);
#ifdef ECM_INTERFACE_OVS_BRIDGE_ENABLE
/*
* ecm_db_iface_ovs_bridge_address_get()
* Obtain the ethernet address for a ovs bridge interface
*/
void ecm_db_iface_ovs_bridge_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_OVS_BRIDGE, "%px: Bad type, expected ovs bridge, actual: %d\n", ii, ii->type);
spin_lock_bh(&ecm_db_lock);
ether_addr_copy(address, ii->type_info.ovsb.address);
spin_unlock_bh(&ecm_db_lock);
}
#endif
#ifdef ECM_INTERFACE_BOND_ENABLE
/*
* ecm_db_iface_lag_address_get()
* Obtain the ethernet address for a LAG interface
*/
void ecm_db_iface_lag_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_LAG, "%px: Bad type, expected LAG, actual: %d\n", ii, ii->type);
spin_lock_bh(&ecm_db_lock);
ether_addr_copy(address, ii->type_info.lag.address);
spin_unlock_bh(&ecm_db_lock);
}
EXPORT_SYMBOL(ecm_db_iface_lag_address_get);
#endif
/*
* _ecm_db_iface_identifier_hash_table_insert_entry()
* Calculate the hash index based on updated interface_identifier, and
* re-insert into interface identifier chain.
*
* Note: Must take ecm_db_lock before calling this.
*/
static void _ecm_db_iface_identifier_hash_table_insert_entry(struct ecm_db_iface_instance *ii, int32_t interface_identifier)
{
ecm_db_iface_id_hash_t iface_id_hash_index;
/*
* Compute hash chain for insertion
*/
iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
ii->iface_id_hash_index = iface_id_hash_index;
/*
* Insert into interface identifier chain
*/
ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
if (ecm_db_iface_id_table[iface_id_hash_index]) {
ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
}
ecm_db_iface_id_table[iface_id_hash_index] = ii;
ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%px: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
}
/*
* _ecm_db_iface_identifier_hash_table_remove_entry()
* Remove an entry of a given interface instance from interface identifier chain.
*
* Note: Must take ecm_db_lock before calling this.
*/
static void _ecm_db_iface_identifier_hash_table_remove_entry(struct ecm_db_iface_instance *ii)
{
/*
* Remove from database if inserted
*/
if (!ii->flags & ECM_DB_IFACE_FLAGS_INSERTED) {
return;
}
/*
* Link out of interface identifier hash table
*/
if (!ii->iface_id_hash_prev) {
DEBUG_ASSERT(ecm_db_iface_id_table[ii->iface_id_hash_index] == ii, "%px: hash table bad got %px for hash index %u\n", ii, ecm_db_iface_id_table[ii->iface_id_hash_index], ii->iface_id_hash_index);
ecm_db_iface_id_table[ii->iface_id_hash_index] = ii->iface_id_hash_next;
} else {
ii->iface_id_hash_prev->iface_id_hash_next = ii->iface_id_hash_next;
}
if (ii->iface_id_hash_next) {
ii->iface_id_hash_next->iface_id_hash_prev = ii->iface_id_hash_prev;
}
ii->iface_id_hash_next = NULL;
ii->iface_id_hash_prev = NULL;
ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]--;
DEBUG_ASSERT(ecm_db_iface_id_table_lengths[ii->iface_id_hash_index] >= 0, "%px: invalid table len %d\n", ii, ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]);
}
/*
* ecm_db_iface_identifier_hash_table_entry_check_and_update()
* Update the hash table entry of interface identifier hash table.
* First remove the 'ii' from curent hash index position, re-calculate new hash and re-insert
* the 'ii' at new hash index position into interface identifier hash table.
*/
void ecm_db_iface_identifier_hash_table_entry_check_and_update(struct ecm_db_iface_instance *ii, int32_t new_interface_identifier)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
spin_lock_bh(&ecm_db_lock);
if (ii->interface_identifier == new_interface_identifier) {
spin_unlock_bh(&ecm_db_lock);
return;
}
DEBUG_TRACE("%px: interface ifindex has changed Old %d, New %d \n", ii, ii->interface_identifier, new_interface_identifier);
_ecm_db_iface_identifier_hash_table_remove_entry(ii);
ii->interface_identifier = new_interface_identifier;
_ecm_db_iface_identifier_hash_table_insert_entry(ii, new_interface_identifier);
spin_unlock_bh(&ecm_db_lock);
}
EXPORT_SYMBOL(ecm_db_iface_identifier_hash_table_entry_check_and_update);
/*
* ecm_db_iface_find_and_ref_by_interface_identifier()
* Return an interface based on a hlos interface identifier
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_by_interface_identifier(int32_t interface_id)
{
ecm_db_iface_id_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup database iface with interface_id %d\n", interface_id);
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_id_generate_hash_index(interface_id);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_id_table[hash_index];
while (ii) {
if (ii->interface_identifier == interface_id) {
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
/*
* Try next
*/
ii = ii->iface_id_hash_next;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_by_interface_identifier);
/*
* ecm_db_iface_ifidx_find_and_ref_ethernet()
* Return an interface based on a MAC address and interface hlos interface identifier
*/
struct ecm_db_iface_instance *ecm_db_iface_ifidx_find_and_ref_ethernet(uint8_t *address, int32_t ifidx)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup ethernet iface with addr %pM\n", address);
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_ETHERNET)
|| memcmp(ii->type_info.ethernet.address, address, ETH_ALEN)
|| ii->interface_identifier != ifidx) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_ifidx_find_and_ref_ethernet);
#ifdef ECM_INTERFACE_VLAN_ENABLE
/*
* ecm_db_iface_vlan_info_get()
* Get vlan interface specific information
*/
void ecm_db_iface_vlan_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_vlan *vlan_info)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_VLAN, "%px: Bad type, expected vlan, actual: %d\n", ii, ii->type);
spin_lock_bh(&ecm_db_lock);
ether_addr_copy(vlan_info->address, ii->type_info.vlan.address);
vlan_info->vlan_tag = ii->type_info.vlan.vlan_tag;
vlan_info->vlan_tpid = ii->type_info.vlan.vlan_tpid;
spin_unlock_bh(&ecm_db_lock);
}
EXPORT_SYMBOL(ecm_db_iface_vlan_info_get);
/*
* ecm_db_iface_find_and_ref_vlan()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_vlan(uint8_t *address, uint16_t vlan_tag, uint16_t vlan_tpid)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup vlan iface with addr %pM, vlan tag: %x vlan tpid: %x\n", address, vlan_tag, vlan_tpid);
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_VLAN) || (ii->type_info.vlan.vlan_tag != vlan_tag)
|| (ii->type_info.vlan.vlan_tpid != vlan_tpid)
|| memcmp(ii->type_info.vlan.address, address, ETH_ALEN)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_vlan);
#endif
#ifdef ECM_INTERFACE_MACVLAN_ENABLE
/*
* ecm_db_iface_find_and_ref_macvlan()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_macvlan(uint8_t *address)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup macvlan iface with addr %pM\n", address);
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_MACVLAN) || !ether_addr_equal(ii->type_info.macvlan.address, address)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
/*
* ecm_db_iface_macvlan_address_get()
* Obtain the ethernet address for a macvlan interface
*/
void ecm_db_iface_macvlan_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
{
spin_lock_bh(&ecm_db_lock);
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_MACVLAN, "%px: Bad type, expected macvlan, actual: %d\n", ii, ii->type);
ether_addr_copy(address, ii->type_info.macvlan.address);
spin_unlock_bh(&ecm_db_lock);
}
#endif
#ifdef ECM_INTERFACE_VXLAN_ENABLE
/*
* ecm_db_iface_find_and_ref_vxlan()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_vxlan(uint32_t vni, uint32_t type)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup vxlan iface with vxlan id: %d & if_type: %d\n", vni, type);
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_vxlan(vni, type);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_VXLAN)
|| (ii->type_info.vxlan.vni != vni)
|| (ii->type_info.vxlan.if_type != type)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
#endif
/*
* ecm_db_iface_find_and_ref_bridge()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_bridge(uint8_t *address, int32_t if_num)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup bridge iface with addr %pM\n", address);
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_BRIDGE)
|| memcmp(ii->type_info.bridge.address, address, ETH_ALEN)
|| ii->interface_identifier != if_num) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_bridge);
#ifdef ECM_INTERFACE_OVS_BRIDGE_ENABLE
/*
* ecm_db_iface_find_and_ref_ovs_bridge()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_ovs_bridge(uint8_t *address, int32_t if_num)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup OVS bridge iface with addr %pM\n", address);
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_OVS_BRIDGE)
|| memcmp(ii->type_info.ovsb.address, address, ETH_ALEN)
|| (ii->interface_identifier != if_num)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
#endif
#ifdef ECM_INTERFACE_BOND_ENABLE
/*
* ecm_db_iface_find_and_ref_lag()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_lag(uint8_t *address)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup lag iface with addr %pM\n", address);
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_LAG) || memcmp(ii->type_info.lag.address, address, ETH_ALEN)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_lag);
#endif
#ifdef ECM_INTERFACE_PPPOE_ENABLE
/*
* ecm_db_iface_pppoe_session_info_get()
* Get pppoe interface specific information
*/
void ecm_db_iface_pppoe_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppoe *pppoe_info)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPPOE, "%px: Bad type, expected pppoe, actual: %d\n", ii, ii->type);
spin_lock_bh(&ecm_db_lock);
ether_addr_copy(pppoe_info->remote_mac, ii->type_info.pppoe.remote_mac);
pppoe_info->pppoe_session_id = ii->type_info.pppoe.pppoe_session_id;
spin_unlock_bh(&ecm_db_lock);
}
EXPORT_SYMBOL(ecm_db_iface_pppoe_session_info_get);
/*
* ecm_db_iface_find_and_ref_pppoe()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pppoe(uint16_t pppoe_session_id, uint8_t *remote_mac)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup pppoe iface with addr %x\n", pppoe_session_id);
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_pppoe(pppoe_session_id);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_PPPOE)
|| (ii->type_info.pppoe.pppoe_session_id != pppoe_session_id)
|| memcmp(ii->type_info.pppoe.remote_mac, remote_mac, ETH_ALEN)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pppoe);
#endif
/*
* ecm_db_iface_update_ae_interface_identifier()
* update ae_interface_identifier in iface instance.
*/
void ecm_db_iface_update_ae_interface_identifier(struct ecm_db_iface_instance *ii, int32_t ae_interface_identifier)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
spin_lock_bh(&ecm_db_lock);
if (ii->ae_interface_identifier == ae_interface_identifier) {
spin_unlock_bh(&ecm_db_lock);
return;
}
ii->ae_interface_identifier = ae_interface_identifier;
spin_unlock_bh(&ecm_db_lock);
}
EXPORT_SYMBOL(ecm_db_iface_update_ae_interface_identifier);
#ifdef ECM_INTERFACE_L2TPV2_ENABLE
/*
* ecm_db_iface_pppol2tpv2_session_info_get
* get l2tpv2 specific info
*/
void ecm_db_iface_pppol2tpv2_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppol2tpv2 *pppol2tpv2_info)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPPOL2TPV2, "%px: Bad type, expected pppol2tpv2, actual: %d\n", ii, ii->type);
spin_lock_bh(&ecm_db_lock);
memcpy(pppol2tpv2_info, &ii->type_info.pppol2tpv2, sizeof(struct ecm_db_interface_info_pppol2tpv2));
spin_unlock_bh(&ecm_db_lock);
}
EXPORT_SYMBOL(ecm_db_iface_pppol2tpv2_session_info_get);
/*
* ecm_db_iface_find_and_ref_pppol2tpv2()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pppol2tpv2(uint32_t pppol2tpv2_tunnel_id, uint32_t pppol2tpv2_session_id)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_pppol2tpv2(pppol2tpv2_tunnel_id, pppol2tpv2_session_id);
DEBUG_TRACE("Lookup pppol2tpv2 iface with local_tunnel_id = %d, local_session_id = %d, hash = 0x%x\n", pppol2tpv2_tunnel_id,
pppol2tpv2_session_id, hash_index);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_PPPOL2TPV2)
|| (ii->type_info.pppol2tpv2.l2tp.session.session_id != pppol2tpv2_session_id)
|| (ii->type_info.pppol2tpv2.l2tp.tunnel.tunnel_id != pppol2tpv2_tunnel_id)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pppol2tpv2);
#endif
#ifdef ECM_INTERFACE_PPTP_ENABLE
/*
* ecm_db_iface_pptp_session_info_get
* get pptp specific info
*/
void ecm_db_iface_pptp_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPTP, "%px: Bad type, expected pptp, actual: %d\n", ii, ii->type);
spin_lock_bh(&ecm_db_lock);
memcpy(pptp_info, &ii->type_info.pptp, sizeof(struct ecm_db_interface_info_pptp));
spin_unlock_bh(&ecm_db_lock);
}
EXPORT_SYMBOL(ecm_db_iface_pptp_session_info_get);
/*
* ecm_db_iface_find_and_ref_pptp()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pptp(uint32_t pptp_src_call_id, uint32_t pptp_dst_call_id, int32_t ae_interface_num)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_pptp(pptp_src_call_id, pptp_dst_call_id);
DEBUG_TRACE("Lookup pptp iface with local_call_id = %d, remote_call_id = %d, hash = 0x%x\n", pptp_src_call_id,
pptp_dst_call_id, hash_index);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_PPTP)
|| (ii->type_info.pptp.src_call_id != pptp_src_call_id)
|| (ii->type_info.pptp.dst_call_id != pptp_dst_call_id)
|| (ii->ae_interface_identifier != ae_interface_num)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pptp);
#endif
#ifdef ECM_INTERFACE_MAP_T_ENABLE
/*
* ecm_db_iface_map_t_info_get
* get map_t specific info
*/
void ecm_db_iface_map_t_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_map_t *map_t_info)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_MAP_T, "%px: Bad type, expected map_t, actual: %d\n", ii, ii->type);
spin_lock_bh(&ecm_db_lock);
memcpy(map_t_info, &ii->type_info.map_t, sizeof(struct ecm_db_interface_info_map_t));
spin_unlock_bh(&ecm_db_lock);
}
EXPORT_SYMBOL(ecm_db_iface_map_t_info_get);
/*
* ecm_db_iface_find_and_ref_map_t()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_map_t(int if_index, int32_t ae_interface_num)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup map_t iface with if_index = %d\n", if_index);
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_map_t(if_index);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_MAP_T)
|| (ii->type_info.map_t.if_index != if_index)
|| (ii->ae_interface_identifier != ae_interface_num)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("%px: iface found\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_map_t);
#endif
#ifdef ECM_INTERFACE_GRE_TUN_ENABLE
/*
* ecm_db_iface_gre_tun_info_get
* Get gre specific info
*/
void ecm_db_iface_gre_tun_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_gre_tun *gre_tun_info)
{
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_GRE_TUN, "%px: Bad type, expected gre, actual: %d\
n", ii, ii->type);
spin_lock_bh(&ecm_db_lock);
memcpy(gre_tun_info, &ii->type_info.gre_tun, sizeof(struct ecm_db_interface_info_gre_tun));
spin_unlock_bh(&ecm_db_lock);
}
EXPORT_SYMBOL(ecm_db_iface_gre_tun_info_get);
/*
* ecm_db_iface_find_and_ref_gre()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_gre_tun(int if_index, int32_t ae_interface_num)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup gre iface with if_index = %d\n", if_index);
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_gre_tun(if_index);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_GRE_TUN)
|| (ii->type_info.gre_tun.if_index != if_index)
|| (ii->ae_interface_identifier != ae_interface_num)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("%px: iface found\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_gre_tun);
#endif
/*
* ecm_db_iface_find_and_ref_unknown()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_unknown(uint32_t os_specific_ident)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup unknown iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_unknown(os_specific_ident);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_UNKNOWN) || (ii->type_info.unknown.os_specific_ident != os_specific_ident)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_unknown);
/*
* ecm_db_iface_find_and_ref_loopback()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_loopback(uint32_t os_specific_ident)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup loopback iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_loopback(os_specific_ident);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_LOOPBACK) || (ii->type_info.loopback.os_specific_ident != os_specific_ident)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_loopback);
#ifdef ECM_INTERFACE_IPSEC_ENABLE
/*
* ecm_db_iface_find_and_ref_ipsec_tunnel()
* Lookup and return a iface reference if any.
* GGG TODO Flesh this out using tunnel endpoint keys
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_ipsec_tunnel(uint32_t os_specific_ident, int32_t ae_interface_num)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup ipsec_tunnel iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_ipsec_tunnel(os_specific_ident);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_IPSEC_TUNNEL)
|| (ii->type_info.ipsec_tunnel.os_specific_ident != os_specific_ident)
|| (ii->ae_interface_identifier != ae_interface_num)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_ipsec_tunnel);
#endif
#ifdef ECM_INTERFACE_SIT_ENABLE
/*
* ecm_db_iface_find_and_ref_sit()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_sit(ip_addr_t saddr, ip_addr_t daddr, int32_t ae_interface_num)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup sit (6-in-4) iface with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT "\n",
ECM_IP_ADDR_TO_OCTAL(saddr), ECM_IP_ADDR_TO_OCTAL(daddr));
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_sit(saddr, daddr);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_SIT)
|| !ECM_IP_ADDR_MATCH(ii->type_info.sit.saddr, saddr)
|| !ECM_IP_ADDR_MATCH(ii->type_info.sit.daddr, daddr)
|| (ii->ae_interface_identifier != ae_interface_num)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_sit);
#endif
#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
#ifdef ECM_IPV6_ENABLE
/*
* ecm_db_iface_find_and_ref_tunipip6()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_tunipip6(ip_addr_t saddr, ip_addr_t daddr, int32_t ae_interface_num)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup TUNIPIP6 iface with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT "\n",
ECM_IP_ADDR_TO_OCTAL(saddr), ECM_IP_ADDR_TO_OCTAL(daddr));
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_tunipip6(saddr, daddr);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_TUNIPIP6)
|| !ECM_IP_ADDR_MATCH(ii->type_info.tunipip6.saddr, saddr)
|| !ECM_IP_ADDR_MATCH(ii->type_info.tunipip6.daddr, daddr)
|| (ii->ae_interface_identifier != ae_interface_num)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_tunipip6);
#endif
#endif
#ifdef ECM_INTERFACE_RAWIP_ENABLE
/*
* ecm_db_iface_find_and_ref_rawip()
* Lookup and return a iface reference if any
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_rawip(uint8_t *address)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup RAWIP iface with addr %pM\n", address);
/*
* Compute the hash chain index and prepare to walk the chain
* We can use the same hash function of ethernet interface.
*/
hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
/*
* Iterate the chain looking for an iface with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_RAWIP)
|| memcmp(ii->type_info.rawip.address, address, ETH_ALEN)) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("%px: RAWIP iface found\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("RAWIP iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_rawip);
#endif
#ifdef ECM_INTERFACE_OVPN_ENABLE
/*
* ecm_db_iface_find_and_ref_ovpn()
* Lookup and return OVPN iface reference
*/
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_ovpn(int32_t tun_ifnum)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_iface_instance *ii;
DEBUG_TRACE("Lookup OVPN iface with ifnum: %d\n", tun_ifnum);
/*
* Compute the hash chain index and prepare to walk the chain
*/
hash_index = ecm_db_iface_generate_hash_index_ovpn(tun_ifnum);
/*
* Iterate the chain looking for a host with matching details
*/
spin_lock_bh(&ecm_db_lock);
ii = ecm_db_iface_table[hash_index];
while (ii) {
if ((ii->type != ECM_DB_IFACE_TYPE_OVPN)
|| ii->type_info.ovpn.tun_ifnum != tun_ifnum) {
ii = ii->hash_next;
continue;
}
_ecm_db_iface_ref(ii);
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("iface found %px\n", ii);
return ii;
}
spin_unlock_bh(&ecm_db_lock);
DEBUG_TRACE("Iface not found\n");
return NULL;
}
EXPORT_SYMBOL(ecm_db_iface_find_and_ref_ovpn);
#endif
#ifdef ECM_DB_XREF_ENABLE
/*
* ecm_db_iface_connections_get_and_ref_first()
* Return a reference to the first connection made for this iface on the specified direction.
*/
struct ecm_db_connection_instance *
ecm_db_iface_connections_get_and_ref_first(struct ecm_db_iface_instance *ii,
ecm_db_obj_dir_t dir)
{
struct ecm_db_connection_instance *ci;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
spin_lock_bh(&ecm_db_lock);
ci = ii->connections[dir];
if (ci) {
_ecm_db_connection_ref(ci);
}
spin_unlock_bh(&ecm_db_lock);
return ci;
}
EXPORT_SYMBOL(ecm_db_iface_connections_get_and_ref_first);
/*
* ecm_db_iface_nodes_get_and_ref_first()
* Return a reference to the first node made from this iface
*/
struct ecm_db_node_instance *ecm_db_iface_nodes_get_and_ref_first(struct ecm_db_iface_instance *ii)
{
struct ecm_db_node_instance *ni;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed", ii);
spin_lock_bh(&ecm_db_lock);
ni = ii->nodes;
if (ni) {
_ecm_db_node_ref(ni);
}
spin_unlock_bh(&ecm_db_lock);
return ni;
}
EXPORT_SYMBOL(ecm_db_iface_nodes_get_and_ref_first);
/*
* ecm_db_iface_node_count_get()
* Return the number of nodes to this iface
*/
int ecm_db_iface_node_count_get(struct ecm_db_iface_instance *ii)
{
int count;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
count = ii->node_count;
spin_unlock_bh(&ecm_db_lock);
return count;
}
EXPORT_SYMBOL(ecm_db_iface_node_count_get);
#endif
/*
* ecm_db_iface_add_to_db()
* Adds the created iface to the database lists.
*/
static inline void ecm_db_iface_add_to_db(struct ecm_db_iface_instance *ii, ecm_db_iface_hash_t hash_index)
{
ecm_db_iface_id_hash_t iface_id_hash_index;
struct ecm_db_listener_instance *li;
ii->hash_index = hash_index;
iface_id_hash_index = ecm_db_iface_id_generate_hash_index(ii->interface_identifier);
ii->iface_id_hash_index = iface_id_hash_index;
/*
* Add into the global list
*/
spin_lock_bh(&ecm_db_lock);
ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
ii->prev = NULL;
ii->next = ecm_db_interfaces;
if (ecm_db_interfaces) {
ecm_db_interfaces->prev = ii;
}
ecm_db_interfaces = ii;
/*
* Insert into chain
*/
ii->hash_prev = NULL;
ii->hash_next = ecm_db_iface_table[hash_index];
if (ecm_db_iface_table[hash_index]) {
ecm_db_iface_table[hash_index]->hash_prev = ii;
}
ecm_db_iface_table[hash_index] = ii;
ecm_db_iface_table_lengths[hash_index]++;
DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%px: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
DEBUG_INFO("%px: interface inserted at hash index %u, hash prev is %px, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
/*
* Insert into interface identifier chain
*/
ii->iface_id_hash_prev = NULL;
ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
if (ecm_db_iface_id_table[iface_id_hash_index]) {
ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
}
ecm_db_iface_id_table[iface_id_hash_index] = ii;
ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%px: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
/*
* Set time of addition
*/
ii->time_added = ecm_db_time;
spin_unlock_bh(&ecm_db_lock);
/*
* Throw add event to the listeners
*/
DEBUG_TRACE("%px: Throw iface added event\n", ii);
li = ecm_db_listeners_get_and_ref_first();
while (li) {
struct ecm_db_listener_instance *lin;
if (li->iface_added) {
li->iface_added(li->arg, ii);
}
/*
* Get next listener
*/
lin = ecm_db_listener_get_and_ref_next(li);
ecm_db_listener_deref(li);
li = lin;
}
}
/*
* ecm_db_iface_add_ethernet()
* Add a iface instance into the database
*/
void ecm_db_iface_add_ethernet(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
int32_t interface_identifier, int32_t ae_interface_identifier,
ecm_db_iface_final_callback_t final, void *arg)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_interface_info_ethernet *type_info;
spin_lock_bh(&ecm_db_lock);
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
DEBUG_ASSERT(address, "%px: address null\n", ii);
#ifdef ECM_DB_XREF_ENABLE
DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%px: nodes not null\n", ii);
#endif
DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%px: inserted\n", ii);
DEBUG_ASSERT(name, "%px: no name given\n", ii);
spin_unlock_bh(&ecm_db_lock);
/*
* Record general info
*/
ii->type = ECM_DB_IFACE_TYPE_ETHERNET;
#ifdef ECM_STATE_OUTPUT_ENABLE
ii->state_get = ecm_db_iface_ethernet_state_get;
#endif
ii->arg = arg;
ii->final = final;
strlcpy(ii->name, name, IFNAMSIZ);
ii->mtu = mtu;
ii->interface_identifier = interface_identifier;
ii->ae_interface_identifier = ae_interface_identifier;
/*
* Type specific info
*/
type_info = &ii->type_info.ethernet;
memcpy(type_info->address, address, ETH_ALEN);
/*
* Compute hash chain for insertion
*/
hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
ecm_db_iface_add_to_db(ii, hash_index);
}
EXPORT_SYMBOL(ecm_db_iface_add_ethernet);
#ifdef ECM_INTERFACE_BOND_ENABLE
/*
* ecm_db_iface_add_lag()
* Add a iface instance into the database
*/
void ecm_db_iface_add_lag(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
int32_t interface_identifier, int32_t ae_interface_identifier,
ecm_db_iface_final_callback_t final, void *arg)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_interface_info_lag *type_info;
spin_lock_bh(&ecm_db_lock);
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
DEBUG_ASSERT(address, "%px: address null\n", ii);
#ifdef ECM_DB_XREF_ENABLE
DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%px: nodes not null\n", ii);
#endif
DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%px: inserted\n", ii);
DEBUG_ASSERT(name, "%px: no name given\n", ii);
spin_unlock_bh(&ecm_db_lock);
/*
* Record general info
*/
ii->type = ECM_DB_IFACE_TYPE_LAG;
#ifdef ECM_STATE_OUTPUT_ENABLE
ii->state_get = ecm_db_iface_lag_state_get;
#endif
ii->arg = arg;
ii->final = final;
strlcpy(ii->name, name, IFNAMSIZ);
ii->mtu = mtu;
ii->interface_identifier = interface_identifier;
ii->ae_interface_identifier = ae_interface_identifier;
/*
* Type specific info
*/
type_info = &ii->type_info.lag;
memcpy(type_info->address, address, ETH_ALEN);
/*
* Compute hash chain for insertion
*/
hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
ecm_db_iface_add_to_db(ii, hash_index);
}
EXPORT_SYMBOL(ecm_db_iface_add_lag);
#endif
/*
* ecm_db_iface_add_bridge()
* Add a iface instance into the database
*/
void ecm_db_iface_add_bridge(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
int32_t interface_identifier, int32_t ae_interface_identifier,
ecm_db_iface_final_callback_t final, void *arg)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_interface_info_bridge *type_info;
spin_lock_bh(&ecm_db_lock);
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
DEBUG_ASSERT(address, "%px: address null\n", ii);
#ifdef ECM_DB_XREF_ENABLE
DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%px: nodes not null\n", ii);
#endif
DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%px: inserted\n", ii);
DEBUG_ASSERT(name, "%px: no name given\n", ii);
spin_unlock_bh(&ecm_db_lock);
/*
* Record general info
*/
ii->type = ECM_DB_IFACE_TYPE_BRIDGE;
#ifdef ECM_STATE_OUTPUT_ENABLE
ii->state_get = ecm_db_iface_bridge_state_get;
#endif
ii->arg = arg;
ii->final = final;
strlcpy(ii->name, name, IFNAMSIZ);
ii->mtu = mtu;
ii->interface_identifier = interface_identifier;
ii->ae_interface_identifier = ae_interface_identifier;
/*
* Type specific info
*/
type_info = &ii->type_info.bridge;
memcpy(type_info->address, address, ETH_ALEN);
/*
* Compute hash chain for insertion
*/
hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
ecm_db_iface_add_to_db(ii, hash_index);
}
EXPORT_SYMBOL(ecm_db_iface_add_bridge);
#ifdef ECM_INTERFACE_OVS_BRIDGE_ENABLE
/*
* ecm_db_iface_add_ovs_bridge()
* Add a iface instance into the database
*/
void ecm_db_iface_add_ovs_bridge(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
int32_t interface_identifier, int32_t ae_interface_identifier,
ecm_db_iface_final_callback_t final, void *arg)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_interface_info_ovs_bridge *type_info;
spin_lock_bh(&ecm_db_lock);
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
DEBUG_ASSERT(address, "%px: address null\n", ii);
#ifdef ECM_DB_XREF_ENABLE
DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%px: nodes not null\n", ii);
#endif
DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%px: inserted\n", ii);
DEBUG_ASSERT(name, "%px: no name given\n", ii);
spin_unlock_bh(&ecm_db_lock);
/*
* Record general info
*/
ii->type = ECM_DB_IFACE_TYPE_OVS_BRIDGE;
#ifdef ECM_STATE_OUTPUT_ENABLE
ii->state_get = ecm_db_iface_ovs_bridge_state_get;
#endif
ii->arg = arg;
ii->final = final;
strlcpy(ii->name, name, IFNAMSIZ);
ii->mtu = mtu;
ii->interface_identifier = interface_identifier;
ii->ae_interface_identifier = ae_interface_identifier;
/*
* Type specific info
*/
type_info = &ii->type_info.ovsb;
memcpy(type_info->address, address, ETH_ALEN);
/*
* Compute hash chain for insertion
*/
hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
ecm_db_iface_add_to_db(ii, hash_index);
}
#endif
#ifdef ECM_INTERFACE_MACVLAN_ENABLE
/*
* ecm_db_iface_add_macvlan()
* Add a iface instance into the database
*/
void ecm_db_iface_add_macvlan(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
int32_t interface_identifier, int32_t ae_interface_identifier,
ecm_db_iface_final_callback_t final, void *arg)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_interface_info_macvlan *type_info;
spin_lock_bh(&ecm_db_lock);
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
DEBUG_ASSERT(address, "%px: address null\n", ii);
#ifdef ECM_DB_XREF_ENABLE
DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%px: nodes not null\n", ii);
#endif
DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%px: inserted\n", ii);
DEBUG_ASSERT(name, "%px: no name given\n", ii);
spin_unlock_bh(&ecm_db_lock);
/*
* Record general info
*/
ii->type = ECM_DB_IFACE_TYPE_MACVLAN;
#ifdef ECM_STATE_OUTPUT_ENABLE
ii->state_get = ecm_db_iface_macvlan_state_get;
#endif
ii->arg = arg;
ii->final = final;
strlcpy(ii->name, name, IFNAMSIZ);
ii->mtu = mtu;
ii->interface_identifier = interface_identifier;
ii->ae_interface_identifier = ae_interface_identifier;
/*
* Type specific info
*/
type_info = &ii->type_info.macvlan;
ether_addr_copy(type_info->address, address);
/*
* Compute hash chain for insertion
*/
hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
ecm_db_iface_add_to_db(ii, hash_index);
}
#endif
#ifdef ECM_INTERFACE_VLAN_ENABLE
/*
* ecm_db_iface_add_vlan()
* Add a iface instance into the database
*/
void 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,
int32_t interface_identifier, int32_t ae_interface_identifier,
ecm_db_iface_final_callback_t final, void *arg)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_interface_info_vlan *type_info;
spin_lock_bh(&ecm_db_lock);
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
DEBUG_ASSERT(address, "%px: address null\n", ii);
#ifdef ECM_DB_XREF_ENABLE
DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%px: nodes not null\n", ii);
#endif
DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%px: inserted\n", ii);
DEBUG_ASSERT(name, "%px: no name given\n", ii);
spin_unlock_bh(&ecm_db_lock);
/*
* Record general info
*/
ii->type = ECM_DB_IFACE_TYPE_VLAN;
#ifdef ECM_STATE_OUTPUT_ENABLE
ii->state_get = ecm_db_iface_vlan_state_get;
#endif
ii->arg = arg;
ii->final = final;
strlcpy(ii->name, name, IFNAMSIZ);
ii->mtu = mtu;
ii->interface_identifier = interface_identifier;
ii->ae_interface_identifier = ae_interface_identifier;
/*
* Type specific info
*/
type_info = &ii->type_info.vlan;
type_info->vlan_tag = vlan_tag;
type_info->vlan_tpid = vlan_tpid;
memcpy(type_info->address, address, ETH_ALEN);
/*
* Compute hash chain for insertion
*/
hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
ecm_db_iface_add_to_db(ii, hash_index);
}
EXPORT_SYMBOL(ecm_db_iface_add_vlan);
#endif
#ifdef ECM_INTERFACE_MAP_T_ENABLE
/*
* ecm_db_iface_add_map_t()
* Add a iface instance into the database
*/
void ecm_db_iface_add_map_t(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_map_t *map_t_info,
char *name, int32_t mtu, int32_t interface_identifier,
int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
void *arg)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_interface_info_map_t *type_info;
spin_lock_bh(&ecm_db_lock);
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
#ifdef ECM_DB_XREF_ENABLE
DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%px: nodes not null\n", ii);
#endif
DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%px: inserted\n", ii);
DEBUG_ASSERT(name, "%px: no name given\n", ii);
spin_unlock_bh(&ecm_db_lock);
/*
* Record general info
*/
ii->type = ECM_DB_IFACE_TYPE_MAP_T;
#ifdef ECM_STATE_OUTPUT_ENABLE
ii->state_get = ecm_db_iface_map_t_state_get;
#endif
ii->arg = arg;
ii->final = final;
strlcpy(ii->name, name, IFNAMSIZ);
ii->mtu = mtu;
ii->interface_identifier = interface_identifier;
ii->ae_interface_identifier = ae_interface_identifier;
/*
* Type specific info
*/
type_info = &ii->type_info.map_t;
memcpy(type_info, map_t_info, sizeof(struct ecm_db_interface_info_map_t));
/*
* Compute hash chain for insertion
*/
hash_index = ecm_db_iface_generate_hash_index_map_t(type_info->if_index);
ecm_db_iface_add_to_db(ii, hash_index);
}
EXPORT_SYMBOL(ecm_db_iface_add_map_t);
#endif
#ifdef ECM_INTERFACE_GRE_TUN_ENABLE
/*
* ecm_db_iface_add_gre_tun()
* Add a iface instance into the database
*/
void ecm_db_iface_add_gre_tun(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_gre_tun *gre_tun_info,
char *name, int32_t mtu, int32_t interface_identifier,
int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
void *arg)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_interface_info_gre_tun *type_info;
spin_lock_bh(&ecm_db_lock);
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
#ifdef ECM_DB_XREF_ENABLE
DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%px: nodes not null\n", ii);
#endif
DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%px: inserted\n", ii);
DEBUG_ASSERT(name, "%px: no name given\n", ii);
spin_unlock_bh(&ecm_db_lock);
/*
* Record general info
*/
ii->type = ECM_DB_IFACE_TYPE_GRE_TUN;
#ifdef ECM_STATE_OUTPUT_ENABLE
ii->state_get = ecm_db_iface_gre_tun_state_get;
#endif
ii->arg = arg;
ii->final = final;
strlcpy(ii->name, name, IFNAMSIZ);
ii->mtu = mtu;
ii->interface_identifier = interface_identifier;
ii->ae_interface_identifier = ae_interface_identifier;
/*
* Type specific info
*/
type_info = &ii->type_info.gre_tun;
memcpy(type_info, gre_tun_info, sizeof(struct ecm_db_interface_info_gre_tun));
/*
* Compute hash chain for insertion
*/
hash_index = ecm_db_iface_generate_hash_index_gre_tun(type_info->if_index);
ecm_db_iface_add_to_db(ii, hash_index);
}
EXPORT_SYMBOL(ecm_db_iface_add_gre_tun);
#endif
#ifdef ECM_INTERFACE_PPPOE_ENABLE
/*
* ecm_db_iface_add_pppoe()
* Add a iface instance into the database
*/
void ecm_db_iface_add_pppoe(struct ecm_db_iface_instance *ii, uint16_t pppoe_session_id, uint8_t *remote_mac,
char *name, int32_t mtu, int32_t interface_identifier,
int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
void *arg)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_interface_info_pppoe *type_info;
spin_lock_bh(&ecm_db_lock);
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
#ifdef ECM_DB_XREF_ENABLE
DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%px: nodes not null\n", ii);
#endif
DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%px: inserted\n", ii);
DEBUG_ASSERT(name, "%px: no name given\n", ii);
spin_unlock_bh(&ecm_db_lock);
/*
* Record general info
*/
ii->type = ECM_DB_IFACE_TYPE_PPPOE;
#ifdef ECM_STATE_OUTPUT_ENABLE
ii->state_get = ecm_db_iface_pppoe_state_get;
#endif
ii->arg = arg;
ii->final = final;
strlcpy(ii->name, name, IFNAMSIZ);
ii->mtu = mtu;
ii->interface_identifier = interface_identifier;
ii->ae_interface_identifier = ae_interface_identifier;
/*
* Type specific info
*/
type_info = &ii->type_info.pppoe;
type_info->pppoe_session_id = pppoe_session_id;
memcpy(type_info->remote_mac, remote_mac, ETH_ALEN);
/*
* Compute hash chain for insertion
*/
hash_index = ecm_db_iface_generate_hash_index_pppoe(pppoe_session_id);
ecm_db_iface_add_to_db(ii, hash_index);
}
EXPORT_SYMBOL(ecm_db_iface_add_pppoe);
#endif
#ifdef ECM_INTERFACE_L2TPV2_ENABLE
/*
* ecm_db_iface_add_pppol2tpv2()
* Add a iface instance into the database
*/
void ecm_db_iface_add_pppol2tpv2(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppol2tpv2 *pppol2tpv2_info,
char *name, int32_t mtu, int32_t interface_identifier,
int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
void *arg)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_interface_info_pppol2tpv2 *type_info;
spin_lock_bh(&ecm_db_lock);
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
#ifdef ECM_DB_XREF_ENABLE
DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%px: nodes not null\n", ii);
#endif
DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%px: inserted\n", ii);
DEBUG_ASSERT(name, "%px: no name given\n", ii);
spin_unlock_bh(&ecm_db_lock);
/*
* Record general info
*/
ii->type = ECM_DB_IFACE_TYPE_PPPOL2TPV2;
#ifdef ECM_STATE_OUTPUT_ENABLE
ii->state_get = ecm_db_iface_pppol2tpv2_state_get;
#endif
ii->arg = arg;
ii->final = final;
strlcpy(ii->name, name, IFNAMSIZ);
ii->mtu = mtu;
ii->interface_identifier = interface_identifier;
ii->ae_interface_identifier = ae_interface_identifier;
/*
* Type specific info
*/
type_info = &ii->type_info.pppol2tpv2;
memcpy(type_info, pppol2tpv2_info, sizeof(struct ecm_db_interface_info_pppol2tpv2));
/*
* Compute hash chain for insertion
*/
hash_index = ecm_db_iface_generate_hash_index_pppol2tpv2(type_info->l2tp.tunnel.tunnel_id,
type_info->l2tp.session.session_id);
ecm_db_iface_add_to_db(ii, hash_index);
}
EXPORT_SYMBOL(ecm_db_iface_add_pppol2tpv2);
#endif
#ifdef ECM_INTERFACE_PPTP_ENABLE
/*
* ecm_db_iface_add_pptp()
* Add a iface instance into the database
*/
void ecm_db_iface_add_pptp(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info,
char *name, int32_t mtu, int32_t interface_identifier,
int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
void *arg)
{
ecm_db_iface_hash_t hash_index;
struct ecm_db_interface_info_pptp *type_info;
DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%px: magic failed\n", ii);
spin_lock_bh(&ecm_db_lock);
#ifdef ECM_DB_XREF_ENABLE
DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%px: nodes not null\n", ii);
#endif
DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%px: inserted\n", ii);
DEBUG_ASSERT(name, "%px: no name given\n", ii);
spin_unlock_bh(&ecm_db_lock);
/*
* Record general info
*/
ii->type = ECM_DB_IFACE_TYPE_PPTP;
#ifdef ECM_STATE_OUTPUT_ENABLE
ii->state_get = ecm_db_iface_pptp_state_get;
#endif
ii->arg = arg;
ii->final = final;
strlcpy(ii->name, name, IFNAMSIZ);
ii->mtu = mtu;
ii->interface_identifier = interface_identifier;
ii->ae_interface_identifier = ae_interface_identifier;
/*
* Type specific info
*/
type_info = &ii->type_info.pptp;
memcpy(type_info, pptp_info, sizeof(struct ecm_db_interface_info_pptp));
/*
* Compute hash chain for insertion
*/
hash_index = ecm_db_iface_generate_hash_index_pptp(type_info->src_call_id,
type_info->dst_call_id);
ecm_db_iface_add_to_db(ii, hash_index);
}
EXPORT_SYMBOL(ecm_db_iface_add_pptp);
#endif
/*
* ecm_db_iface_add_unknown()
* Add a iface instance into the database
*/
void ecm_db_iface_add_unknown(struct ecm_db_iface_instance