1275 lines
48 KiB
C
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
|
|
****************************************************************************
|
|
*/
|