1099 lines
48 KiB
C
1099 lines
48 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6ha_route.c,v $ $Revision: 1.23.10.2 $
|
|
* $Source: /home/interpeak/CVSRoot/ipmip6ha/src/ipmip6ha_route.c,v $
|
|
* $Author: svc-cmnet $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#include "ipmip6ha_config.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_os.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_sock6.h>
|
|
#include <ipcom_inet.h>
|
|
#include <ipcom_list.h>
|
|
#include <ipcom_hash.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_ipd.h>
|
|
|
|
#include <ipnet.h>
|
|
|
|
#include <ipmip.h>
|
|
#include <private/ipmip_util.h>
|
|
#include <private/ipmip_inet.h>
|
|
|
|
#include <ipmip6.h>
|
|
#include <private/ipmip6_context.h>
|
|
#include <private/ipmip6_mh.h>
|
|
#include <private/ipmip6_mh_pkt.h>
|
|
#include <private/ipmip6_netlink.h>
|
|
#include <private/ipmip6_if.h>
|
|
#include <private/ipmip6_util.h>
|
|
|
|
#include "ipmip6ha_h.h"
|
|
#include "ipmip6ha_pktbuf.h"
|
|
#include "ipmip6ha_mh.h"
|
|
#include "ipmip6ha_if.h"
|
|
#include "ipmip6ha_node.h"
|
|
#include "ipmip6ha_attr_h.h"
|
|
#include "ipmip6ha_route.h"
|
|
#include "ipmip6ha_nemo.h"
|
|
#include "ipmip6ha_nemo_dsmipv6.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
enum
|
|
{
|
|
IPMIP6HA_ROUTE_STATE_DO_ADD,
|
|
IPMIP6HA_ROUTE_STATE_DO_DEL,
|
|
};
|
|
|
|
#define IPMIP6HA_ROUTE_COA_SIZE(x) ((x) == IPMIP6_MIB_InetAddressType_ipv6? sizeof(struct Ip_in6_addr) : sizeof(Ip_u32))
|
|
|
|
#define IPMIP6HA_ROUTE_GRE(x) ((x)->registered.mip6BindingTunnelType == IPMIP_TUNNELTYPE_GRE || (x)->registered.mip6BindingTunnelType == IPMIP_TUNNELTYPE_GRE6)
|
|
#define IPMIP6HA_ROUTE_GRE_KEYS(x) (IPMIP6HA_ROUTE_GRE(x) && (x)->gre_keys[IPMIP_LINK_DOWN] && (x)->gre_keys[IPMIP_LINK_UP])
|
|
#define IPMIP6HA_ROUTE_GRE_DOWNLINK(x) (IPMIP6HA_ROUTE_GRE_KEYS(x)? (x)->gre_keys[IPMIP_LINK_DOWN] : IP_NULL)
|
|
#define IPMIP6HA_ROUTE_GRE_UPLINK(x) (IPMIP6HA_ROUTE_GRE_KEYS(x)? (x)->gre_keys[IPMIP_LINK_UP] : IP_NULL)
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
typedef void (*Ipmip6ha_route_state_do_t) (struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node,
|
|
int docmd);
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
IP_STATIC void ipmip6ha_route_state_ipv6(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node,
|
|
int docmd);
|
|
IP_STATIC void ipmip6ha_route_state_tunnel_ipv6(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node,
|
|
int docmd);
|
|
IP_STATIC void ipmip6ha_route_state_ipv6_nemo(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node,
|
|
int docmd);
|
|
IP_STATIC void ipmip6ha_route_state_ipv4_nemo(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node,
|
|
int docmd);
|
|
|
|
IP_STATIC void ipmip6ha_route_state_ipv4(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node,
|
|
int docmd);
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
static Ipmip6ha_route_state_do_t ipmip6ha_route_states[IPMIP6HA_ROUTE_BIT_MAX] =
|
|
{
|
|
ipmip6ha_route_state_ipv6,
|
|
ipmip6ha_route_state_tunnel_ipv6,
|
|
ipmip6ha_route_state_ipv6_nemo,
|
|
ipmip6ha_route_state_ipv4_nemo,
|
|
ipmip6ha_route_state_ipv4
|
|
};
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
IP_STATIC int
|
|
ipmip6ha_netlink_route_ro_rthdr(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ip_u8 flags,
|
|
Ip_u32 table,
|
|
Ip_u32 ifindex,
|
|
const struct Ip_in6_addr *hoa,
|
|
const struct Ip_in6_addr *coa,
|
|
const void *prefix,
|
|
Ip_size_t psize,
|
|
Ip_u32 prefix_len,
|
|
Ip_u32 rtf_flags,
|
|
Ip_u32 identity,
|
|
Ipmip_netlink_kern_compare_t *srccmp)
|
|
{
|
|
Ipmip_buffer_t rbuf;
|
|
Ip_size_t hdr_off;
|
|
struct Ip_mipmsg *msg;
|
|
int ret;
|
|
Ipmip_netlink_kern_handle_t handle;
|
|
|
|
ipmip_buffer_init(&rbuf);
|
|
|
|
/* Create NLMSG HDR */
|
|
ipmip_netlink_nlmsghdr_request(&rbuf, 0, 0, IP_RTM_NEWMIP, 0);
|
|
msg = ipmip_buffer_offset(&rbuf, ipmip_netlink_nlmsghdr_put(&rbuf, IP_NULL, sizeof(*msg)));
|
|
|
|
msg->mip_family = IP_AF_INET6;
|
|
msg->mip_type = IP_WRMOB6_NEW_ROUTE_RO_RTHDR;
|
|
msg->mip_flags = flags;
|
|
|
|
/* Create the nested HoA attribute */
|
|
hdr_off = ipmip_netlink_nlmsghdr_rta_begin(&rbuf, IP_MIP_ENCAP);
|
|
ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_IFINDEX, ifindex);
|
|
ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_DST, psize, prefix);
|
|
ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_DST_LEN, prefix_len);
|
|
ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_TABLE, table);
|
|
ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_FLAGS, rtf_flags);
|
|
|
|
if (srccmp)
|
|
ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_SRCMAC, sizeof(*srccmp), srccmp);
|
|
|
|
if (identity)
|
|
{
|
|
handle.mip_facility = IPCOM_IPD_ID_IPMIP6HA;
|
|
handle.mip_ident = identity;
|
|
ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_HANDLE, sizeof(handle), &handle);
|
|
}
|
|
|
|
if (hoa)
|
|
ipmip_netlink_nlmsghdr_rta_put_in6(&rbuf, IP_WRMOB6_ROUTE_HOA, hoa);
|
|
if (coa)
|
|
ipmip_netlink_nlmsghdr_rta_put_in6(&rbuf, IP_WRMOB6_ROUTE_COA, coa);
|
|
|
|
ipmip_netlink_nlmsghdr_rta_end(&rbuf, hdr_off);
|
|
|
|
/* Complete the buffer */
|
|
ipmip_netlink_nlmsghdr_done(&rbuf, 0);
|
|
|
|
/* NETLINK request */
|
|
ret = ipmip_netlink_request(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
ctx->ipmip6.ipmip.nl_req,
|
|
0,
|
|
0,
|
|
(struct Ip_nlmsghdr *)IPMIP_BUFFER_PTR(&rbuf),
|
|
IP_NULL);
|
|
/**/
|
|
ipmip_buffer_release(&rbuf);
|
|
|
|
if (ret < 0)
|
|
{
|
|
IPMIP6_EVENT_IF(ERR, proc,
|
|
ipmip_log_event_add(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
"Unable to perform MIP6 command NEW/RTHDR = %d", -ret));
|
|
}
|
|
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
IP_STATIC Ipmip_netlink_kern_compare_t *
|
|
ipmip6ha_route_state_cmp_tunnel_end(Ipmip_netlink_kern_compare_t *scmp,
|
|
Ipmip6ha_node_t *node)
|
|
{
|
|
Ip_u32 *gre_key = IPMIP6HA_ROUTE_GRE_UPLINK(node);
|
|
Ipmip_netlink_kern_compare_t *scmpp = IP_NULL;
|
|
|
|
if (gre_key || node->ifp_home->AlwaysVerifyTunnelSrc)
|
|
{
|
|
if (node->registered.mip6BindingCOAType == IPMIP6_MIB_InetAddressType_ipv6)
|
|
scmpp = ipmip_netlink_route_src_tunnel_in6(scmp, &node->registered.mip6BindingCOA.ipv6, gre_key);
|
|
#ifdef IPMIP_USE_INET
|
|
else
|
|
scmpp = ipmip_netlink_route_src_tunnel_in(scmp, node->registered.mip6BindingCOA.ipv4.s_addr, gre_key);
|
|
#endif
|
|
}
|
|
|
|
return scmpp;
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipmip6ha_route_state_ipv6(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node,
|
|
int docmd)
|
|
{
|
|
switch (docmd)
|
|
{
|
|
case IPMIP6HA_ROUTE_STATE_DO_ADD:
|
|
|
|
/* Add the R/O route to the home agent */
|
|
ipmip6ha_netlink_route_ro_rthdr(ctx,
|
|
proc,
|
|
0,
|
|
node->ifp_transport->iftables.route_optimize,
|
|
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
|
|
&node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6,
|
|
&node->registered.mip6BindingCOA.ipv6,
|
|
&node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6,
|
|
sizeof(node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6),
|
|
128,
|
|
IPNET_RTF_MBINDING|IPNET_RTF_BLACKHOLE,
|
|
node->identity,
|
|
IP_NULL);
|
|
break;
|
|
case IPMIP6HA_ROUTE_STATE_DO_DEL:
|
|
/* Delete the R/O route to the home agent */
|
|
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
IP_AF_INET6,
|
|
IP_RTM_DELROUTE,
|
|
node->ifp_transport->iftables.route_optimize,
|
|
0,
|
|
&node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6,
|
|
128,
|
|
IP_NULL,
|
|
IP_RTN_UNICAST);
|
|
break;
|
|
}
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipmip6ha_route_state_ipv6_nemo(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node,
|
|
int docmd)
|
|
{
|
|
Ipmip6ha_nemo_t *nemo, *nnemo;
|
|
Ipmip_netlink_kern_compare_t scmp;
|
|
Ipmip_netlink_kern_handle_t handle;
|
|
|
|
handle.mip_facility = IPCOM_IPD_ID_IPMIP6HA;
|
|
handle.mip_ident = node->identity;
|
|
|
|
switch (docmd)
|
|
{
|
|
case IPMIP6HA_ROUTE_STATE_DO_ADD:
|
|
for (nemo = IPCOM_LIST_FIRST(&node->nemo_v6); nemo != IP_NULL; nemo = nnemo)
|
|
{
|
|
nnemo = IPCOM_LIST_NEXT(&nemo->next);
|
|
|
|
/* Create inbound tunnel route */
|
|
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
|
|
proc,
|
|
IP_RTM_NEWMIP,
|
|
IP_WRMOB6_NEW_LINK_TX,
|
|
0,
|
|
node->ifp_home->iftables.tunnel,
|
|
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
|
|
&nemo->prefix,
|
|
sizeof(nemo->prefix),
|
|
nemo->len,
|
|
&node->registered.mip6BindingCOA,
|
|
IPMIP6HA_ROUTE_COA_SIZE(node->registered.mip6BindingCOAType),
|
|
node->registered.mip6BindingUDPEncapType,
|
|
IP_NULL,
|
|
&handle,
|
|
IPMIP_LINK_RECV,
|
|
IPMIP6HA_ROUTE_GRE_DOWNLINK(node),
|
|
IPNET_RTF_MBINDING|IPNET_RTF_TUNNELEND);
|
|
|
|
/* Create outbound statistics route */
|
|
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
|
|
proc,
|
|
IP_RTM_NEWMIP,
|
|
IP_WRMOB6_NEW_LINK_RX,
|
|
0,
|
|
ctx->iftables.forward,
|
|
node->ifp_home->ipmip6.iff.ifindex,
|
|
&nemo->prefix,
|
|
sizeof(nemo->prefix),
|
|
nemo->len,
|
|
IP_NULL,
|
|
0,
|
|
0,
|
|
ipmip6ha_route_state_cmp_tunnel_end(&scmp, node),
|
|
&handle,
|
|
IPMIP_LINK_SEND,
|
|
IP_NULL,
|
|
IPNET_RTF_SKIP); /* */
|
|
|
|
nemo->flags = (Ip_u8)(nemo->flags & ~IPMIP6HA_NEMO_ACL_ADDED);
|
|
}
|
|
break;
|
|
case IPMIP6HA_ROUTE_STATE_DO_DEL:
|
|
for (nemo = IPCOM_LIST_FIRST(&node->nemo_v6); nemo != IP_NULL; nemo = nnemo)
|
|
{
|
|
nnemo = IPCOM_LIST_NEXT(&nemo->next);
|
|
if (IP_BIT_ISFALSE(nemo->flags, IPMIP6HA_NEMO_ACL_ADDED))
|
|
{
|
|
/* Delete the tunneling route */
|
|
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
IP_AF_INET6,
|
|
IP_RTM_DELROUTE,
|
|
node->ifp_home->iftables.tunnel,
|
|
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
|
|
&nemo->prefix,
|
|
nemo->len,
|
|
IP_NULL,
|
|
IP_RTN_UNICAST);
|
|
|
|
/* Delete the STATS route */
|
|
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
IP_AF_INET6,
|
|
IP_RTM_DELROUTE,
|
|
ctx->iftables.forward,
|
|
node->ifp_home->ipmip6.iff.ifindex,
|
|
&nemo->prefix,
|
|
nemo->len,
|
|
IP_NULL,
|
|
IP_RTN_UNICAST);
|
|
|
|
if (IP_BIT_ISTRUE(nemo->flags, IPMIP6HA_NEMO_ACL_DELETED))
|
|
ipmip6ha_nemo_free(ctx, proc, node, nemo);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipmip6ha_route_state_tunnel_ipv6(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node,
|
|
int docmd)
|
|
{
|
|
Ipmip_netlink_kern_compare_t scmp;
|
|
Ipmip_netlink_kern_handle_t handle;
|
|
|
|
handle.mip_facility = IPCOM_IPD_ID_IPMIP6HA;
|
|
handle.mip_ident = node->identity;
|
|
|
|
switch (docmd)
|
|
{
|
|
case IPMIP6HA_ROUTE_STATE_DO_ADD:
|
|
/* Create inbound tunnel route */
|
|
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
|
|
proc,
|
|
IP_RTM_NEWMIP,
|
|
IP_WRMOB6_NEW_LINK_TX,
|
|
0,
|
|
node->ifp_home->iftables.tunnel,
|
|
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
|
|
&node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6,
|
|
sizeof(node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6),
|
|
128,
|
|
&node->registered.mip6BindingCOA,
|
|
IPMIP6HA_ROUTE_COA_SIZE(node->registered.mip6BindingCOAType),
|
|
node->registered.mip6BindingUDPEncapType,
|
|
IP_NULL,
|
|
&handle,
|
|
IPMIP_LINK_RECV,
|
|
IPMIP6HA_ROUTE_GRE_DOWNLINK(node),
|
|
IPNET_RTF_MBINDING|IPNET_RTF_TUNNELEND);
|
|
|
|
/* Create outbound statistics route */
|
|
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
|
|
proc,
|
|
IP_RTM_NEWMIP,
|
|
IP_WRMOB6_NEW_LINK_RX,
|
|
0,
|
|
ctx->iftables.forward,
|
|
node->ifp_home->ipmip6.iff.ifindex,
|
|
&node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6,
|
|
sizeof(node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6),
|
|
128,
|
|
IP_NULL,
|
|
0,
|
|
0,
|
|
ipmip6ha_route_state_cmp_tunnel_end(&scmp, node),
|
|
&handle,
|
|
IPMIP_LINK_SEND,
|
|
IP_NULL,
|
|
IPNET_RTF_SKIP); /* */
|
|
|
|
break;
|
|
case IPMIP6HA_ROUTE_STATE_DO_DEL:
|
|
|
|
/* Delete the tunneling route */
|
|
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
IP_AF_INET6,
|
|
IP_RTM_DELROUTE,
|
|
node->ifp_home->iftables.tunnel,
|
|
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
|
|
&node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6,
|
|
128,
|
|
IP_NULL,
|
|
IP_RTN_UNICAST);
|
|
|
|
/* Delete the STATS route */
|
|
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
IP_AF_INET6,
|
|
IP_RTM_DELROUTE,
|
|
ctx->iftables.forward,
|
|
node->ifp_home->ipmip6.iff.ifindex,
|
|
&node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6,
|
|
128,
|
|
IP_NULL,
|
|
IP_RTN_UNICAST);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipmip6ha_route_state_ipv4_nemo(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node,
|
|
int docmd)
|
|
{
|
|
#ifdef IPMIP_USE_INET
|
|
Ipmip6ha_nemo_dsmipv6_t *nemo, *nnemo;
|
|
Ipmip_netlink_kern_compare_t scmp;
|
|
Ipmip_netlink_kern_handle_t handle;
|
|
|
|
handle.mip_facility = IPCOM_IPD_ID_IPMIP6HA;
|
|
handle.mip_ident = node->identity;
|
|
|
|
switch (docmd)
|
|
{
|
|
case IPMIP6HA_ROUTE_STATE_DO_ADD:
|
|
for (nemo = IPCOM_LIST_FIRST(&node->nemo_prefix_v4); nemo != IP_NULL; nemo = nnemo)
|
|
{
|
|
nnemo = IPCOM_LIST_NEXT(&nemo->next);
|
|
/* Create inbound tunnel route */
|
|
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
|
|
proc,
|
|
IP_RTM_NEWMIP,
|
|
IP_WRMOB6_NEW_LINK_TX,
|
|
0,
|
|
node->ifp_home->iftables.tunnel,
|
|
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
|
|
&nemo->prefix,
|
|
sizeof(nemo->prefix),
|
|
(Ip_u8)nemo->len,
|
|
&node->registered.mip6BindingCOA,
|
|
IPMIP6HA_ROUTE_COA_SIZE(node->registered.mip6BindingCOAType),
|
|
node->registered.mip6BindingUDPEncapType,
|
|
IP_NULL,
|
|
&handle,
|
|
IPMIP_LINK_RECV,
|
|
IPMIP6HA_ROUTE_GRE_DOWNLINK(node),
|
|
IPNET_RTF_MBINDING|IPNET_RTF_TUNNELEND);
|
|
|
|
/* Create outbound statistics route */
|
|
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
|
|
proc,
|
|
IP_RTM_NEWMIP,
|
|
IP_WRMOB6_NEW_LINK_RX,
|
|
0,
|
|
ctx->iftables.forward,
|
|
node->ifp_home->ipmip6.iff.ifindex,
|
|
&nemo->prefix,
|
|
sizeof(nemo->prefix),
|
|
(Ip_u8)nemo->len,
|
|
IP_NULL,
|
|
0,
|
|
0,
|
|
ipmip6ha_route_state_cmp_tunnel_end(&scmp, node),
|
|
&handle,
|
|
IPMIP_LINK_SEND,
|
|
IP_NULL,
|
|
IPNET_RTF_SKIP); /* */
|
|
|
|
if (IP_BIT_ISTRUE(nemo->flags, IPMIP6HA_NEMO_ACL_ADDED))
|
|
nemo->flags = (Ip_u8)(nemo->flags & ~IPMIP6HA_NEMO_ACL_ADDED);
|
|
}
|
|
break;
|
|
case IPMIP6HA_ROUTE_STATE_DO_DEL:
|
|
for (nemo = IPCOM_LIST_FIRST(&node->nemo_prefix_v4); nemo != IP_NULL; nemo = nnemo)
|
|
{
|
|
nnemo = IPCOM_LIST_NEXT(&nemo->next);
|
|
if (IP_BIT_ISFALSE(nemo->flags, IPMIP6HA_NEMO_ACL_ADDED))
|
|
{
|
|
/* Delete the tunneling route */
|
|
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
IP_AF_INET,
|
|
IP_RTM_DELROUTE,
|
|
node->ifp_home->iftables.tunnel,
|
|
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
|
|
&nemo->prefix,
|
|
(Ip_u8)nemo->len,
|
|
IP_NULL,
|
|
IP_RTN_UNICAST);
|
|
|
|
/* Delete the STATS route */
|
|
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
IP_AF_INET,
|
|
IP_RTM_DELROUTE,
|
|
ctx->iftables.forward,
|
|
node->ifp_home->ipmip6.iff.ifindex,
|
|
&nemo->prefix,
|
|
(Ip_u8)nemo->len,
|
|
IP_NULL,
|
|
IP_RTN_UNICAST);
|
|
|
|
if (IP_BIT_ISTRUE(nemo->flags, IPMIP6HA_NEMO_ACL_DELETED))
|
|
{
|
|
/* Free this NEMO entry */
|
|
ipmip6ha_nemo_dsmipv6_free(ctx, proc, node, nemo);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
#else
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
IPMIP_UNUSED_PARAMETER(node);
|
|
IPMIP_UNUSED_PARAMETER(docmd);
|
|
#endif
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipmip6ha_route_state_ipv4(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node,
|
|
int docmd)
|
|
{
|
|
#ifdef IPMIP_USE_INET
|
|
Ipmip6ha_nemo_dsmipv6_t *nemo, *nnemo;
|
|
Ipmip_netlink_kern_compare_t scmp;
|
|
Ipmip_netlink_kern_handle_t handle;
|
|
|
|
handle.mip_facility = IPCOM_IPD_ID_IPMIP6HA;
|
|
handle.mip_ident = node->identity;
|
|
|
|
switch (docmd)
|
|
{
|
|
case IPMIP6HA_ROUTE_STATE_DO_ADD:
|
|
for (nemo = IPCOM_LIST_FIRST(&node->nemo_hoa_v4); nemo != IP_NULL; nemo = nnemo)
|
|
{
|
|
nnemo = IPCOM_LIST_NEXT(&nemo->next);
|
|
/* Create inbound tunnel route */
|
|
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
|
|
proc,
|
|
IP_RTM_NEWMIP,
|
|
IP_WRMOB6_NEW_LINK_TX,
|
|
0,
|
|
node->ifp_home->iftables.tunnel,
|
|
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
|
|
&nemo->prefix,
|
|
sizeof(nemo->prefix),
|
|
(Ip_u8)nemo->len,
|
|
&node->registered.mip6BindingCOA,
|
|
IPMIP6HA_ROUTE_COA_SIZE(node->registered.mip6BindingCOAType),
|
|
node->registered.mip6BindingUDPEncapType,
|
|
IP_NULL,
|
|
&handle,
|
|
IPMIP_LINK_RECV,
|
|
IPMIP6HA_ROUTE_GRE_DOWNLINK(node),
|
|
IPNET_RTF_MBINDING|IPNET_RTF_TUNNELEND);
|
|
|
|
/* Create outbound statistics route */
|
|
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
|
|
proc,
|
|
IP_RTM_NEWMIP,
|
|
IP_WRMOB6_NEW_LINK_TX,
|
|
0,
|
|
ctx->iftables.forward,
|
|
node->ifp_home->ipmip6.iff.ifindex,
|
|
&nemo->prefix,
|
|
sizeof(nemo->prefix),
|
|
(Ip_u8)nemo->len,
|
|
IP_NULL,
|
|
0,
|
|
0,
|
|
ipmip6ha_route_state_cmp_tunnel_end(&scmp, node),
|
|
&handle,
|
|
IPMIP_LINK_SEND,
|
|
IP_NULL,
|
|
IPNET_RTF_SKIP); /* */
|
|
|
|
if (IP_BIT_ISTRUE(nemo->flags, IPMIP6HA_NEMO_ACL_ADDED))
|
|
{
|
|
if (IP_BIT_ISFALSE(nemo->flags, IPMIP6HA_NEMO_ACL_HOA_PROXY))
|
|
{
|
|
ipmip_timer_lock_acquire(&ctx->ipmip6.ipmip, proc, node->ifp_home->ipmip6.iff_lock);
|
|
if (!ipmip_inet_arp_proxy(&ctx->ipmip6.ipmip, proc, node->ifp_home->ipmip6.iff.ifindex, nemo->prefix, IP_TRUE))
|
|
{
|
|
IPMIP6_EVENT_IF(ERR, proc,
|
|
ipmip_log_event_add(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
"Unable to install proxy ARP handler for %s (%s) = %x",
|
|
ipmip6ha_node_describe(proc, node),
|
|
ipmip_ntop_inet(proc, nemo->prefix),
|
|
ipcom_errno));
|
|
}
|
|
IP_BIT_SET(nemo->flags, IPMIP6HA_NEMO_ACL_HOA_PROXY);
|
|
ipmip_timer_lock_release(&ctx->ipmip6.ipmip, proc, node->ifp_home->ipmip6.iff_lock);
|
|
}
|
|
|
|
nemo->flags = (Ip_u8)(nemo->flags & ~IPMIP6HA_NEMO_ACL_ADDED);
|
|
}
|
|
}
|
|
break;
|
|
case IPMIP6HA_ROUTE_STATE_DO_DEL:
|
|
for (nemo = IPCOM_LIST_FIRST(&node->nemo_hoa_v4); nemo != IP_NULL; nemo = nnemo)
|
|
{
|
|
nnemo = IPCOM_LIST_NEXT(&nemo->next);
|
|
if (IP_BIT_ISFALSE(nemo->flags, IPMIP6HA_NEMO_ACL_ADDED))
|
|
{
|
|
/* Delete the tunneling route */
|
|
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
IP_AF_INET,
|
|
IP_RTM_DELROUTE,
|
|
node->ifp_home->iftables.tunnel,
|
|
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
|
|
&nemo->prefix,
|
|
(Ip_u8)nemo->len,
|
|
IP_NULL,
|
|
IP_RTN_UNICAST);
|
|
|
|
/* Delete the STATS route */
|
|
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
IP_AF_INET,
|
|
IP_RTM_DELROUTE,
|
|
ctx->iftables.forward,
|
|
node->ifp_home->ipmip6.iff.ifindex,
|
|
&nemo->prefix,
|
|
(Ip_u8)nemo->len,
|
|
IP_NULL,
|
|
IP_RTN_UNICAST);
|
|
|
|
if (IP_BIT_ISTRUE(nemo->flags, IPMIP6HA_NEMO_ACL_DELETED))
|
|
{
|
|
if (IP_BIT_ISTRUE(nemo->flags, IPMIP6HA_NEMO_ACL_HOA_PROXY))
|
|
{
|
|
ipmip_timer_lock_acquire(&ctx->ipmip6.ipmip, proc, node->ifp_home->ipmip6.iff_lock);
|
|
ipmip_inet_arp_proxy(&ctx->ipmip6.ipmip, proc, node->ifp_home->ipmip6.iff.ifindex, nemo->prefix, IP_FALSE);
|
|
nemo->flags = (Ip_u8)(nemo->flags & ~IPMIP6HA_NEMO_ACL_HOA_PROXY);
|
|
ipmip_timer_lock_release(&ctx->ipmip6.ipmip, proc, node->ifp_home->ipmip6.iff_lock);
|
|
}
|
|
|
|
/* Free this NEMO entry */
|
|
ipmip6ha_nemo_dsmipv6_free(ctx, proc, node, nemo);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
#else
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
IPMIP_UNUSED_PARAMETER(node);
|
|
IPMIP_UNUSED_PARAMETER(docmd);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmip6ha_route_state_add
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipmip6ha_route_state_add(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node,
|
|
Ip_u32 states)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < IPMIP6HA_ROUTE_BIT_MAX; i++)
|
|
{
|
|
if (IPMIP6HA_ROUTE_STATE_CHECK(states,i) != 0)
|
|
{
|
|
if (IPMIP6HA_ROUTE_STATE_CHECK(node->route_state,i) == 0)
|
|
{
|
|
/* Time to enable this state */
|
|
(*ipmip6ha_route_states[i]) (ctx, proc, node, IPMIP6HA_ROUTE_STATE_DO_ADD);
|
|
node->route_state |= IPMIP6HA_ROUTE_STATE_BIT(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmip6ha_route_state_add
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipmip6ha_route_state_del(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node,
|
|
Ip_u32 states)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < IPMIP6HA_ROUTE_BIT_MAX; i++)
|
|
{
|
|
if (IPMIP6HA_ROUTE_STATE_CHECK(states,i) != 0)
|
|
{
|
|
if (IPMIP6HA_ROUTE_STATE_CHECK(node->route_state,i) != 0)
|
|
{
|
|
/* Time to enable this state */
|
|
(*ipmip6ha_route_states[i]) (ctx, proc, node, IPMIP6HA_ROUTE_STATE_DO_DEL);
|
|
node->route_state &= ~IPMIP6HA_ROUTE_STATE_BIT(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipmip6ha_route_add_outbound(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip6ha_node *node,
|
|
Ip_u64 octets,
|
|
Ip_u64 pkts)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
|
|
IP_U64_ADD(node->mip6NodeTrafficEntry.mip6HCNodeOutOctets, octets);
|
|
node->mip6NodeTrafficEntry.mip6NodeOutOctets = IP_U64_GETLO(node->mip6NodeTrafficEntry.mip6HCNodeOutOctets);
|
|
IP_U64_ADD(node->mip6NodeTrafficEntry.mip6HCNodeOutPkts, pkts);
|
|
node->mip6NodeTrafficEntry.mip6NodeOutPkts = IP_U64_GETLO(node->mip6NodeTrafficEntry.mip6HCNodeOutPkts);
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip6ha_route_add_inbound(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip6ha_node *node,
|
|
Ip_u64 octets,
|
|
Ip_u64 pkts)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
|
|
IP_U64_ADD(node->mip6NodeTrafficEntry.mip6HCNodeInOctets, octets);
|
|
node->mip6NodeTrafficEntry.mip6NodeInOctets = IP_U64_GETLO(node->mip6NodeTrafficEntry.mip6HCNodeInOctets);
|
|
IP_U64_ADD(node->mip6NodeTrafficEntry.mip6HCNodeInPkts, pkts);
|
|
node->mip6NodeTrafficEntry.mip6NodeInPkts = IP_U64_GETLO(node->mip6NodeTrafficEntry.mip6HCNodeInPkts);
|
|
}
|
|
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipmip6ha_route_direct_temporary(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_if_t *ifp,
|
|
struct Ip_in6_addr *endpoint,
|
|
union Ipmip6_mib_InetAddress *tunnel_endpoint,
|
|
Ip_u32 tunnel_endpoint_type,
|
|
Ip_u16 port)
|
|
{
|
|
Ipmip_netlink_kern_compare_t scmp;
|
|
|
|
#ifdef IPMIP_USE_INET
|
|
if (tunnel_endpoint_type == IPMIP6_MIB_InetAddressType_ipv4)
|
|
{
|
|
/* Need the temporary tunneling rule if we're doing inet */
|
|
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
|
|
proc,
|
|
IP_RTM_NEWMIP,
|
|
IP_WRMOB6_NEW_LINK_TX,
|
|
IP_WRMOB6_NEW_TYPE_TEMPORARY,
|
|
ifp->iftables.pending,
|
|
ifp->iftunnels[IPMIP_TUNNELTYPE_IPIP]->ipmip6.iff.ifindex,
|
|
endpoint,
|
|
sizeof(struct Ip_in6_addr),
|
|
128,
|
|
&tunnel_endpoint->ipv4,
|
|
sizeof(struct Ip_in_addr),
|
|
port,
|
|
ipmip_netlink_route_src_protocol(&scmp, IP_IPPROTO_MH),
|
|
IP_NULL,
|
|
IPMIP_LINK_RECV,
|
|
IP_NULL,
|
|
IPNET_RTF_TUNNELEND);
|
|
}
|
|
else
|
|
#endif
|
|
if (port)
|
|
{
|
|
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
|
|
proc,
|
|
IP_RTM_NEWMIP,
|
|
IP_WRMOB6_NEW_LINK_TX,
|
|
IP_WRMOB6_NEW_TYPE_TEMPORARY,
|
|
ifp->iftables.pending,
|
|
ifp->iftunnels[IPMIP_TUNNELTYPE_IP6IP6]->ipmip6.iff.ifindex,
|
|
endpoint,
|
|
sizeof(struct Ip_in6_addr),
|
|
128,
|
|
&tunnel_endpoint->ipv6,
|
|
sizeof(struct Ip_in6_addr),
|
|
port,
|
|
ipmip_netlink_route_src_protocol(&scmp, IP_IPPROTO_MH),
|
|
IP_NULL,
|
|
IPMIP_LINK_RECV,
|
|
IP_NULL,
|
|
IPNET_RTF_TUNNELEND);
|
|
}
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip6ha_route_rthdr_temporary(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_if_t *ifp,
|
|
struct Ip_in6_addr *hoa,
|
|
union Ipmip6_mib_InetAddress *coa,
|
|
Ip_u32 coa_type,
|
|
Ip_u16 port)
|
|
{
|
|
Ipmip_netlink_kern_compare_t scmp;
|
|
|
|
IPMIP_UNUSED_PARAMETER(coa_type);
|
|
#ifdef IPMIP_USE_INET
|
|
if (coa_type == IPMIP6_MIB_InetAddressType_ipv4)
|
|
{
|
|
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
|
|
proc,
|
|
IP_RTM_NEWMIP,
|
|
IP_WRMOB6_NEW_LINK_TX,
|
|
IP_WRMOB6_NEW_TYPE_TEMPORARY,
|
|
ifp->iftables.pending,
|
|
ifp->iftunnels[IPMIP_TUNNELTYPE_IPIP]->ipmip6.iff.ifindex,
|
|
hoa,
|
|
sizeof(struct Ip_in6_addr),
|
|
128,
|
|
&coa->ipv4.s_addr,
|
|
sizeof(struct Ip_in_addr),
|
|
port,
|
|
ipmip_netlink_route_src_protocol(&scmp, IP_IPPROTO_MH),
|
|
IP_NULL,
|
|
IPMIP_LINK_RECV,
|
|
IP_NULL,
|
|
IPNET_RTF_TUNNELEND);
|
|
}
|
|
else
|
|
#endif
|
|
if (port)
|
|
{
|
|
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
|
|
proc,
|
|
IP_RTM_NEWMIP,
|
|
IP_WRMOB6_NEW_LINK_TX,
|
|
IP_WRMOB6_NEW_TYPE_TEMPORARY,
|
|
ifp->iftables.pending,
|
|
ifp->iftunnels[IPMIP_TUNNELTYPE_IP6IP6]->ipmip6.iff.ifindex,
|
|
hoa,
|
|
sizeof(struct Ip_in6_addr),
|
|
128,
|
|
&coa->ipv6,
|
|
sizeof(struct Ip_in6_addr),
|
|
port,
|
|
ipmip_netlink_route_src_protocol(&scmp, IP_IPPROTO_MH),
|
|
IP_NULL,
|
|
IPMIP_LINK_RECV,
|
|
IP_NULL,
|
|
IPNET_RTF_TUNNELEND);
|
|
}
|
|
else
|
|
{
|
|
/* Add the R/O route to the mobile node */
|
|
ipmip6ha_netlink_route_ro_rthdr(ctx,
|
|
proc,
|
|
IP_WRMOB6_NEW_TYPE_TEMPORARY,
|
|
ifp->iftables.pending,
|
|
ifp->ipmip6.iff.ifindex,
|
|
hoa,
|
|
&coa->ipv6,
|
|
hoa,
|
|
sizeof(struct Ip_in6_addr),
|
|
128,
|
|
IPNET_RTF_BLACKHOLE,
|
|
0,
|
|
ipmip_netlink_route_src_protocol(&scmp, IP_IPPROTO_MH));
|
|
}
|
|
}
|
|
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipmip6ha_route_update_temporary(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_pktbuf *pbuf,
|
|
Ip_bool route_direct)
|
|
{
|
|
|
|
|
|
/* Restore route states; we're done */
|
|
if (route_direct)
|
|
{
|
|
ipmip6ha_route_direct_temporary(ctx,
|
|
proc,
|
|
pbuf->iff_transport.priv,
|
|
&pbuf->ipmip6.ipmip.srcinfo.src->sin6.sin6_addr,
|
|
&pbuf->pktinfo.mip6BindingCOA,
|
|
pbuf->pktinfo.mip6BindingCOAType,
|
|
pbuf->pktinfo.mip6BindingUDPEncapPort);
|
|
}
|
|
else
|
|
{
|
|
if (pbuf->pktinfo.haMobilityDeregistration && ipmip6_util_InetAddress_cmp(pbuf->pktinfo.mip6BindingCOAType, &pbuf->pktinfo.mip6BindingCOA, pbuf->pktinfo.mip6BindingHomeAddressType, &pbuf->pktinfo.mip6BindingHomeAddress))
|
|
{
|
|
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
IP_AF_INET6,
|
|
IP_RTM_DELROUTE,
|
|
pbuf->iff_transport.priv->iftables.pending,
|
|
0,
|
|
&pbuf->ipmip6.ipmip.srcinfo.src->sin6.sin6_addr,
|
|
128,
|
|
IP_NULL,
|
|
IP_RTN_UNICAST);
|
|
return IP_TRUE;
|
|
}
|
|
else
|
|
{
|
|
ipmip6ha_route_rthdr_temporary(ctx,
|
|
proc,
|
|
pbuf->iff_transport.priv,
|
|
&pbuf->pktinfo.mip6BindingHomeAddress.ipv6,
|
|
&pbuf->pktinfo.mip6BindingCOA,
|
|
pbuf->pktinfo.mip6BindingCOAType,
|
|
pbuf->pktinfo.mip6BindingUDPEncapPort);
|
|
}
|
|
}
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipmip6ha_route_context_init(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc)
|
|
{
|
|
ctx->iftables.forward = ipmip_util_route_table_alloc(&ctx->ipmip6.ipmip, proc);
|
|
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip6ha_route_context_destroy(struct Ipmip6ha_context *ctx,
|
|
struct Ipmip_proc *proc)
|
|
{
|
|
if (ctx->iftables.forward != IPCOM_ROUTE_TABLE_UNSPEC)
|
|
ipmip_util_route_table_free(&ctx->ipmip6.ipmip, proc, ctx->iftables.forward);
|
|
|
|
}
|
|
|
|
IP_GLOBAL int
|
|
ipmip6ha_netlink_new_handle(Ipmip6ha_context_t *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node)
|
|
{
|
|
/**/
|
|
return ipmip6_netlink_new_handle(&ctx->ipmip6, proc, IPCOM_IPD_ID_IPMIP6HA, node->identity);
|
|
}
|
|
|
|
IP_GLOBAL int
|
|
ipmip6ha_netlink_del_handle(Ipmip6ha_context_t *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node)
|
|
{
|
|
/**/
|
|
return ipmip6_netlink_del_handle(&ctx->ipmip6, proc, IPCOM_IPD_ID_IPMIP6HA, node->identity);
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipmip6ha_netlink_get_handle_stat(Ipmip6ha_context_t *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip6ha_node *node)
|
|
{
|
|
Ipmip6_netlink_kern_statistics_t link_recv, link_send;
|
|
Ipmip_netlink_kern_handle_t handle;
|
|
|
|
/* Identity */
|
|
handle.mip_facility = IPCOM_IPD_ID_IPMIP6HA;
|
|
handle.mip_ident = node->identity;
|
|
|
|
/* Retrieve the statistics; the SEND/RECV from the MIP4 point of view is
|
|
* 'send tunnel' / 'receive tunnel', while from the node point of view
|
|
* (statistics) is 'send from node' / 'send to node'. So, we have to
|
|
* reverse the send/recv variables to get it right.
|
|
*/
|
|
if (ipmip6_netlink_get_handle_stat(&ctx->ipmip6, proc, &handle, &link_recv, &link_send))
|
|
{
|
|
/* Update stats */
|
|
ipmip6_context_add_outbound(&ctx->ipmip6, link_send.mip_s_octets, link_send.mip_s_pkts);
|
|
ipmip6ha_route_add_outbound(ctx, node, link_send.mip_s_octets, link_send.mip_s_pkts);
|
|
|
|
ipmip6_context_add_inbound(&ctx->ipmip6, link_recv.mip_s_octets, link_recv.mip_s_pkts);
|
|
ipmip6ha_route_add_inbound(ctx, node, link_recv.mip_s_octets, link_recv.mip_s_pkts);
|
|
return IP_TRUE;
|
|
}
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|