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

1275 lines
48 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_cmd_ip_route.c,v $ $Revision: 1.2.40.3 $
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_cmd_ip_route.c,v $
* $Author: hxie $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#ifdef IPCOM_KERNEL
#undef IPCOM_KERNEL
#endif
#include "ipnet_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_cmd.h>
#include <ipcom_getopt.h>
#include <ipcom_shell.h>
#include <ipcom_sysctl.h>
#include "ipnet.h"
#include "ipnet_cmd.h"
#include "ipnet_ctrl.h"
#include "ipnet_h.h"
#include "ipnet_sysctl.h"
#include "ipnet_cmd_ip.h"
#ifdef IPNET_USE_NETLINK
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
enum
{
IPNET_IP_ROUTE_MAIN_HELP,
IPNET_IP_ROUTE_MAIN_LIST,
IPNET_IP_ROUTE_MAIN_FLUSH,
IPNET_IP_ROUTE_MAIN_GET,
IPNET_IP_ROUTE_MAIN_ADD,
IPNET_IP_ROUTE_MAIN_APPEND,
IPNET_IP_ROUTE_MAIN_DEL,
IPNET_IP_ROUTE_MAIN_CHANGE,
IPNET_IP_ROUTE_MAIN_REPLACE,
IPNET_IP_ROUTE_MAIN_MONITOR
};
enum
{
IPNET_IP_ROUTE_LISTFLUSH_TABLE,
IPNET_IP_ROUTE_LISTFLUSH_ROOT,
IPNET_IP_ROUTE_LISTFLUSH_EXACT,
IPNET_IP_ROUTE_LISTFLUSH_MATCH,
IPNET_IP_ROUTE_LISTFLUSH_TYPE,
IPNET_IP_ROUTE_LISTFLUSH_SCOPE,
IPNET_IP_ROUTE_LISTFLUSH_PREFSRC,
IPNET_IP_ROUTE_LISTFLUSH_VIA,
IPNET_IP_ROUTE_LISTFLUSH_DEVNAME,
IPNET_IP_ROUTE_LISTFLUSH_PROTOCOL,
IPNET_IP_ROUTE_LISTFLUSH_NOOP
};
enum
{
IPNET_IP_ROUTE_MODIFY_TABLE,
IPNET_IP_ROUTE_MODIFY_TYPE,
IPNET_IP_ROUTE_MODIFY_SCOPE,
IPNET_IP_ROUTE_MODIFY_PREFSRC,
IPNET_IP_ROUTE_MODIFY_VIA,
IPNET_IP_ROUTE_MODIFY_DEVNAME,
IPNET_IP_ROUTE_MODIFY_METRIC_MTU,
IPNET_IP_ROUTE_MODIFY_METRIC_RTT,
IPNET_IP_ROUTE_MODIFY_METRIC_RTTVAR,
IPNET_IP_ROUTE_MODIFY_METRIC_HOP,
IPNET_IP_ROUTE_MODIFY_NEXTHOP,
IPNET_IP_ROUTE_MODIFY_VR,
IPNET_IP_ROUTE_MODIFY_DST,
IPNET_IP_ROUTE_MODIFY_PROTOCOL,
IPNET_IP_ROUTE_MODIFY_NOOP
};
enum
{
IPNET_IP_ROUTE_MODIFY_NH_VIA,
IPNET_IP_ROUTE_MODIFY_NH_DEVNAME,
IPNET_IP_ROUTE_MODIFY_NH_WEIGHT,
IPNET_IP_ROUTE_MODIFY_NH_ONLINK,
IPNET_IP_ROUTE_MODIFY_NH_NEXTHOP
};
static Ipcom_cmd_int_str_map ipnet_ip_route_nexthop[] =
{
{ IPNET_IP_ROUTE_MODIFY_NH_VIA, "via" },
{ IPNET_IP_ROUTE_MODIFY_NH_DEVNAME, "dev" },
{ IPNET_IP_ROUTE_MODIFY_NH_WEIGHT, "weight" },
{ IPNET_IP_ROUTE_MODIFY_NH_ONLINK, "onlink" },
{ IPNET_IP_ROUTE_MODIFY_NH_NEXTHOP, "nexthop" },
{ -1, IP_NULL },
};
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
typedef struct Ipnet_cmd_ip_module_route_filter_struct
{
Ip_u64 mask;
Ip_u32 table;
Ipnet_ip_prefix_t root;
Ipnet_ip_prefix_t match;
Ip_u32 type;
Ip_u32 scope;
Ip_u32 proto;
Ipnet_ip_prefix_t src;
Ipnet_ip_prefix_t via;
Ip_u32 ifindex;
} Ipnet_cmd_ip_module_route_filter_t;
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
static Ipcom_cmd_int_str_map ipnet_ip_route_main[] =
{
{ IPNET_IP_ROUTE_MAIN_HELP, "help" },
{ IPNET_IP_ROUTE_MAIN_LIST, "show" },
{ IPNET_IP_ROUTE_MAIN_LIST, "list" },
{ IPNET_IP_ROUTE_MAIN_LIST, "lst" },
{ IPNET_IP_ROUTE_MAIN_FLUSH, "flush" },
{ IPNET_IP_ROUTE_MAIN_GET, "get" },
{ IPNET_IP_ROUTE_MAIN_ADD, "add" },
{ IPNET_IP_ROUTE_MAIN_APPEND, "append" },
{ IPNET_IP_ROUTE_MAIN_DEL, "delete" },
{ IPNET_IP_ROUTE_MAIN_DEL, "del" },
{ IPNET_IP_ROUTE_MAIN_CHANGE, "change" },
{ IPNET_IP_ROUTE_MAIN_CHANGE, "chg" },
{ IPNET_IP_ROUTE_MAIN_REPLACE, "replace" },
{ IPNET_IP_ROUTE_MAIN_MONITOR, "monitor" },
{ -1, IP_NULL },
};
static Ipcom_cmd_int_str_map ipnet_ip_route_listflush[] =
{
{ IPNET_IP_ROUTE_LISTFLUSH_TABLE, "table" },
{ IPNET_IP_ROUTE_LISTFLUSH_ROOT, "root" },
{ IPNET_IP_ROUTE_LISTFLUSH_EXACT, "exact" },
{ IPNET_IP_ROUTE_LISTFLUSH_MATCH, "match" },
{ IPNET_IP_ROUTE_LISTFLUSH_TYPE, "type" },
{ IPNET_IP_ROUTE_LISTFLUSH_SCOPE, "scope" },
{ IPNET_IP_ROUTE_LISTFLUSH_PREFSRC, "src" },
{ IPNET_IP_ROUTE_LISTFLUSH_VIA, "via" },
{ IPNET_IP_ROUTE_LISTFLUSH_DEVNAME, "dev" },
{ IPNET_IP_ROUTE_LISTFLUSH_DEVNAME, "oif" },
{ IPNET_IP_ROUTE_LISTFLUSH_NOOP, "to" },
{ -1, IP_NULL },
};
static Ipcom_cmd_int_str_map ipnet_ip_route_modify[] =
{
{ IPNET_IP_ROUTE_MODIFY_TABLE, "table" },
{ IPNET_IP_ROUTE_MODIFY_TYPE, "type" },
{ IPNET_IP_ROUTE_MODIFY_SCOPE, "scope" },
{ IPNET_IP_ROUTE_MODIFY_PREFSRC, "src" },
{ IPNET_IP_ROUTE_MODIFY_VIA, "via" },
{ IPNET_IP_ROUTE_MODIFY_DEVNAME, "dev" },
{ IPNET_IP_ROUTE_MODIFY_DEVNAME, "oif" },
{ IPNET_IP_ROUTE_MODIFY_PROTOCOL, "protocol" },
{ IPNET_IP_ROUTE_MODIFY_PROTOCOL, "proto" },
{ IPNET_IP_ROUTE_MODIFY_METRIC_MTU, "mtu" },
{ IPNET_IP_ROUTE_MODIFY_METRIC_HOP, "weight" },
{ IPNET_IP_ROUTE_MODIFY_METRIC_HOP, "hoplimit" },
{ IPNET_IP_ROUTE_MODIFY_METRIC_RTT, "rtt" },
{ IPNET_IP_ROUTE_MODIFY_METRIC_RTTVAR, "rttvar" },
{ IPNET_IP_ROUTE_MODIFY_NEXTHOP, "nexthop" },
{ IPNET_IP_ROUTE_MODIFY_VR, "vr" },
{ IPNET_IP_ROUTE_MODIFY_NOOP, "to" },
{ -1, IP_NULL },
};
Ipcom_cmd_int_str_map ipnet_ip_rtn_types[] =
{
{ IP_RTN_UNSPEC, "any" },
{ IP_RTN_UNSPEC, "unspec" },
{ IP_RTN_LOCAL, "local" },
{ IP_RTN_NAT, "nat" },
{ IP_RTN_BROADCAST, "broadcast" },
{ IP_RTN_BROADCAST, "brd" },
{ IP_RTN_ANYCAST, "anycast" },
{ IP_RTN_MULTICAST, "multicast" },
{ IP_RTN_PROHIBIT, "prohibit" },
{ IP_RTN_UNREACHABLE, "unreachable" },
{ IP_RTN_BLACKHOLE, "blackhole" },
{ IP_RTN_XRESOLVE, "xresolve" },
{ IP_RTN_UNICAST, "unicast" },
{ IP_RTN_THROW, "throw" },
{ -1, IP_NULL },
};
Ipcom_cmd_int_str_map ipnet_ip_scope_types[] =
{
{ IP_RT_SCOPE_UNIVERSE, "global" },
{ IP_RT_SCOPE_UNIVERSE, "universe" },
{ IP_RT_SCOPE_SITE, "site" },
{ IP_RT_SCOPE_LINK, "link" },
{ IP_RT_SCOPE_HOST, "host" },
{ IP_RT_SCOPE_NOWHERE, "nowhere" },
{ -1, IP_NULL },
};
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
IP_STATIC int
ipnet_cmd_ip_route_usage(Ipnet_ip_config_t *cfg, int ret)
{
ipnet_ip_stdio_printf(cfg, ""IP_LF);
ipnet_ip_stdio_printf(cfg, "NAME"IP_LF);
ipnet_ip_stdio_printf(cfg, " ip route - Display and modify the IPNET routing states and configurations"IP_LF);
ipnet_ip_stdio_printf(cfg, ""IP_LF);
ipnet_ip_stdio_printf(cfg, "SYNOPSIS"IP_LF);
ipnet_ip_stdio_printf(cfg, " ip route <list|flush> [table <id>] [root <prefix>] [match <prefix>] [exact <prefix>] "IP_LF);
ipnet_ip_stdio_printf(cfg, " [type <type>] [scope <scope>] [src <address>] [via <gateway>]"IP_LF);
ipnet_ip_stdio_printf(cfg, " [dev <devname>]"IP_LF);
ipnet_ip_stdio_printf(cfg, " ip route <add|change|replace|delete|get|append> [table <id>] [type <type>] [scope <scope>] [src <address>]"IP_LF);
ipnet_ip_stdio_printf(cfg, " [via <gateway>] [dev <devname>] [vr <vr>] [nexthop <[dev <devname>] [via <gateway>] [weight <weight>]>]"IP_LF);
ipnet_ip_stdio_printf(cfg, " [rtt <RTT>] [rttvar <RTTVAR>] [mtu <mtu>]"IP_LF);
ipnet_ip_stdio_printf(cfg, " ip route help"IP_LF);
ipnet_ip_stdio_printf(cfg, " ip route monitor"IP_LF);
ipnet_ip_stdio_printf(cfg, ""IP_LF);
ipnet_ip_stdio_printf(cfg, "DESCRIPTION"IP_LF);
ipnet_ip_stdio_printf(cfg, " help Display usage information"IP_LF);
ipnet_ip_stdio_printf(cfg, " list|flush List/Flush all routes matching the selectors"IP_LF);
ipnet_ip_stdio_printf(cfg, " add|change|replace Add/Change/Replace a route based on the selectors"IP_LF);
ipnet_ip_stdio_printf(cfg, " Duplicate matching is done on destination, table and mask"IP_LF);
ipnet_ip_stdio_printf(cfg, " append Same as add, but with more explicit route matching."IP_LF);
ipnet_ip_stdio_printf(cfg, " Duplicate matching is done on destination, table and mask, "IP_LF);
ipnet_ip_stdio_printf(cfg, " interface and gateway"IP_LF);
ipnet_ip_stdio_printf(cfg, " delete Delete a route based on the selectors"IP_LF);
ipnet_ip_stdio_printf(cfg, " get Get a route based on the selectors"IP_LF);
ipnet_ip_stdio_printf(cfg, " Selector Decription:"IP_LF);
ipnet_ip_stdio_printf(cfg, " table <id> - The route must be in table <id>"IP_LF);
ipnet_ip_stdio_printf(cfg, " root <prefix> - Selects routes not shorter than the ROOT <prefix>"IP_LF);
ipnet_ip_stdio_printf(cfg, " match <prefix> - Selects routes not longer than the MATCH <prefix>"IP_LF);
ipnet_ip_stdio_printf(cfg, " exact <prefix> - The route must be in exact match to <prefix>"IP_LF);
ipnet_ip_stdio_printf(cfg, " type <type> - The route must be of type <type>. For example unicast, broadcast, multicast etc."IP_LF);
ipnet_ip_stdio_printf(cfg, " scope <scope> - The route must have scope identifier <scope>."IP_LF);
ipnet_ip_stdio_printf(cfg, " src <source> - The route must have preferred source address <source>."IP_LF);
ipnet_ip_stdio_printf(cfg, " via <gateway> - The route must be routed through gateway."IP_LF);
ipnet_ip_stdio_printf(cfg, " dev <devname> - The route must be associated with the device <devname>."IP_LF);
ipnet_ip_stdio_printf(cfg, " rtt <RTT> - Add RTT metric. The RTT metric is specified in ms."IP_LF);
ipnet_ip_stdio_printf(cfg, " rttvar <RTTVAR> - Add RTTVAR metric. The RTTVAR metric is specified in ms."IP_LF);
ipnet_ip_stdio_printf(cfg, " mtu <mtu> - Add MTU metric."IP_LF);
ipnet_ip_stdio_printf(cfg, " weight <weight> - Add WEIGHT metric to a multipath route."IP_LF);
ipnet_ip_stdio_printf(cfg, " vr <vr> - Virtual Router descriptor."IP_LF);
ipnet_ip_stdio_printf(cfg, " nexthop - Starts a multipath route. Anything following the first nexthop"IP_LF);
ipnet_ip_stdio_printf(cfg, " will be considered multipath commands ."IP_LF);
return ret;
}
IP_STATIC Ip_u32
ipnet_cmd_ip_module_route_get_table(Ipnet_ip_handle_msg_t *nlmsg)
{
struct Ip_rtmsg *rtm = IP_NLMSG_DATA(nlmsg->hdr);
if (nlmsg->rta[IP_RTA_TABLE])
return ipnet_ip_rta_u32(nlmsg->rta[IP_RTA_TABLE]);
return rtm->rtm_table;
}
IP_STATIC void
ipnet_cmd_ip_module_route_filter(Ipnet_ip_config_t *cfg, Ipnet_cmd_ip_module_route_filter_t *filter)
{
Ipnet_ip_handle_msg_t *nlmsg, *nnlmsg;
nlmsg = IPCOM_LIST_FIRST(&cfg->handle->replies);
for ( ; IP_NULL != nlmsg; nlmsg = nnlmsg)
{
unsigned i;
struct Ip_rtmsg *rtm = IP_NLMSG_DATA(nlmsg->hdr);
nnlmsg = IPCOM_LIST_NEXT(&nlmsg->next);
if (0 != ipnet_ip_parse_reply(nlmsg, IP_RTA_MAX, sizeof(struct Ip_rtmsg)))
{
ipnet_ip_free_reply(nlmsg);
continue;
}
if (IP_NULL != nlmsg->rta[IP_RTA_VR] && cfg->vr != ipnet_ip_rta_s32(nlmsg->rta[IP_RTA_VR]))
{
ipnet_ip_free_reply(nlmsg);
continue;
}
for (i = 0; i < sizeof(filter->mask) * 8; i++)
{
if (IP_BIT_ISSET(filter->mask, IP_BIT_UVAL64(i)))
{
Ipnet_ip_prefix_t p;
switch (i)
{
case IPNET_IP_ROUTE_LISTFLUSH_TABLE:
if (filter->table != 0 && filter->table != ipnet_cmd_ip_module_route_get_table(nlmsg))
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
break;
case IPNET_IP_ROUTE_LISTFLUSH_ROOT:
if (filter->root.prefix_family != rtm->rtm_family
|| filter->root.prefix_length > rtm->rtm_dst_len
|| IP_NULL == nlmsg->rta[IP_RTA_DST])
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
if (IP_FALSE == ipnet_ip_match_prefix(&filter->root, IP_RTA_DATA(nlmsg->rta[IP_RTA_DST])))
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
break;
case IPNET_IP_ROUTE_LISTFLUSH_MATCH:
if (filter->match.prefix_family != rtm->rtm_family
|| filter->match.prefix_length < rtm->rtm_dst_len
|| IP_NULL == nlmsg->rta[IP_RTA_DST])
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
p.prefix_family = rtm->rtm_family;
p.prefix_length = rtm->rtm_dst_len;
p.prefix_max = filter->match.prefix_max;
ipcom_memcpy(&p.prefix, IP_RTA_DATA(nlmsg->rta[IP_RTA_DST]), p.prefix_max/8);
if (IP_FALSE == ipnet_ip_match_prefix(&p, &filter->match.prefix))
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
break;
case IPNET_IP_ROUTE_LISTFLUSH_TYPE:
if (filter->type != 0 && filter->type != rtm->rtm_type)
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
break;
case IPNET_IP_ROUTE_LISTFLUSH_SCOPE:
if (filter->scope != rtm->rtm_scope)
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
break;
case IPNET_IP_ROUTE_LISTFLUSH_PREFSRC:
if (filter->src.prefix_family != rtm->rtm_family
|| IP_NULL == nlmsg->rta[IP_RTA_PREFSRC])
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
if (IP_FALSE == ipnet_ip_match_prefix(&filter->src, IP_RTA_DATA(nlmsg->rta[IP_RTA_PREFSRC])))
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
break;
case IPNET_IP_ROUTE_LISTFLUSH_VIA:
if (filter->via.prefix_family != rtm->rtm_family
|| IP_NULL == nlmsg->rta[IP_RTA_GATEWAY])
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
if (IP_FALSE == ipnet_ip_match_prefix(&filter->via, IP_RTA_DATA(nlmsg->rta[IP_RTA_GATEWAY])))
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
break;
case IPNET_IP_ROUTE_LISTFLUSH_DEVNAME:
if (IP_NULL == nlmsg->rta[IP_RTA_OIF])
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
if (filter->ifindex != ipnet_ip_rta_u32(nlmsg->rta[IP_RTA_OIF]))
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
break;
case IPNET_IP_ROUTE_LISTFLUSH_PROTOCOL:
if (rtm->rtm_protocol != filter->proto)
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
break;
}
}
}
next_message:
IP_NOOP;
}
}
IP_STATIC int
ipnet_cmd_ip_module_route_print(Ipnet_ip_config_t *cfg, Ipnet_cmd_ip_module_route_filter_t *filter, Ipnet_ip_handle_msg_t *nlmsg)
{
Ip_u64 mask = filter? filter->mask : 0;
char buf[128];
Ip_u32 tmp;
struct Ip_rtmsg *rtm = IP_NLMSG_DATA(nlmsg->hdr);
if (cfg->is_silent)
return 0;
(void)ipnet_ip_parse_reply(nlmsg, IP_RTA_MAX, sizeof(struct Ip_rtmsg));
if (nlmsg->hdr->nlmsg_type == IP_RTM_DELROUTE)
ipnet_ip_stdio_printf(cfg, "Deleted ");
if (rtm->rtm_type != IP_RTN_UNICAST && IP_BIT_ISFALSE(mask, IP_BIT_UVAL64(IPNET_IP_ROUTE_LISTFLUSH_TYPE)))
ipnet_ip_stdio_printf(cfg, "%s ", ipnet_ip_key_to_str(ipnet_ip_rtn_types, rtm->rtm_type, buf, sizeof(buf)));
ipnet_ip_stdio_printf(cfg, "%s", ipnet_ip_format_host(rtm->rtm_family, IP_RTA_DATA(nlmsg->rta[IP_RTA_DST]), rtm->rtm_dst_len, buf, sizeof(buf), "default"));
if (IP_NULL != nlmsg->rta[IP_RTA_GATEWAY] && IP_BIT_ISFALSE(mask, IP_BIT_UVAL64(IPNET_IP_ROUTE_LISTFLUSH_VIA)))
ipnet_ip_stdio_printf(cfg, " via %s", ipnet_ip_format_host(rtm->rtm_family, IP_RTA_DATA(nlmsg->rta[IP_RTA_GATEWAY]), -1, buf, sizeof(buf), IP_NULL));
if (IP_NULL != nlmsg->rta[IP_RTA_OIF] && IP_BIT_ISFALSE(mask, IP_BIT_UVAL64(IPNET_IP_ROUTE_LISTFLUSH_DEVNAME)))
ipnet_ip_stdio_printf(cfg, " dev %s", ipnet_ip_if_indextoname(buf, ipnet_ip_rta_u32(nlmsg->rta[IP_RTA_OIF]), ipnet_ip_rta_vr(cfg, nlmsg->rta[IP_RTA_VR])));
if (IP_NULL != nlmsg->rta[IP_RTA_PREFSRC] && IP_BIT_ISFALSE(mask, IP_BIT_UVAL64(IPNET_IP_ROUTE_LISTFLUSH_PREFSRC)))
ipnet_ip_stdio_printf(cfg, " src %s", ipnet_ip_format_host(rtm->rtm_family, IP_RTA_DATA(nlmsg->rta[IP_RTA_PREFSRC]), -1, buf, sizeof(buf), IP_NULL));
tmp = ipnet_cmd_ip_module_route_get_table(nlmsg);
if ((tmp != IPCOM_ROUTE_TABLE_DEFAULT && IP_BIT_ISFALSE(mask, IP_BIT_UVAL64(IPNET_IP_ROUTE_LISTFLUSH_TABLE))) ||
(IP_BIT_ISTRUE(mask, IP_BIT_UVAL64(IPNET_IP_ROUTE_LISTFLUSH_TABLE)) && IP_NULL != filter && 0 == filter->table))
ipnet_ip_stdio_printf(cfg, " table %d", tmp);
if (rtm->rtm_protocol != IP_RTPROT_BOOT && IP_BIT_ISFALSE(mask, IP_BIT_UVAL64(IPNET_IP_ROUTE_LISTFLUSH_PROTOCOL)))
ipnet_ip_stdio_printf(cfg, " proto %d", rtm->rtm_protocol);
if (rtm->rtm_scope != IP_RT_SCOPE_UNIVERSE && IP_BIT_ISFALSE(mask, IP_BIT_UVAL64(IPNET_IP_ROUTE_LISTFLUSH_SCOPE)))
ipnet_ip_stdio_printf(cfg, " scope %d", rtm->rtm_scope);
if (IP_NULL != nlmsg->rta[IP_RTA_VR] && cfg->vr != ipnet_ip_rta_s32(nlmsg->rta[IP_RTA_VR]))
ipnet_ip_stdio_printf(cfg, " vr %u", ipnet_ip_rta_u32(nlmsg->rta[IP_RTA_VR]));
if (IP_NULL != nlmsg->rta[IP_RTA_METRICS])
{
struct Ip_rtattr *mattr[IP_RTAX_MAX + 1];
struct Ip_rtattr *attr = IP_RTA_DATA(nlmsg->rta[IP_RTA_METRICS]);
Ip_size_t attrlen = IP_RTA_PAYLOAD(nlmsg->rta[IP_RTA_METRICS]);
ipnet_ip_parse_attr(mattr, IP_RTAX_MAX, attr, attrlen);
/* Parse the metrics */
if (mattr[IP_RTAX_MTU])
ipnet_ip_stdio_printf(cfg, " mtu %d", ipnet_ip_rta_u32(mattr[IP_RTAX_MTU]));
if (mattr[IP_RTAX_RTT])
ipnet_ip_stdio_printf(cfg, " rtt %u ms", ipnet_ip_rta_u32(mattr[IP_RTAX_RTT]));
if (mattr[IP_RTAX_RTTVAR])
ipnet_ip_stdio_printf(cfg, " rttvar %u ms", ipnet_ip_rta_u32(mattr[IP_RTAX_RTTVAR]));
if (mattr[IP_RTAX_HOPLIMIT])
ipnet_ip_stdio_printf(cfg, " weight %d", ipnet_ip_rta_u32(mattr[IP_RTAX_HOPLIMIT]) + 1);
}
if (IP_NULL != nlmsg->rta[IP_RTA_MULTIPATH])
{
struct Ip_rtnexthop *nh = IP_RTA_DATA(nlmsg->rta[IP_RTA_MULTIPATH]);
Ip_size_t nhlen = IP_RTA_PAYLOAD(nlmsg->rta[IP_RTA_MULTIPATH]);
for (;nhlen >= sizeof(*nh) && nh->rtnh_len <= nhlen; nhlen -= IP_NLMSG_ALIGN(nh->rtnh_len), nh = IP_RTNH_NEXT(nh))
{
ipnet_ip_stdio_printf(cfg, "%s\tnexthop", cfg->oneline);
if (nh->rtnh_len > sizeof(*nh))
{
struct Ip_rtattr *rattr[IP_RTA_MAX + 1];
ipnet_ip_parse_attr(rattr, IP_RTA_MAX, IP_RTNH_DATA(nh), (Ip_size_t) nh->rtnh_len - sizeof(*nh));
if (IP_NULL != rattr[IP_RTA_GATEWAY])
ipnet_ip_stdio_printf(cfg, " via %s", ipnet_ip_format_host(rtm->rtm_family, IP_RTA_DATA(rattr[IP_RTA_GATEWAY]), -1, buf, sizeof(buf), IP_NULL));
}
ipnet_ip_stdio_printf(cfg, " dev %s", ipnet_ip_if_indextoname(buf, (Ip_u32)nh->rtnh_ifindex, ipnet_ip_rta_vr(cfg, nlmsg->rta[IP_RTA_VR])));
ipnet_ip_stdio_printf(cfg, " weight %d", nh->rtnh_hops + 1);
}
}
ipnet_ip_stdio_printf(cfg, IP_LF);
return 0;
}
IP_STATIC Ip_ssize_t
ipnet_cmd_ip_module_route_listflush(Ipnet_ip_config_t *cfg, Ipnet_cmd_ip_module_route_filter_t *filter)
{
char *sarg;
int arg;
/* Time to go through the filter parameters */
while (IP_FALSE != ipnet_ip_cmd_param_str(&sarg, cfg))
{
if (IP_FALSE == ipnet_ip_str_to_key(&arg, ipnet_ip_route_listflush, sarg))
return ipnet_cmd_ip_unknown_keyword(cfg, sarg);
switch (arg)
{
case IPNET_IP_ROUTE_LISTFLUSH_TABLE:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "table <table>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&filter->table, cfg, ipnet_ip_default_values))
return ipnet_cmd_ip_requires_argument(cfg, "table <table>");
break;
case IPNET_IP_ROUTE_LISTFLUSH_ROOT:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "root <prefix>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_prefix(cfg->family, &filter->root, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "root <prefix>");
break;
case IPNET_IP_ROUTE_LISTFLUSH_MATCH:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "match <prefix>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_prefix(cfg->family, &filter->match, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "match <prefix>");
break;
case IPNET_IP_ROUTE_LISTFLUSH_EXACT:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "exact <prefix>", IPNET_IP_ROUTE_LISTFLUSH_MATCH))
return -1;
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "exact <prefix>", IPNET_IP_ROUTE_LISTFLUSH_ROOT))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_prefix(cfg->family, &filter->match, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "exact <prefix>");
/* Same value in root as match */
ipcom_memcpy(&filter->root, &filter->match, sizeof(filter->root));
break;
case IPNET_IP_ROUTE_LISTFLUSH_TYPE:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "type <type>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&filter->type, cfg, ipnet_ip_rtn_types))
return ipnet_cmd_ip_requires_argument(cfg, "type <type>");
break;
case IPNET_IP_ROUTE_LISTFLUSH_SCOPE:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "scope <scope>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&filter->scope, cfg, ipnet_ip_scope_types))
return ipnet_cmd_ip_requires_argument(cfg, "scope <scope>");
break;
case IPNET_IP_ROUTE_LISTFLUSH_PREFSRC:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "src <source>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_prefix(cfg->family, &filter->src, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "src <source>");
break;
case IPNET_IP_ROUTE_LISTFLUSH_VIA:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "via <gateway>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_prefix(cfg->family, &filter->via, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "via <gateway>");
break;
case IPNET_IP_ROUTE_LISTFLUSH_DEVNAME:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "dev <devname>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "dev <devname>");
/* RESOLVE SPARAM TO IFINDEX */
filter->ifindex = ipnet_ip_if_nametoindex(sarg, cfg->vr);
if (0 == filter->ifindex)
{
ipnet_ip_stdio_printf(cfg, "Unable to resolve interface name \'%s\'"IP_LF, sarg);
return -1;
}
break;
case IPNET_IP_ROUTE_LISTFLUSH_PROTOCOL:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "proto <proto>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&filter->proto, cfg, IP_NULL))
return ipnet_cmd_ip_requires_argument(cfg, "proto <proto>");
break;
case IPNET_IP_ROUTE_LISTFLUSH_NOOP:
/* Dont do anything */
break;
}
}
/* If no table or type is specified, do add some default parameters */
if (IP_BIT_ISFALSE(cfg->mask, IP_BIT_UVAL64(IPNET_IP_ROUTE_LISTFLUSH_TABLE)))
{
filter->table = IPCOM_ROUTE_TABLE_DEFAULT;
(void)ipnet_cmd_ip_check_mask(cfg, IP_NULL, IPNET_IP_ROUTE_LISTFLUSH_TABLE);
if (IP_BIT_ISFALSE(cfg->mask, IP_BIT_UVAL64(IPNET_IP_ROUTE_LISTFLUSH_TYPE)))
{
(void)ipnet_cmd_ip_check_mask(cfg, IP_NULL, IPNET_IP_ROUTE_LISTFLUSH_TYPE);
filter->type = IP_RTN_UNICAST;
}
}
/* All parameters are parsed
* Store the argument match mask
*/
ipcom_memcpy(&filter->mask, &cfg->mask, sizeof(filter->mask));
return 0;
}
IP_STATIC Ip_ssize_t
ipnet_cmd_ip_module_route_list(Ipnet_ip_config_t *cfg)
{
Ipnet_cmd_ip_module_route_filter_t filter;
Ip_ssize_t ret = ipnet_cmd_ip_module_route_listflush(cfg, &filter);
if (0 <= ret)
{
Ipnet_ip_handle_msg_t *nlmsg;
/* Dump the NETLINK information */
if (0 > (ret = ipnet_ip_dump_netlink(cfg, cfg->handle, IP_RTM_GETROUTE, cfg->family, cfg->core, IP_TRUE)))
{
ipnet_ip_stdio_printf(cfg, "Unable to dump routing table, error = %d"IP_LF, ret);
return ret;
}
/* Filter the reply chain */
ipnet_cmd_ip_module_route_filter(cfg, &filter);
for (nlmsg = IPCOM_LIST_FIRST(&cfg->handle->replies); IP_NULL != nlmsg; nlmsg = IPCOM_LIST_NEXT(&nlmsg->next))
ipnet_cmd_ip_module_route_print(cfg, &filter, nlmsg);
}
return ret;
}
IP_STATIC Ip_ssize_t
ipnet_cmd_ip_module_route_flush(Ipnet_ip_config_t *cfg)
{
Ipnet_cmd_ip_module_route_filter_t filter;
Ip_ssize_t ret = ipnet_cmd_ip_module_route_listflush(cfg, &filter);
if (0 <= ret)
{
Ipnet_ip_handle_msg_t *nlmsg;
/* Dump the NETLINK information */
if (0 > (ret = ipnet_ip_dump_netlink(cfg, cfg->handle, IP_RTM_GETROUTE, cfg->family, cfg->core, IP_TRUE)))
{
ipnet_ip_stdio_printf(cfg, "Unable to dump routing table, error = %d"IP_LF, ret);
return ret;
}
/* Filter the reply chain */
ipnet_cmd_ip_module_route_filter(cfg, &filter);
for (nlmsg = IPCOM_LIST_FIRST(&cfg->handle->replies); IP_NULL != nlmsg; nlmsg = IPCOM_LIST_NEXT(&nlmsg->next))
{
if (nlmsg->hdr->nlmsg_type != IP_RTM_NEWROUTE)
continue;
nlmsg->hdr->nlmsg_type = IP_RTM_DELROUTE;
nlmsg->hdr->nlmsg_flags = IP_NLM_F_REQUEST|IP_NLM_F_ACK;
(void)ipnet_ip_request_netlink(cfg, cfg->handle, nlmsg->hdr, cfg->core, IP_TRUE);
ipnet_cmd_ip_module_route_print(cfg, &filter, nlmsg);
}
}
return 0;
}
IP_STATIC Ip_ssize_t
ipnet_cmd_ip_module_route_modify(Ipnet_ip_config_t *cfg)
{
char *sarg;
int arg;
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->tx[0];
struct Ip_rtmsg *rtm;
Ip_u32 uarg;
struct Ip_rtattr *metric = (struct Ip_rtattr *)&cfg->handle->rx[0];
ipcom_memset(nlh, 0, sizeof(*nlh));
nlh->nlmsg_len = IP_NLMSG_LENGTH(0);
/* Start of the routing message */
rtm = (struct Ip_rtmsg *)IP_NLMSG_DATA(nlh);
ipcom_memset(rtm, 0, sizeof(*rtm));
rtm->rtm_family = cfg->family;
rtm->rtm_type = IP_RTN_UNICAST;
rtm->rtm_protocol = IP_RTPROT_BOOT;
rtm->rtm_scope = IP_RT_SCOPE_UNIVERSE;
/* Move past the routing header */
nlh->nlmsg_len = (Ip_u32) (IP_NLMSG_ALIGN(nlh->nlmsg_len) + sizeof(*rtm));
/**/
metric->rta_len = IP_RTA_LENGTH(0);
metric->rta_type = IP_RTA_METRICS;
/* Time to go through the filter parameters */
while (IP_FALSE != ipnet_ip_cmd_param_str(&sarg, cfg))
{
Ipnet_ip_prefix_t addr;
if (IP_FALSE == ipnet_ip_str_to_key(&arg, ipnet_ip_route_modify, sarg))
{
if (IP_TRUE != ipnet_ip_str_to_prefix(rtm->rtm_family, sarg, &addr))
return ipnet_cmd_ip_unknown_keyword(cfg, sarg);
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "destination", IPNET_IP_ROUTE_MODIFY_DST))
return -1;
/* 'to' Indicator */
rtm->rtm_dst_len = (Ip_u8) addr.prefix_length;
ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_RTA_DST, &addr.prefix, addr.prefix_max/8);
if (rtm->rtm_family == IP_AF_UNSPEC)
rtm->rtm_family = addr.prefix_family;
continue;
}
switch (arg)
{
case IPNET_IP_ROUTE_MODIFY_TABLE:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "table <table>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, ipnet_ip_default_values))
return ipnet_cmd_ip_requires_argument(cfg, "table <table>");
ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_RTA_TABLE, &uarg, sizeof(Ip_u32));
rtm->rtm_table = (Ip_u8)uarg;
break;
case IPNET_IP_ROUTE_MODIFY_VR:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "vr <vr>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL))
return ipnet_cmd_ip_requires_argument(cfg, "vr <vr>");
ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_RTA_VR, &uarg, sizeof(Ip_u32));
break;
case IPNET_IP_ROUTE_MODIFY_TYPE:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "type <type>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, ipnet_ip_rtn_types))
return ipnet_cmd_ip_requires_argument(cfg, "type <type>");
rtm->rtm_type = (Ip_u8)uarg;
break;
case IPNET_IP_ROUTE_MODIFY_SCOPE:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "scope <scope>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, ipnet_ip_scope_types))
return ipnet_cmd_ip_requires_argument(cfg, "scope <scope>");
rtm->rtm_scope = (Ip_u8)uarg;
break;
case IPNET_IP_ROUTE_MODIFY_PREFSRC:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "src <source>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_prefix(rtm->rtm_family, &addr, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "src <source>");
if (rtm->rtm_family == IP_AF_UNSPEC)
rtm->rtm_family = addr.prefix_family;
ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_RTA_PREFSRC, &addr.prefix, addr.prefix_max/8);
break;
case IPNET_IP_ROUTE_MODIFY_VIA:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "via <gateway>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_prefix(rtm->rtm_family, &addr, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "via <gateway>");
if (rtm->rtm_family == IP_AF_UNSPEC)
rtm->rtm_family = addr.prefix_family;
ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_RTA_GATEWAY, &addr.prefix, addr.prefix_max/8);
break;
case IPNET_IP_ROUTE_MODIFY_DEVNAME:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "dev <devname>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "dev <devname>");
/* RESOLVE SPARAM TO IFINDEX */
uarg = ipnet_ip_if_nametoindex(sarg, cfg->vr);
if (0 == uarg)
{
ipnet_ip_stdio_printf(cfg, "Unable to resolve interface name \'%s\'"IP_LF, sarg);
return -1;
}
ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_RTA_OIF, &uarg, sizeof(Ip_u32));
break;
case IPNET_IP_ROUTE_MODIFY_PROTOCOL:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "proto <proto>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL))
return ipnet_cmd_ip_requires_argument(cfg, "proto <proto>");
rtm->rtm_protocol = (Ip_u8)uarg;
break;
case IPNET_IP_ROUTE_MODIFY_METRIC_MTU:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "mtu <mtu>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL))
return ipnet_cmd_ip_requires_argument(cfg, "mtu <mtu>");
ipcom_netlink_rta_addattr_l(metric, IPNET_IP_HANDLE_BUFFER/2, IP_RTAX_MTU, &uarg, sizeof(Ip_u32));
break;
case IPNET_IP_ROUTE_MODIFY_METRIC_RTT:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "rtt <RTT in ms>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL))
return ipnet_cmd_ip_requires_argument(cfg, "rtt <RTT in ms>");
ipcom_netlink_rta_addattr_l(metric, IPNET_IP_HANDLE_BUFFER/2, IP_RTAX_RTT, &uarg, sizeof(Ip_u32));
break;
case IPNET_IP_ROUTE_MODIFY_METRIC_RTTVAR:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "rttvar <RTTVAR in ms>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL))
return ipnet_cmd_ip_requires_argument(cfg, "rttvar <RTTVAR in ms>");
ipcom_netlink_rta_addattr_l(metric, IPNET_IP_HANDLE_BUFFER/2, IP_RTAX_RTTVAR, &uarg, sizeof(Ip_u32));
break;
case IPNET_IP_ROUTE_MODIFY_METRIC_HOP:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "hoplimit <hoplimit>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL))
return ipnet_cmd_ip_requires_argument(cfg, "hoplimit <hoplimit>");
if (uarg == 0 || uarg > 256)
{
ipnet_ip_stdio_printf(cfg, "\'hoplimit\' is invalid");
return -1;
}
ipcom_netlink_rta_addattr_l(metric, IPNET_IP_HANDLE_BUFFER/2, IP_RTAX_HOPLIMIT, &uarg, sizeof(Ip_u32));
break;
case IPNET_IP_ROUTE_MODIFY_NEXTHOP:
{
struct Ip_rtattr *rnh = (struct Ip_rtattr *)&cfg->handle->rx[IPNET_IP_HANDLE_BUFFER/2];
struct Ip_rtnexthop *nh;
rnh->rta_len = IP_RTA_LENGTH(0);
rnh->rta_type = IP_RTA_MULTIPATH;
nh = IP_RTA_DATA(rnh);
ipcom_memset(nh, 0, sizeof(*nh));
nh->rtnh_len = sizeof(*nh);
rnh->rta_len = (Ip_u16) (IP_RTA_ALIGN(rnh->rta_len) + nh->rtnh_len);
while (IP_FALSE != ipnet_ip_cmd_param_str(&sarg, cfg))
{
if (IP_FALSE == ipnet_ip_str_to_key(&arg, ipnet_ip_route_nexthop, sarg))
return ipnet_cmd_ip_unknown_keyword(cfg, sarg);
switch (arg)
{
case IPNET_IP_ROUTE_MODIFY_NH_VIA:
if (IP_TRUE != ipnet_ip_cmd_param_prefix(rtm->rtm_family, &addr, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "via <gateway>");
ipcom_netlink_rta_addattr_l(rnh, IPNET_IP_HANDLE_BUFFER/2, IP_RTA_GATEWAY, &addr.prefix, addr.prefix_max/8);
nh->rtnh_len = (Ip_u16) (nh->rtnh_len + addr.prefix_max/8 + sizeof(struct Ip_rtattr));
break;
case IPNET_IP_ROUTE_MODIFY_NH_DEVNAME:
if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "dev <devname>");
nh->rtnh_ifindex = (Ip_s32)ipnet_ip_if_nametoindex(sarg, cfg->vr);
break;
case IPNET_IP_ROUTE_MODIFY_NH_WEIGHT:
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL))
return ipnet_cmd_ip_requires_argument(cfg, "weight <weight>");
if (uarg == 0 || uarg > 256)
{
ipnet_ip_stdio_printf(cfg, "\'weight\' is invalid");
return -1;
}
nh->rtnh_hops = (Ip_u8) (uarg - 1);
break;
case IPNET_IP_ROUTE_MODIFY_NH_ONLINK:
nh->rtnh_flags |= IP_RTNH_F_ONLINK;
break;
case IPNET_IP_ROUTE_MODIFY_NH_NEXTHOP:
nh = IP_RTNH_NEXT(nh);
ipcom_memset(nh, 0, sizeof(*nh));
nh->rtnh_len = sizeof(*nh);
rnh->rta_len = (Ip_u16) (IP_RTA_ALIGN(rnh->rta_len) + nh->rtnh_len);
break;
}
}
if (IP_RTA_LENGTH(0) != rnh->rta_len)
ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_RTA_MULTIPATH, IP_RTA_DATA(rnh), IP_RTA_PAYLOAD(rnh));
}
break;
case IPNET_IP_ROUTE_MODIFY_NOOP:
/* Dont do anything */
break;
}
}
/* Add additional metrics */
if (IP_RTA_LENGTH(0) != metric->rta_len)
ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_RTA_METRICS, IP_RTA_DATA(metric), IP_RTA_PAYLOAD(metric));
if (IP_BIT_ISFALSE(cfg->mask, IP_BIT_UVAL64(IPNET_IP_ROUTE_MODIFY_DST)))
{
ipnet_ip_stdio_printf(cfg, "Need destination address for route"IP_LF);
return -1;
}
return 0;
}
IP_STATIC Ip_ssize_t
ipnet_cmd_ip_module_route_get(Ipnet_ip_config_t *cfg)
{
Ip_ssize_t ret = ipnet_cmd_ip_module_route_modify(cfg);
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->tx[0];
if (0 <= ret)
{
Ipnet_ip_handle_msg_t *nlmsg;
nlh->nlmsg_type = IP_RTM_GETROUTE;
nlh->nlmsg_flags = IP_NLM_F_REQUEST;
if (0 <= (ret = ipnet_ip_request_netlink(cfg, cfg->handle, IP_NULL, cfg->core, IP_TRUE)))
{
for (nlmsg = IPCOM_LIST_FIRST(&cfg->handle->replies); IP_NULL != nlmsg; nlmsg = IPCOM_LIST_NEXT(&nlmsg->next))
ipnet_cmd_ip_module_route_print(cfg, IP_NULL, nlmsg);
}
else
ipnet_ip_stdio_printf(cfg, "RTNETLINK answers: %s"IP_LF, ipcom_strerror(-(int)ret));
}
return ret;
}
IP_STATIC Ip_ssize_t
ipnet_cmd_ip_module_route_add(Ipnet_ip_config_t *cfg)
{
Ip_ssize_t ret = ipnet_cmd_ip_module_route_modify(cfg);
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->tx[0];
if (0 <= ret)
{
nlh->nlmsg_flags = IP_NLM_F_CREATE|IP_NLM_F_EXCL|IP_NLM_F_REQUEST|IP_NLM_F_ACK;
nlh->nlmsg_type = IP_RTM_NEWROUTE;
if (0 > (ret = ipnet_ip_request_netlink(cfg, cfg->handle, IP_NULL, cfg->core, IP_TRUE)))
ipnet_ip_stdio_printf(cfg, "RTNETLINK answers: %s"IP_LF, ipcom_strerror(-(int)ret));
}
return ret;
}
IP_STATIC Ip_ssize_t
ipnet_cmd_ip_module_route_append(Ipnet_ip_config_t *cfg)
{
Ip_ssize_t ret = ipnet_cmd_ip_module_route_modify(cfg);
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->tx[0];
if (0 <= ret)
{
nlh->nlmsg_flags = IP_NLM_F_CREATE|IP_NLM_F_APPEND|IP_NLM_F_REQUEST|IP_NLM_F_ACK;
nlh->nlmsg_type = IP_RTM_NEWROUTE;
if (0 > (ret = ipnet_ip_request_netlink(cfg, cfg->handle, IP_NULL, cfg->core, IP_TRUE)))
ipnet_ip_stdio_printf(cfg, "RTNETLINK answers: %s"IP_LF, ipcom_strerror(-(int)ret));
}
return ret;
}
IP_STATIC Ip_ssize_t
ipnet_cmd_ip_module_route_change(Ipnet_ip_config_t *cfg)
{
Ip_ssize_t ret = ipnet_cmd_ip_module_route_modify(cfg);
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->tx[0];
if (0 <= ret)
{
nlh->nlmsg_flags = IP_NLM_F_REPLACE|IP_NLM_F_REQUEST|IP_NLM_F_ACK;
nlh->nlmsg_type = IP_RTM_NEWROUTE;
if (0 > (ret = ipnet_ip_request_netlink(cfg, cfg->handle, IP_NULL, cfg->core, IP_TRUE)))
ipnet_ip_stdio_printf(cfg, "RTNETLINK answers: %s"IP_LF, ipcom_strerror(-(int)ret));
}
return ret;
}
IP_STATIC Ip_ssize_t
ipnet_cmd_ip_module_route_replace(Ipnet_ip_config_t *cfg)
{
Ip_ssize_t ret = ipnet_cmd_ip_module_route_modify(cfg);
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->tx[0];
if (0 <= ret)
{
nlh->nlmsg_flags = IP_NLM_F_CREATE|IP_NLM_F_REPLACE|IP_NLM_F_REQUEST|IP_NLM_F_ACK;
nlh->nlmsg_type = IP_RTM_NEWROUTE;
if (0 > (ret = ipnet_ip_request_netlink(cfg, cfg->handle, IP_NULL, cfg->core, IP_TRUE)))
ipnet_ip_stdio_printf(cfg, "RTNETLINK answers: %s"IP_LF, ipcom_strerror(-(int)ret));
}
return ret;
}
IP_STATIC Ip_ssize_t
ipnet_cmd_ip_module_route_delete(Ipnet_ip_config_t *cfg)
{
Ip_ssize_t ret = ipnet_cmd_ip_module_route_modify(cfg);
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->tx[0];
if (0 <= ret)
{
nlh->nlmsg_type = IP_RTM_DELROUTE;
nlh->nlmsg_flags = IP_NLM_F_REQUEST|IP_NLM_F_ACK;
if (0 > (ret = ipnet_ip_request_netlink(cfg, cfg->handle, IP_NULL, cfg->core, IP_TRUE)))
ipnet_ip_stdio_printf(cfg, "RTNETLINK answers: %s"IP_LF, ipcom_strerror(-(int)ret));
}
return ret;
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
IP_GLOBAL Ip_ssize_t
ipnet_cmd_ip_module_route(Ipnet_ip_config_t *cfg)
{
int arg;
char *sparam;
cfg->handle = ipnet_ip_open_netlink(cfg, 0, IP_NETLINK_ROUTE);
if (IP_NULL == cfg->handle)
return -1;
/* START */
/* Resolve the subcommand */
if (IP_TRUE != ipnet_ip_cmd_param_str(&sparam, cfg))
return ipnet_cmd_ip_route_usage(cfg, -1);
/* Resolve the module */
if (IP_FALSE == ipnet_ip_str_to_key(&arg, ipnet_ip_route_main, sparam))
return ipnet_cmd_ip_unknown_keyword(cfg, sparam);
else
{
ipnet_cmd_ip_clear_mask(cfg);
switch (arg)
{
case IPNET_IP_ROUTE_MAIN_ADD:
return ipnet_cmd_ip_module_route_add(cfg);
case IPNET_IP_ROUTE_MAIN_APPEND:
return ipnet_cmd_ip_module_route_append(cfg);
case IPNET_IP_ROUTE_MAIN_DEL:
return ipnet_cmd_ip_module_route_delete(cfg);
case IPNET_IP_ROUTE_MAIN_CHANGE:
return ipnet_cmd_ip_module_route_change(cfg);
case IPNET_IP_ROUTE_MAIN_REPLACE:
return ipnet_cmd_ip_module_route_replace(cfg);
case IPNET_IP_ROUTE_MAIN_GET:
return ipnet_cmd_ip_module_route_get(cfg);
case IPNET_IP_ROUTE_MAIN_LIST:
return ipnet_cmd_ip_module_route_list(cfg);
case IPNET_IP_ROUTE_MAIN_FLUSH:
return ipnet_cmd_ip_module_route_flush(cfg);
case IPNET_IP_ROUTE_MAIN_HELP:
return ipnet_cmd_ip_route_usage(cfg, 0);
case IPNET_IP_ROUTE_MAIN_MONITOR:
return ipnet_cmd_ip_module_monitor(cfg, IP_BIT_VAL(IPNET_IP_MODULE_ROUTE));
}
}
return 0;
}
IP_GLOBAL Ip_u32
ipnet_cmd_ip_module_route_monitor_groups(Ipnet_ip_config_t *cfg)
{
if (cfg->family == IP_AF_INET)
return IP_RTMGRP_IPV4_ROUTE;
if (cfg->family == IP_AF_INET6)
return IP_RTMGRP_IPV6_ROUTE;
return IP_RTMGRP_IPV6_ROUTE|IP_RTMGRP_IPV4_ROUTE;
}
IP_GLOBAL Ip_bool
ipnet_cmd_ip_module_route_monitor(Ipnet_ip_config_t *cfg, Ipnet_ip_handle_msg_t *nlmsg)
{
if (nlmsg->hdr->nlmsg_type == IP_RTM_NEWROUTE || nlmsg->hdr->nlmsg_type == IP_RTM_DELROUTE)
{
ipnet_cmd_ip_module_route_print(cfg, IP_NULL, nlmsg);
return IP_TRUE;
}
return IP_FALSE;
}
IP_GLOBAL Ip_ssize_t
ipnet_cmd_ip_module_route_flush_all(Ipnet_ip_config_t *cfg)
{
/* Flush 'em all */
return ipnet_cmd_ip_module_route_flush(cfg);
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
#endif /* IPNET_USE_NETLINK */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/