Files
m241Neelima/components/ip_net2-6.9/ipnet2/src/ipnet_rtnetlink_route.c
T
2026-07-30 11:19:44 +05:30

1079 lines
33 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_rtnetlink_route.c,v $ $Revision: 1.11.10.2 $
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_rtnetlink_route.c,v $
* $Author: svc-cmnet $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation Jonas Rendel <Jonas.Rendel@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
* Contains netlink handlers for managing Ipv4 and Ipv6 routes as well as
* MPLS shortcut routes.
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#ifndef IPCOM_KERNEL
#define IPCOM_KERNEL
#endif
#include "ipnet_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#ifdef IPNET_USE_NETLINK
#define IPCOM_USE_CLIB_PROTO
#include <ipcom.h>
#include <ipcom_type.h>
#include <ipcom_clib.h>
#include <ipcom_cstyle.h>
#include <ipcom_sock.h>
#include <ipcom_sock6.h>
#include <ipcom_sock2.h>
#include <ipcom_route.h>
#include <ipcom_errno.h>
#include "ipnet_h.h"
#include "ipnet_ctrl.h"
#include "ipnet_route.h"
#include "ipnet_netlink_h.h"
#include "ipnet_rtnetlink_h.h"
#include "ipcom_sock.h"
#include "ipnet_loopback.h"
#ifdef IP_PORT_LKM
#include "ipcom_lkm.h" /* Needed for Linux PPP interface config */
#endif /* IP_PORT_LKM */
#include "ipnet_eth.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
#define IP_IN4_IS_ADDR_MULTICAST(x) (((x) & ip_htonl(0xf0000000)) == ip_ntohl (0xe0000000))
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
typedef struct Ipnet_rtnetlink_route_family
{
struct
{
Ip_ptrdiff_t *vr;
Ip_ptrdiff_t *table;
Ip_ptrdiff_t *rt;
Ip_ptrdiff_t *done;
Ip_ptrdiff_t aborted;
Ip_ptrdiff_t cont;
} state;
/* Requested */
struct Ip_nlmsghdr *nlmsg;
int table; /* Caller specified table */
Ip_u8 family;
/* Buffering */
Ipnet_netlink_mem_t *mem;
}
Ipnet_rtnetlink_route_family_t;
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipnet_rtnetlink_route_foreach_vr
*===========================================================================
* Description: Hash table foreach callback. Called once for each virtual
* router that exists in the system.
* Parameters: rtab - route table
* param - callback parameters.
* Returns: -
*
*/
IP_STATIC void
ipnet_rtnetlink_route_foreach_vr_family(Ipcom_route *rtab, Ipnet_rtnetlink_route_family_t *param)
{
int new_offs = 0;
Ip_ptrdiff_t table = IPNET_ROUTE_GET_TABLE(rtab);
Ip_u16 vr = IPNET_ROUTE_GET_VR(rtab);
Ipnet_route_entry *rt = IP_NULL;
/* This traversal is already aborted */
if (param->state.aborted)
return;
/* Only handle rtabs of selected address family */
if (IPNET_ROUTE_GET_FAMILY(rtab) != param->family)
return;
/* Check if specific VR shall be dumped */
if (IP_BIT_ISFALSE(param->nlmsg->nlmsg_flags, IP_NLM_F_VR_UNSPEC) && (param->mem->vr != IPCOM_VR_ANY) && (param->mem->vr != vr))
return;
/*
* If this is a trailer message buffer, make sure it
* starts dumping where the last message ended
*/
if (param->state.cont)
{
Ipnet_route_entry *rtt = (Ipnet_route_entry*)(*param->state.rt);
/* Verify current state */
if (*param->state.vr != vr || *param->state.table != table)
return;
if (rtt != IP_NULL)
{
rt = ipnet_route_first_entry(IPNET_ROUTE_GET_FAMILY(rtab),
vr,
(Ip_u32) table);
while (rt != IP_NULL)
{
if (rt == rtt)
break;
rt = ipnet_route_next_entry(rt);
}
}
}
/* Reset the continue variable; we're on the move again */
param->state.cont = 0;
/* Get first unless we've found one to continue from */
if (rt == IP_NULL)
rt = ipnet_route_first_entry(IPNET_ROUTE_GET_FAMILY(rtab),
vr,
(Ip_u32) table);
/* */
while (rt)
{
/* Do not dump the 255.255.255.255, 224.0.0.0/4 or IPv6 multicast routes. */
/* Do not dump routes that are part of multipath routes either */
if (IP_BIT_ISFALSE(rt->hdr.flags, IPNET_RTF_X_MCAST_RO | IPNET_RTF_X_BCAST_RO | IPNET_RTF_X_HIDDEN)
&& (rt->prev == IP_NULL))
{
#ifdef IPCOM_USE_INET
if (param->family == IP_AF_INET)
{
new_offs = ipnet_rtnetlink_ip4_route_fill_info (param->mem,
rt,
param->nlmsg->nlmsg_seq,
IP_RTM_NEWROUTE,
IP_NLM_F_MULTI);
}
else
#endif
#ifdef IPCOM_USE_INET6
if (param->family == IP_AF_INET6)
{
new_offs = ipnet_rtnetlink_ip6_route_fill_info (param->mem,
rt,
param->nlmsg->nlmsg_seq,
IP_RTM_NEWROUTE,
IP_NLM_F_MULTI);
}
else
#endif
{
IP_PANIC();
}
if (new_offs < 0)
goto aborted;
}
rt = ipnet_route_next_entry(rt);
/* */
if (rt && new_offs)
goto aborted;
}
return;
aborted:
param->state.aborted = 1;
*param->state.rt = (Ip_ptrdiff_t)rt;
*param->state.table = (Ip_ptrdiff_t)table;
*param->state.vr = (Ip_ptrdiff_t)vr;
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipnet_rtnetlink_route_newroute_family
*===========================================================================
* Description: Add a new rotue via NETLINK.
* Parameters: data - Message payload
* len - Length of message.
* nlh - NETLINK message header
* arg - Reference to route attributes.
*
* Returns: 0 - Success
* <0 - Failure
*
*/
IP_GLOBAL int
ipnet_rtnetlink_route_newroute_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlh,
struct Ip_rtattr **rta,
int family)
{
Ipnet_netif *netif = IP_NULL;
Ipnet_ppp_peer *p = IP_NULL;
int ret = -1;
Ip_u16 vr;
Ip_u32 table;
Ip_bool is_multipath_route = IP_FALSE;
Ip_ssize_t mpa_size = 0;
struct Ip_rtnexthop *nh = IP_NULL;
struct Ipnet_rt_metrics metrics;
struct Ip_sockaddr *gw = IP_NULL;
void *mask = IP_NULL;
struct Ip_sockaddr_dl gw_dl;
struct Ipnet_route_add_param param;
struct Ip_rtmsg *rtm = IP_NLMSG_DATA(nlh);
union Ip_sockaddr_union ugw;
Ipnet_rtnetlink_key_t ukey;
#ifdef IPMPLS
struct Ip_sockaddr_mpls gw_mpls;
#endif /* IPMPLS */
#ifdef IPNET_USE_ROUTE_COOKIES
Ipnet_rt_cookie cookie;
#endif /* IPNET_USE_ROUTE_COOKIES */
table = (Ip_u32) IPCOM_ROUTE_TABLE_GET(rtm->rtm_table);
/* Prepare route parameters */
ipcom_memset(&param, 0, sizeof(param));
ipcom_memset(&metrics,0,sizeof(metrics));
param.flags = IPNET_RTF_STATIC | IPNET_RTF_UP | IPNET_RTF_DONE;
#ifdef IPNET_USE_ROUTE_TABLE_NAMES
if (rta[IP_RTA_TABLE_NAME -1])
{
if (ipnet_route_vr_and_table_from_name(IP_RTA_DATA(rta[IP_RTA_TABLE_NAME - 1]),
&vr,
&table) < 0)
return -IP_ERRNO_ESRCH;
}
else
#endif
{
if (mem->vr == IPCOM_VR_ANY)
return -IP_ERRNO_EINVAL;
vr = ipnet_rtnetlink_vr(rta[IP_RTA_VR - 1], mem->vr);
if (rta[IP_RTA_TABLE - 1])
table = IP_GET_32ON8(IP_RTA_DATA(rta[IP_RTA_TABLE - 1]));
}
if (rta[IP_RTA_OIF -1])
{
Ip_u32 ifindex = 0;
if (rta[IP_RTA_OIF-1]->rta_len != IP_RTA_LENGTH(sizeof(int)))
return -IP_ERRNO_EINVAL;
ifindex = IP_GET_32ON8(IP_RTA_DATA(rta[IP_RTA_OIF-1]));
netif = ipnet_if_indextonetif(vr, ifindex);
if (netif)
p = netif->private_data;
}
if (rta[IP_RTA_MULTIPATH -1])
{
is_multipath_route = IP_TRUE;
nh = IP_RTA_DATA(rta[IP_RTA_MULTIPATH-1]);
mpa_size = (Ip_ssize_t) IP_RTA_PAYLOAD(rta[IP_RTA_MULTIPATH-1]);
if ((nh == IP_NULL) || (mpa_size == 0))
return -IP_ERRNO_EINVAL;
}
if ((ret = ipnet_rtnetlink_route_key_setup(family, &ukey, netif? netif->ipcom.ifindex : 0, &mask, rtm->rtm_dst_len, rta[IP_RTA_DST-1])) < 0)
return ret;
if ((ret = ipnet_rtnetlink_route_gw_setup(family, netif? netif->ipcom.ifindex : 0, &ugw, &gw, rta[IP_RTA_GATEWAY-1])) < 0)
return ret;
#ifdef IPCOM_USE_INET
if (family == IP_AF_INET)
{
if (gw != IP_NULL)
{
/* Check if it is a pure gateway or not */
if (p == IP_NULL || p->peer4.s_addr != ugw.sin.sin_addr.s_addr)
{
/* Support for NBMA tunnel routes */
if (netif != IP_NULL && IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_POINTOPOINT))
param.flags |= IPNET_RTF_TUNNELEND;
else
param.flags |= IPNET_RTF_GATEWAY;
}
}
}
else
#endif
#ifdef IPCOM_USE_INET6
if (family == IP_AF_INET6)
{
if (gw != IP_NULL)
{
/* Check if it is a pure gateway or not */
if (p == IP_NULL || !IP_IN6_ARE_ADDR_EQUAL(&ugw.sin6.sin6_addr, &p->peer6))
{
if (netif != IP_NULL && IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_POINTOPOINT))
param.flags |= IPNET_RTF_TUNNELEND;
else
param.flags |= IPNET_RTF_GATEWAY;
}
}
}
else
#endif
{
return -IP_ERRNO_EAFNOSUPPORT;
}
if (!mask)
param.flags |= IPNET_RTF_HOST;
if (rtm->rtm_type == IP_RTN_PROXY)
{
/* This is a proxy arp network route */
IP_BIT_CLR(param.flags, IPNET_RTF_CLONING);
IP_BIT_SET(param.flags, IPNET_RTF_PROTO2);
if (rta[IP_RTA_PROXY_ARP_LLADDR - 1])
{
/* This is a network proxy arp with specific lladdr */
if (netif == IP_NULL)
return -IP_ERRNO_EINVAL;
ipcom_memset(&gw_dl, 0, sizeof(struct Ip_sockaddr_dl));
IPCOM_SA_LEN_SET(&gw_dl, sizeof(struct Ip_sockaddr_dl));
gw_dl.sdl_family = IP_AF_LINK;
gw_dl.sdl_index = (Ip_u16)netif->ipcom.ifindex;
gw_dl.sdl_alen = (Ip_u8) netif->ipcom.link_addr_size;
gw_dl.sdl_type = (Ip_u8) netif->ipcom.type;
ipcom_memcpy(IP_SOCKADDR_DL_LLADDR(&gw_dl),
IP_RTA_DATA(rta[IP_RTA_PROXY_ARP_LLADDR - 1]),
IPNET_ETH_ADDR_SIZE);
gw = (struct Ip_sockaddr *) &gw_dl;
IP_BIT_SET(param.flags, IPNET_RTF_LLINFO);
}
}
else if (rtm->rtm_type == IP_RTN_PROHIBIT)
IP_BIT_SET(param.flags, IPNET_RTF_REJECT);
else if (rtm->rtm_type == IP_RTN_THROW)
IP_BIT_SET(param.flags, IPNET_RTF_SKIP);
else if (rtm->rtm_type == IP_RTN_UNREACHABLE)
{
if (netif == IP_NULL)
netif = ipnet_loopback_get_netif(vr);
IP_BIT_CLR(param.flags, IPNET_RTF_UP);
}
else if (rtm->rtm_type == IP_RTN_CLONE)
IP_BIT_SET(param.flags, IPNET_RTF_CLONING);
else if (rtm->rtm_type == IP_RTN_BLACKHOLE)
IP_BIT_SET(param.flags, IPNET_RTF_BLACKHOLE);
#ifdef IPMPLS
/* Check for IPNET MPLS pseudo-wire route */
if (rta[IP_RTA_NH_PROTO-1])
{
Ip_u32 nh_type;
if (rta[IP_RTA_NH_PROTO-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32)))
return -IP_ERRNO_EINVAL;
if (rta[IP_RTA_NH_PROTO_DATA-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32)))
return -IP_ERRNO_EINVAL;
ipcom_memcpy(&nh_type, IP_RTA_DATA(rta[IP_RTA_NH_PROTO-1]), sizeof(Ip_u32));
if (nh_type != IPNET_ETH_P_MPLS_UNICAST)
return -IP_ERRNO_EINVAL;
ipcom_memset(&gw_mpls, 0, sizeof(gw_mpls));
gw_mpls.smpls_family = IP_AF_MPLS;
IPCOM_SA_LEN_SET(&gw_mpls, sizeof (struct Ip_sockaddr_mpls));
ipcom_memcpy(&gw_mpls.smpls_key,
IP_RTA_DATA(rta[IP_RTA_NH_PROTO_DATA-1]),
sizeof(Ip_u32));
IP_BIT_CLR(param.flags,IPNET_RTF_GATEWAY);
gw = (struct Ip_sockaddr *)&gw_mpls;
}
else
{
/* Check if cloning flag shall be set */
if (IP_BIT_ISFALSE(param.flags, IPNET_RTF_HOST | IPNET_RTF_GATEWAY | IPNET_RTF_REJECT | IPNET_RTF_BLACKHOLE))
IP_BIT_SET(param.flags, IPNET_RTF_CLONING);
}
#endif
if (rta[IP_RTA_METRICS-1])
{
Ip_size_t rlen = IP_RTA_PAYLOAD(rta[IP_RTA_METRICS-1]);
struct Ip_rtattr *rtax = (struct Ip_rtattr*)IP_RTA_DATA(rta[IP_RTA_METRICS-1]);
metrics.rmx_expire = IPCOM_ADDR_INFINITE;
param.metrics = &metrics;
while (IP_RTA_OK(rtax, rlen))
{
switch (rtax->rta_type)
{
case IP_RTAX_MTU:
ipcom_memcpy(&metrics.rmx_mtu, IP_RTA_DATA(rtax), sizeof(Ip_u32));
break;
case IP_RTAX_RTT:
ipcom_memcpy(&metrics.rmx_rtt, IP_RTA_DATA(rtax), sizeof(Ip_u32));
break;
case IP_RTAX_RTTVAR:
ipcom_memcpy(&metrics.rmx_rttvar, IP_RTA_DATA(rtax), sizeof(Ip_u32));
break;
}
rtax = IP_RTA_NEXT(rtax, rlen);
}
}
#ifdef IPNET_USE_ROUTE_COOKIES
if (rta[IP_RTA_COOKIE-1])
{
if (IP_RTA_PAYLOAD(rta[IP_RTA_COOKIE-1]) > sizeof(cookie))
return -IP_ERRNO_EINVAL;
ipcom_memset(&cookie, 0, sizeof(cookie));
ipcom_memcpy(&cookie,
IP_RTA_DATA(rta[IP_RTA_COOKIE-1]),
IP_RTA_PAYLOAD(rta[IP_RTA_COOKIE-1]));
param.cookie = &cookie;
}
#endif /* IPNET_USE_ROUTE_COOKIES */
while (1)
{
if (is_multipath_route && (gw == IP_NULL))
{
netif = ipnet_if_indextonetif(vr, (Ip_u32) nh->rtnh_ifindex);
metrics.rmx_hopcount = nh->rtnh_hops;
metrics.rmx_expire = IPCOM_ADDR_INFINITE;
param.metrics = &metrics;
if (nh->rtnh_len > sizeof(struct Ip_rtnexthop))
{
/* Multihop route has gateway */
IP_BIT_CLR(param.flags, IPNET_RTF_CLONING);
IP_BIT_SET(param.flags, IPNET_RTF_GATEWAY);
if ((ret = ipnet_rtnetlink_route_gw_setup(family, netif? netif->ipcom.ifindex : 0, &ugw, &gw, IP_RTNH_DATA(nh))) < 0)
return ret;
}
mpa_size -= (Ip_ssize_t)IP_RTNH_ALIGN(nh->rtnh_len);
if (mpa_size > 0)
nh = IP_RTNH_NEXT(nh);
}
param.domain = family;
param.vr = vr;
param.table = table;
param.netif = netif;
param.key = &ukey;
param.netmask = mask;
param.gateway = gw;
param.pid = mem->pid;
param.seq = nlh->nlmsg_seq;
param.no_ref_count = IP_TRUE;
/* Try to add the route */
if (netif)
IPNET_IF_LOCK(netif);
ret = ipnet_route_add(&param);
if (netif != IP_NULL)
IPNET_IF_UNLOCK(netif);
if (is_multipath_route)
{
gw = IP_NULL;
if (ret < 0 && ret != -IP_ERRNO_EEXIST)
goto rollback;
if (mpa_size == 0)
{
ret = 0;
break;
}
else if (mpa_size < 0)
{
/* Malformed packet */
ret = -IP_ERRNO_EINVAL;
goto rollback;
}
}
else
break;
}
return ret;
rollback:
(void)ipnet_rtnetlink_route_delroute_family(mem, nlh, rta, family);
return ret;
}
/*
*===========================================================================
* ipnet_rtnetlink_route_delroute_family
*===========================================================================
* Description: Delete a route via NETLINK.
* Parameters: data - Message payload
* len - Length of message.
* nlh - NETLINK message header
* arg - Reference to route attributes.
*
* Returns: 0 - Success
* <0 - Failure
*
*/
IP_GLOBAL int
ipnet_rtnetlink_route_delroute_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlh,
struct Ip_rtattr **rta,
int family)
{
int ret = -1;
Ip_u16 vr;
Ip_u32 table;
Ip_u32 ifindex = 0;
Ip_bool is_multipath_route = IP_FALSE;
Ip_size_t mpa_size = 0;
struct Ip_rtnexthop *nh = IP_NULL;
struct Ip_sockaddr *gw = IP_NULL;
void *mask = IP_NULL;
struct Ip_rtmsg *rtm = IP_NLMSG_DATA(nlh);
union Ip_sockaddr_union ugw;
Ipnet_rtnetlink_key_t ukey;
#ifdef IPMPLS
struct Ip_sockaddr_mpls gw_mpls;
#endif /* IPMPLS */
table = (Ip_u32) IPCOM_ROUTE_TABLE_GET(rtm->rtm_table);
#ifdef IPNET_USE_ROUTE_TABLE_NAMES
if (rta[IP_RTA_TABLE_NAME -1])
{
if (ipnet_route_vr_and_table_from_name(IP_RTA_DATA(rta[IP_RTA_TABLE_NAME - 1]),
&vr,
&table) < 0)
return -IP_ERRNO_ESRCH;
}
else
#endif
{
if (mem->vr == IPCOM_VR_ANY)
return -IP_ERRNO_EINVAL;
vr = ipnet_rtnetlink_vr(rta[IP_RTA_VR - 1], mem->vr);
if (rta[IP_RTA_TABLE - 1])
table = IP_GET_32ON8(IP_RTA_DATA(rta[IP_RTA_TABLE - 1]));
}
if (rta[IP_RTA_OIF -1])
{
if (rta[IP_RTA_OIF-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32)))
return -IP_ERRNO_EINVAL;
ifindex = IP_GET_32ON8(IP_RTA_DATA(rta[IP_RTA_OIF-1]));
}
if (rta[IP_RTA_MULTIPATH -1])
{
is_multipath_route = IP_TRUE;
nh = IP_RTA_DATA(rta[IP_RTA_MULTIPATH-1]);
mpa_size = IP_RTA_PAYLOAD(rta[IP_RTA_MULTIPATH-1]);
if ((nh == IP_NULL) || (mpa_size == 0))
return -IP_ERRNO_EINVAL;
}
if ((ret = ipnet_rtnetlink_route_key_setup(family, &ukey, ifindex, &mask, rtm->rtm_dst_len, rta[IP_RTA_DST-1])) < 0)
return ret;
if ((ret = ipnet_rtnetlink_route_gw_setup(family, ifindex, &ugw, &gw, rta[IP_RTA_GATEWAY-1])) < 0)
return ret;
if (rta[IP_RTA_GATEWAY-1])
gw = &ugw.sa;
#ifdef IPMPLS
if (rta[IP_RTA_NH_PROTO-1])
{
Ip_u32 nh_type;
/* IPNET MPLS pseudo-wire route */
if (rta[IP_RTA_NH_PROTO-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32)))
return -IP_ERRNO_EINVAL;
if (rta[IP_RTA_NH_PROTO_DATA-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32)))
return -IP_ERRNO_EINVAL;
ipcom_memcpy(&nh_type, IP_RTA_DATA(rta[IP_RTA_NH_PROTO-1]), sizeof(Ip_u32));
if (nh_type != IPNET_ETH_P_MPLS_UNICAST)
return -IP_ERRNO_EINVAL;
ipcom_memset(&gw_mpls, 0, sizeof(gw_mpls));
gw_mpls.smpls_family = IP_AF_MPLS;
IPCOM_SA_LEN_SET(&gw_mpls, sizeof (struct Ip_sockaddr_mpls));
ipcom_memcpy(&gw_mpls.smpls_key, IP_RTA_DATA(rta[IP_RTA_NH_PROTO_DATA-1]), sizeof(Ip_u32));
gw = (struct Ip_sockaddr *)&gw_mpls;
}
#endif
while(1)
{
if (is_multipath_route)
{
ifindex = (Ip_u32) nh->rtnh_ifindex;
if (nh->rtnh_len > sizeof(struct Ip_rtnexthop))
{
/* Multihop route has gateway */
if ((ret = ipnet_rtnetlink_route_gw_setup(family, ifindex, &ugw, &gw, IP_RTNH_DATA(nh))) < 0)
return ret;
}
}
/* Delete the route */
ret = ipnet_route_delete2(family,
vr,
table,
&ukey,
mask,
gw,
ifindex,
0,
0,
0);
if (is_multipath_route)
{
mpa_size -= IP_RTNH_ALIGN(nh->rtnh_len);
gw = IP_NULL;
if (mpa_size > 0)
nh = IP_RTNH_NEXT(nh);
else
break;
}
else
break;
}
return is_multipath_route ? 0 : ret;
}
/*
*===========================================================================
* ipnet_rtnetlink_route_sz_fill_metrics
*===========================================================================
* Description: Fill route metrics as attributes in a NETLINK route message.
* Parameters: data - Message buffer
* metrics - Pointer to IPNET metrics pointer.
* Returns: Length of added attributes
*
*/
IP_GLOBAL int
ipnet_rtnetlink_route_sz_fill_metrics(Ipnet_netlink_mem_t *mem,
struct Ipnet_rt_metrics *metrics,
Ip_u32 mtu)
{
struct Ip_rtattr *rta;
rta = ipnet_rtnetlink_rta_sz_nested_begin(mem, IP_RTA_METRICS);
if (!rta)
return -1;
if (metrics->rmx_mtu > 0)
mtu = metrics->rmx_mtu;
if (!ipnet_rtnetlink_rta_sz_put(mem, IP_RTAX_MTU, sizeof(Ip_u32), &mtu))
return -1;
/* Add Round Trip Time */
if (metrics->rmx_rtt > 0)
if (!ipnet_rtnetlink_rta_sz_put(mem, IP_RTAX_RTT, sizeof(Ip_u32), &metrics->rmx_rtt))
return -1;
/* Add RTT Variance */
if (metrics->rmx_rttvar > 0)
if (!ipnet_rtnetlink_rta_sz_put(mem, IP_RTAX_RTTVAR, sizeof(Ip_u32), &metrics->rmx_rttvar))
return -1;
/* Terminate the nested RTA */
ipnet_rtnetlink_rta_sz_nested_end(mem, rta);
return 0;
}
/*
*==========================================================================
* ipnet_rtnetlink_route_dump_family
*===========================================================================
* Description: Get interface info via NETLINK
* Parameters: data - Message payload.
* len - Length of message.
* cb - NETLINK callback entry
*
* Returns: 0 - Success
* <0 - Failure
*
*/
IP_GLOBAL int
ipnet_rtnetlink_route_dump_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
int family,
Ip_ptrdiff_t *args)
{
Ipnet_rtnetlink_route_family_t param;
Ip_ptrdiff_t *done = &args[0];
Ip_ptrdiff_t *s_vr = &args[1];
Ip_ptrdiff_t *s_table = &args[2];
Ip_ptrdiff_t *s_rtm = &args[3];
Ip_ptrdiff_t *s_continue = &args[4];
param.nlmsg = nlmsg;
param.table = 0;
param.family = (Ip_u8) family;
param.mem = mem;
if (*done)
goto exit_out;
param.state.aborted = 0;
param.state.done = done;
param.state.rt = s_rtm;
param.state.table = s_table;
param.state.vr = s_vr;
param.state.cont = *s_continue;
/* */
ipcom_hash_for_each(ipnet->rtabs,
(Ipcom_hash_foreach_cb_func)ipnet_rtnetlink_route_foreach_vr_family,
&param);
/* Are we aborted? */
*s_continue = param.state.aborted;
/* If not aborted; we're done */
if (!param.state.aborted)
*done = 1;
exit_out:
return (int) param.mem->used;
}
/*
*==========================================================================
* ipnet_rtnetlink_getroute_family
*===========================================================================
* Description: Get interface info via NETLINK
* Parameters: data - Message payload.
* len - Length of message.
* cb - NETLINK callback entry
*
* Returns: 0 - Success
* <0 - Failure
*
*/
IP_GLOBAL int
ipnet_rtnetlink_route_getroute_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlh,
struct Ip_rtattr **rta,
int family)
{
switch (family)
{
#ifdef IPCOM_USE_INET
case IP_AF_INET:
return ipnet_rtnetlink_ip4_getroute(mem, nlh, rta);
#endif
#ifdef IPCOM_USE_INET6
case IP_AF_INET6:
return ipnet_rtnetlink_ip6_getroute(mem, nlh, rta);
#endif
default:
return -IP_ERRNO_EAFNOSUPPORT;;
}
}
/*
*===========================================================================
* ipnet_rtnetlink_route_key_setup
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL int
ipnet_rtnetlink_route_key_setup(int family,
Ipnet_rtnetlink_key_t *ukey,
Ip_u32 ifindex,
void **maskp,
unsigned mask_len,
struct Ip_rtattr *dst)
{
int ret;
#ifdef IPCOM_USE_INET
if (family == IP_AF_INET)
{
if ((ret = ipnet_rtnetlink_ip4_route_key_setup(ukey, ifindex, maskp, mask_len, dst)) < 0)
return ret;
}
else
#endif
#ifdef IPCOM_USE_INET6
if (family == IP_AF_INET6)
{
if ((ret = ipnet_rtnetlink_ip6_route_key_setup(ukey, ifindex, maskp, mask_len, dst)) < 0)
return ret;
}
else
#endif
{
return -IP_ERRNO_EAFNOSUPPORT;
}
return 0;
}
/*
*===========================================================================
* ipnet_rtnetlink_route_gw_setup
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL int
ipnet_rtnetlink_route_gw_setup(int family,
Ip_u32 ifindex,
union Ip_sockaddr_union *ugw,
struct Ip_sockaddr **gw,
struct Ip_rtattr *rta)
{
int ret;
#ifdef IPCOM_USE_INET
if (family == IP_AF_INET)
{
if ((ret = ipnet_rtnetlink_ip4_route_gw_setup(ifindex, ugw, gw, rta)) < 0)
return ret;
}
else
#endif
#ifdef IPCOM_USE_INET6
if (family == IP_AF_INET6)
{
if ((ret = ipnet_rtnetlink_ip6_route_gw_setup(ifindex, ugw, gw, rta)) < 0)
return ret;
}
else
#endif
{
return -IP_ERRNO_EAFNOSUPPORT;
}
return 0;
}
/*
*===========================================================================
* ipnet_rtnetlink_ip6_addr_event
*===========================================================================
* Description: Status of a network interface has changed, create a IFINFO
* event on NETLNK..
* Parameters: netif - The interface.
* Returns: -
*
*/
IP_STATIC void
ipnet_rtnetlink_route_event(struct Ipnet_route_entry_struct *rt, int event)
{
Ipcom_pkt *pkt = IP_NULL;
Ipnet_netlink_mem_t mem;
int ret = -1;
int group;
if (!ipnet_netlink_pkt_alloc(&pkt, IP_NULL, IP_TRUE, &mem, 512))
return;
/* Must explicitly switch to the correct VR here */
pkt->vr_index = mem.vr = IPNET_ROUTE_GET_VR(rt->head);
#ifdef IPCOM_USE_INET
if (IPNET_ROUTE_GET_FAMILY(rt->head) == IP_AF_INET)
{
ret = ipnet_rtnetlink_ip4_route_fill_info (&mem,
rt,
0,
event,
0);
group = IP_RTNLGRP_IPV4_ROUTE;
}
#endif
#ifdef IPCOM_USE_INET6
if (IPNET_ROUTE_GET_FAMILY(rt->head) == IP_AF_INET6)
{
ret = ipnet_rtnetlink_ip6_route_fill_info (&mem,
rt,
0,
event,
0);
group = IP_RTNLGRP_IPV6_ROUTE;
}
#endif
if (ret < 0)
ipcom_pkt_free(pkt);
else
{
pkt->end += ret;
/* We're done; do report this pkt */
ipnet_rtnetlink_broadcast(pkt, group);
}
}
IP_GLOBAL void
ipnet_rtnetlink_route_add(Ipnet_route_entry *rt)
{
ipnet_rtnetlink_route_event(rt, IP_RTM_NEWROUTE);
}
IP_GLOBAL void
ipnet_rtnetlink_route_change(Ipnet_route_entry *rt)
{
ipnet_rtnetlink_route_event(rt, IP_RTM_NEWROUTE);
}
IP_GLOBAL void
ipnet_rtnetlink_route_del(Ipnet_route_entry *rt)
{
ipnet_rtnetlink_route_event(rt, IP_RTM_DELROUTE);
}
IP_GLOBAL void
ipnet_rtnetlink_route_miss(Ipcom_route *rtab, IP_CONST void *key)
{
/*!! TODO */
(void)rtab;
(void)key;
}
IP_GLOBAL void
ipnet_rtnetlink_route_redirect(Ipcom_route *rtab, Ip_u32 ifindex,
IP_CONST void *dst, IP_CONST void *new_gw)
{
/*!! TODO */
(void)rtab;
(void)ifindex;
(void)dst;
(void)new_gw;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
#endif /* IPNET_USE_NETLINK */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/