/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifdef IPCOM_KERNEL #undef IPCOM_KERNEL #endif #include "ipnet_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #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 [table ] [root ] [match ] [exact ] "IP_LF); ipnet_ip_stdio_printf(cfg, " [type ] [scope ] [src
] [via ]"IP_LF); ipnet_ip_stdio_printf(cfg, " [dev ]"IP_LF); ipnet_ip_stdio_printf(cfg, " ip route [table ] [type ] [scope ] [src
]"IP_LF); ipnet_ip_stdio_printf(cfg, " [via ] [dev ] [vr ] [nexthop <[dev ] [via ] [weight ]>]"IP_LF); ipnet_ip_stdio_printf(cfg, " [rtt ] [rttvar ] [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 - The route must be in table "IP_LF); ipnet_ip_stdio_printf(cfg, " root - Selects routes not shorter than the ROOT "IP_LF); ipnet_ip_stdio_printf(cfg, " match - Selects routes not longer than the MATCH "IP_LF); ipnet_ip_stdio_printf(cfg, " exact - The route must be in exact match to "IP_LF); ipnet_ip_stdio_printf(cfg, " type - The route must be of type . For example unicast, broadcast, multicast etc."IP_LF); ipnet_ip_stdio_printf(cfg, " scope - The route must have scope identifier ."IP_LF); ipnet_ip_stdio_printf(cfg, " src - The route must have preferred source address ."IP_LF); ipnet_ip_stdio_printf(cfg, " via - The route must be routed through gateway."IP_LF); ipnet_ip_stdio_printf(cfg, " dev - The route must be associated with the device ."IP_LF); ipnet_ip_stdio_printf(cfg, " rtt - Add RTT metric. The RTT metric is specified in ms."IP_LF); ipnet_ip_stdio_printf(cfg, " rttvar - Add RTTVAR metric. The RTTVAR metric is specified in ms."IP_LF); ipnet_ip_stdio_printf(cfg, " mtu - Add MTU metric."IP_LF); ipnet_ip_stdio_printf(cfg, " weight - Add WEIGHT metric to a multipath route."IP_LF); ipnet_ip_stdio_printf(cfg, " 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 ", 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
"); break; case IPNET_IP_ROUTE_LISTFLUSH_ROOT: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "root ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_prefix(cfg->family, &filter->root, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "root "); break; case IPNET_IP_ROUTE_LISTFLUSH_MATCH: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "match ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_prefix(cfg->family, &filter->match, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "match "); break; case IPNET_IP_ROUTE_LISTFLUSH_EXACT: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "exact ", IPNET_IP_ROUTE_LISTFLUSH_MATCH)) return -1; if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "exact ", 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 "); /* 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 ", 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 "); break; case IPNET_IP_ROUTE_LISTFLUSH_SCOPE: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "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 "); break; case IPNET_IP_ROUTE_LISTFLUSH_PREFSRC: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "src ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_prefix(cfg->family, &filter->src, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "src "); break; case IPNET_IP_ROUTE_LISTFLUSH_VIA: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "via ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_prefix(cfg->family, &filter->via, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "via "); break; case IPNET_IP_ROUTE_LISTFLUSH_DEVNAME: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "dev ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "dev "); /* 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_uint(&filter->proto, cfg, IP_NULL)) return ipnet_cmd_ip_requires_argument(cfg, "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
", 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
"); 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL)) return ipnet_cmd_ip_requires_argument(cfg, "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 ", 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 "); rtm->rtm_type = (Ip_u8)uarg; break; case IPNET_IP_ROUTE_MODIFY_SCOPE: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "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 "); rtm->rtm_scope = (Ip_u8)uarg; break; case IPNET_IP_ROUTE_MODIFY_PREFSRC: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "src ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_prefix(rtm->rtm_family, &addr, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "src "); 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_prefix(rtm->rtm_family, &addr, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "via "); 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "dev "); /* 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL)) return ipnet_cmd_ip_requires_argument(cfg, "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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL)) return ipnet_cmd_ip_requires_argument(cfg, "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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL)) return ipnet_cmd_ip_requires_argument(cfg, "rtt "); 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL)) return ipnet_cmd_ip_requires_argument(cfg, "rttvar "); 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL)) return ipnet_cmd_ip_requires_argument(cfg, "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 "); 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 "); 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 "); 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 **************************************************************************** */