398 lines
12 KiB
C
398 lines
12 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip_netlink_kern.c,v $ $Revision: 1.7.10.1 $
|
|
* $Source: /home/interpeak/CVSRoot/ipmip/src/ipmip_netlink_kern.c,v $
|
|
* $Author: jsheng $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifndef IPCOM_KERNEL
|
|
#define IPCOM_KERNEL
|
|
#endif
|
|
|
|
#include "ipnet_config.h"
|
|
|
|
#if defined(IPNET)
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_type.h>
|
|
#include <ipcom_cstyle.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_sysvar.h>
|
|
#include <ipcom_inet.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_hash.h>
|
|
|
|
#include "ipnet_h.h"
|
|
#include "ipnet.h"
|
|
|
|
#ifdef IPTCP
|
|
#include "iptcp.h"
|
|
#endif
|
|
|
|
#include <private/ipmip_netlink_kern.h>
|
|
|
|
#ifdef IPMIP6
|
|
#include <private/ipmip6_netlink_kern.h>
|
|
#endif
|
|
|
|
#ifdef IPMIP4
|
|
#include <private/ipmip4_netlink_kern.h>
|
|
#endif
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPMIP_PKT_HAS_INFO(pkt) (pkt->next_extra_data != 0)
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
typedef struct Ipmip_netlink_kern
|
|
{
|
|
Ipcom_hash *handles[IPCOM_VR_MAX];
|
|
} Ipmip_netlink_kern_t;
|
|
|
|
/**/
|
|
IP_STATIC Ipmip_netlink_kern_t *ipmip_netlink_kern = IP_NULL;
|
|
|
|
|
|
IP_STATIC unsigned
|
|
ipmip_netlink_kern_handle_obj_hash(Ipmip_netlink_kern_handle_t *hdr)
|
|
{
|
|
return ipcom_hash_update(hdr, sizeof(*hdr), 0);
|
|
}
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmip_netlink_kern_handle_cmp_hash(Ipmip_netlink_kern_handle_t *obj1,
|
|
Ipmip_netlink_kern_handle_t *obj2)
|
|
{
|
|
/**/
|
|
return obj1->mip_facility == obj2->mip_facility && obj1->mip_ident == obj2->mip_ident;
|
|
}
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmip_netlink_kern_rt_flow_cmp(struct Ipnet_route_entry_struct *rtentry,
|
|
struct Ipnet_dst_cache_struct *dst)
|
|
{
|
|
struct Ipnet_route_func_info *rtinfo = rtentry->rt_func_info;
|
|
Ipmip_netlink_route_flow_info_t *rtflow = (Ipmip_netlink_route_flow_info_t *)(rtinfo + 1);
|
|
|
|
if (IP_BIT_ISSET(rtflow->type, IPMIP_NETLINK_KERN_INGRESS_IFINDEX))
|
|
{
|
|
if (dst->flow_spec.ingress_ifindex == 0)
|
|
{
|
|
IPCOM_LOG0(DEBUG2, "FLOW compare missed on INGRESS");
|
|
return IP_FALSE;
|
|
}
|
|
else if (rtflow->ifindex != 0 && rtflow->ifindex != dst->flow_spec.ingress_ifindex)
|
|
{
|
|
IPCOM_LOG0(DEBUG2, "FLOW compare missed on INGRESS IFINDEX");
|
|
return IP_FALSE;
|
|
}
|
|
}
|
|
|
|
if (IP_BIT_ISSET(rtflow->type, IPMIP_NETLINK_KERN_EGRESS_IFINDEX))
|
|
{
|
|
if (dst->flow_spec.ingress_ifindex != 0)
|
|
{
|
|
IPCOM_LOG0(DEBUG2, "FLOW compare missed on EGRESS");
|
|
return IP_FALSE;
|
|
}
|
|
else if (rtflow->ifindex != 0 && rtflow->ifindex != dst->flow_spec.egress_ifindex)
|
|
{
|
|
IPCOM_LOG0(DEBUG2, "FLOW compare missed on EGRESS IFINDEX");
|
|
return IP_FALSE;
|
|
}
|
|
}
|
|
|
|
if ((rtflow->flow.key.u64[0] != (dst->flow_spec.mip.key.u64[0] & rtflow->flow.mask.u64[0])) ||
|
|
(rtflow->flow.key.u64[1] != (dst->flow_spec.mip.key.u64[1] & rtflow->flow.mask.u64[1])) ||
|
|
(rtflow->flow.key.u64[2] != (dst->flow_spec.mip.key.u64[2] & rtflow->flow.mask.u64[2])))
|
|
{
|
|
IPCOM_LOG0(DEBUG2, "FLOW compare missed on FLOW");
|
|
return IP_FALSE;
|
|
}
|
|
|
|
/* Clear the flow spec values from this dst cache that arent used, just to speed up the cmps a bit */
|
|
dst->flow_spec.mip.key.u64[0] = dst->flow_spec.mip.key.u64[0] & rtflow->flow.mask.u64[0];
|
|
dst->flow_spec.mip.key.u64[1] = dst->flow_spec.mip.key.u64[1] & rtflow->flow.mask.u64[1];
|
|
dst->flow_spec.mip.key.u64[2] = dst->flow_spec.mip.key.u64[2] & rtflow->flow.mask.u64[2];
|
|
|
|
/* Store the mask */
|
|
ipcom_memcpy(&dst->flow_spec.mip.mask, &rtflow->flow.mask, sizeof(rtflow->flow.mask));
|
|
|
|
/* Setup the MIP DST cache init routine based on the Route's callbacks */
|
|
if (rtflow->flow_handle != IP_NULL)
|
|
{
|
|
dst->mip.flow_handle = rtflow->flow_handle;
|
|
dst->mip.flow_aux = ipcom_malloc(rtinfo->rt_info_size);
|
|
if(IP_NULL == dst->mip.flow_aux)
|
|
return IP_FALSE;
|
|
|
|
ipcom_memcpy(dst->mip.flow_aux, rtinfo, rtinfo->rt_info_size);
|
|
}
|
|
|
|
/**/
|
|
return IP_TRUE;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipmip_netlink_kern_rt_flow_set(struct Ipnet_route_func_info *rtinfo,
|
|
Ipmip_netlink_kern_compare_t *srccmp,
|
|
Ipnet_dst_cache_mip_handle flow_handle)
|
|
{
|
|
Ipmip_netlink_route_flow_info_t *rtflow = (Ipmip_netlink_route_flow_info_t *)(rtinfo + 1);
|
|
|
|
/* Set compare function */
|
|
rtinfo->rt_flow_cmp = (Ipnet_route_flow_spec_cmp_t)ipmip_netlink_kern_rt_flow_cmp;
|
|
|
|
/* Set init function */
|
|
rtflow->flow_handle = flow_handle;
|
|
|
|
if (IP_LIKELY(srccmp != IP_NULL))
|
|
{
|
|
if (IP_BIT_ISSET(srccmp->srcmac_type, IPMIP_NETLINK_KERN_PROTO))
|
|
{
|
|
rtflow->flow.mask.u8[1] = 0xFF;
|
|
rtflow->flow.key.u8[1] = srccmp->srcmac.proto;
|
|
}
|
|
|
|
/* Create the flow MASK */
|
|
if (IP_BIT_ISSET(srccmp->srcmac_type, IPMIP_NETLINK_KERN_TUNNEL|IPMIP_NETLINK_KERN_SRCMAC))
|
|
{
|
|
/* First field is ENCAP size */
|
|
rtflow->flow.mask.u8[0] = 0xFF;
|
|
rtflow->flow.key.u8[0] = srccmp->srcmac.srcmac_len;
|
|
|
|
ipcom_memcpy(&rtflow->flow.key.u32[1], &srccmp->srcmac.hdr.opaque[0], srccmp->srcmac.srcmac_len);
|
|
ipcom_memset(&rtflow->flow.mask.u32[1], 0xFF, srccmp->srcmac.srcmac_len);
|
|
}
|
|
|
|
if (IP_BIT_ISSET(srccmp->srcmac_type, IPMIP_NETLINK_KERN_INGRESS_IFINDEX|IPMIP_NETLINK_KERN_EGRESS_IFINDEX))
|
|
rtflow->ifindex = srccmp->srcmac.ifindex;
|
|
|
|
if (IP_BIT_ISSET(srccmp->srcmac_type, IPMIP_NETLINK_KERN_GREKEY))
|
|
{
|
|
rtflow->flow.key.u32[5] = srccmp->srcmac.gre_key;
|
|
rtflow->flow.mask.u32[5] = 0xFFFFFFFF;
|
|
}
|
|
|
|
rtflow->type = srccmp->srcmac_type;
|
|
}
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
IP_GLOBAL Ipmip_netlink_kern_handle_t *
|
|
ipmip_netlink_kern_handle_get(Ip_u32 vr, Ipmip_netlink_kern_handle_t *handle)
|
|
{
|
|
/**/
|
|
return (Ipmip_netlink_kern_handle_t *)ipcom_hash_get(ipmip_netlink_kern->handles[vr], handle);
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip_netlink_kern_handle_add(Ip_u32 vr, Ipmip_netlink_kern_handle_t *handle)
|
|
{
|
|
ipcom_hash_add(ipmip_netlink_kern->handles[vr], handle);
|
|
}
|
|
|
|
IP_GLOBAL Ipmip_netlink_kern_handle_t *
|
|
ipmip_netlink_kern_handle_del(Ip_u32 vr, Ipmip_netlink_kern_handle_t *handle)
|
|
{
|
|
Ipmip_netlink_kern_handle_t *rhandle = ipmip_netlink_kern_handle_get(vr, handle);
|
|
|
|
if (rhandle)
|
|
ipcom_hash_remove(ipmip_netlink_kern->handles[vr], rhandle);
|
|
|
|
/**/
|
|
return rhandle;
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip_netlink_kern_handle_free(Ip_u32 vr, Ipmip_netlink_kern_handle_t *handle)
|
|
{
|
|
handle = ipmip_netlink_kern_handle_del(vr, handle);
|
|
if (handle)
|
|
ipcom_free(handle);
|
|
}
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipmip_netlink_kern_if_include(Ipnet_netif *netif)
|
|
{
|
|
IP_BIT_CLR(netif->flags2, IPNET_IFF2_NO_GLOBAL_SRC);
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip_netlink_kern_if_exclude(Ipnet_netif *netif)
|
|
{
|
|
IP_BIT_SET(netif->flags2, IPNET_IFF2_NO_GLOBAL_SRC);
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip_netlink_kern_hoa_activate(Ipnet_netif *netif,
|
|
struct Ip_rtattr *rta)
|
|
{
|
|
Ipnet_socket *sock = IP_NULL;
|
|
Ipnet_socket *next_sock;
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
if (IP_RTA_PAYLOAD(rta) == sizeof(struct Ip_in6_addr))
|
|
{
|
|
Ipnet_ip6_addr_entry *entry = ipnet_ip6_get_addr_entry(IP_RTA_DATA(rta), netif->vr_index, netif);
|
|
|
|
/* Loop through all addresses */
|
|
if (entry != IP_NULL && IP_BIT_ISTRUE(entry->flags, IPNET_IP6_ADDR_FLAG_HOMEADDRESS))
|
|
{
|
|
/* Kickstart list */
|
|
#ifdef IPTCP
|
|
sock = entry->socket_list;
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef IPCOM_USE_INET
|
|
if (IP_RTA_PAYLOAD(rta) == sizeof(struct Ip_in_addr))
|
|
{
|
|
Ipnet_ip4_addr_entry *entry = ipnet_ip4_get_addr_entry(IP_GET_32ON8(IP_RTA_DATA(rta)), netif->vr_index, netif);
|
|
|
|
/* Loop through all addresses */
|
|
if (entry != IP_NULL && IP_BIT_ISTRUE(entry->flags, IPNET_IP4_ADDR_FLAG_HOMEADDRESS))
|
|
{
|
|
#ifdef IPTCP
|
|
sock = entry->socket_list;
|
|
#endif
|
|
IP_BIT_SET(entry->flags, IPNET_IP4_ADDR_FLAG_PREFERRED);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef IPTCP
|
|
while (sock != IP_NULL)
|
|
{
|
|
/* Locate next socket with the same address */
|
|
next_sock = sock->addr_next;
|
|
|
|
/* Do we have a notify CB */
|
|
if (sock->notify_cb != IP_NULL)
|
|
{
|
|
/* Kickstart it */
|
|
(*sock->notify_cb) (sock, IPTCP_SOCKET_EVENT_KICKSTART);
|
|
}
|
|
|
|
/* Do next socket */
|
|
sock = next_sock;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip_netlink_kern_hoa_deactivate(Ipnet_netif *netif,
|
|
struct Ip_rtattr *rta)
|
|
{
|
|
#ifdef IPCOM_USE_INET6
|
|
if (IP_RTA_PAYLOAD(rta) == sizeof(struct Ip_in6_addr))
|
|
{
|
|
Ipnet_ip6_addr_entry *entry = ipnet_ip6_get_addr_entry(IP_RTA_DATA(rta), netif->vr_index, netif);
|
|
|
|
/* Loop through all addresses */
|
|
if (entry != IP_NULL && IP_BIT_ISTRUE(entry->flags, IPNET_IP6_ADDR_FLAG_HOMEADDRESS))
|
|
{
|
|
/* Kickstart list */
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef IPCOM_USE_INET
|
|
if (IP_RTA_PAYLOAD(rta) == sizeof(struct Ip_in_addr))
|
|
{
|
|
Ipnet_ip4_addr_entry *entry = ipnet_ip4_get_addr_entry(IP_GET_32ON8(IP_RTA_DATA(rta)), netif->vr_index, netif);
|
|
|
|
/* Loop through all addresses */
|
|
if (entry != IP_NULL && IP_BIT_ISTRUE(entry->flags, IPNET_IP4_ADDR_FLAG_HOMEADDRESS))
|
|
{
|
|
IP_BIT_CLR(entry->flags, IPNET_IP4_ADDR_FLAG_PREFERRED);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip_rtnetlink_init(void)
|
|
{
|
|
int i;
|
|
/* Create the handles */
|
|
ipmip_netlink_kern = ipcom_calloc(1, sizeof(*ipmip_netlink_kern));
|
|
|
|
for (i = 0; i < IPCOM_VR_MAX; i++)
|
|
{
|
|
ipmip_netlink_kern->handles[i] = ipcom_hash_new((Ipcom_hash_obj_func) ipmip_netlink_kern_handle_obj_hash,
|
|
(Ipcom_hash_key_func) ipmip_netlink_kern_handle_obj_hash,
|
|
(Ipcom_hash_cmp_func) ipmip_netlink_kern_handle_cmp_hash);
|
|
}
|
|
|
|
#ifdef IPMIP6
|
|
ipmip6_rtnetlink_init();
|
|
#endif
|
|
#ifdef IPMIP4
|
|
ipmip4_rtnetlink_init();
|
|
#endif
|
|
}
|
|
|
|
#else
|
|
int ipmip_netlink_kern_empty_file = 0;
|
|
#endif
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|