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

1968 lines
77 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_cmd_ip_link.c,v $ $Revision: 1.4.12.4 $
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_cmd_ip_link.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_LINK_MAIN_HELP,
IPNET_IP_LINK_MAIN_LIST,
IPNET_IP_LINK_MAIN_FLUSH,
IPNET_IP_LINK_MAIN_ADD,
IPNET_IP_LINK_MAIN_SET,
IPNET_IP_LINK_MAIN_DEL,
IPNET_IP_LINK_MAIN_REPLACE,
IPNET_IP_LINK_MAIN_MONITOR
};
enum
{
IPNET_IP_LINK_ATTRIBUTE_DEVNAME,
IPNET_IP_LINK_ATTRIBUTE_UP,
IPNET_IP_LINK_ATTRIBUTE_DOWN,
IPNET_IP_LINK_ATTRIBUTE_TYPE,
IPNET_IP_LINK_ATTRIBUTE_LINK,
IPNET_IP_LINK_ATTRIBUTE_NAME,
IPNET_IP_LINK_ATTRIBUTE_MTU,
IPNET_IP_LINK_ATTRIBUTE_MULTICAST,
IPNET_IP_LINK_ATTRIBUTE_ALLMULTI,
IPNET_IP_LINK_ATTRIBUTE_PROMISC,
IPNET_IP_LINK_ATTRIBUTE_ADDRESS,
IPNET_IP_LINK_ATTRIBUTE_BROADCAST,
IPNET_IP_LINK_ATTRIBUTE_VR,
IPNET_IP_LINK_ATTRIBUTE_NOOP,
IPNET_IP_LINK_ATTRIBUTE_NOOP_ARG,
IPNET_IP_LINK_ATTRIBUTE_HELP
};
enum
{
IPNET_IP_LINK_VLAN_ATTRIBUTE_ID,
IPNET_IP_LINK_VLAN_ATTRIBUTE_DEVNAME,
IPNET_IP_LINK_VLAN_ATTRIBUTE_EQM,
IPNET_IP_LINK_VLAN_ATTRIBUTE_IQM
};
#ifdef IPCOM_FORWARDER_NAE
enum
{
IPNET_IP_LINK_NAE_RESET
};
#endif
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
typedef struct Ipnet_cmd_ip_module_link_filter_struct
{
Ip_u64 mask;
Ip_u32 ifindex;
char type[64];
} Ipnet_cmd_ip_module_link_filter_t;
typedef struct Ipnet_ip_link_type_map_struct
{
int type;
int family;
} Ipnet_ip_link_type_map;
typedef void (*Ipnet_ip_link_info_print_t) (Ipnet_ip_config_t *cfg, Ipnet_ip_handle_msg_t *nlmsg, struct Ip_rtattr *link_info, const char *dev);
typedef int (*Ipnet_ip_link_info_parse_t) (Ipnet_ip_config_t *cfg, struct Ip_rtattr *link_data, Ip_size_t link_data_size, char **ifla_dev);
typedef void (*Ipnet_ip_link_info_help_t) (Ipnet_ip_config_t *cfg);
typedef struct Ipnet_ip_link_info_struct
{
char *kind;
Ipnet_ip_link_info_print_t print_linkinfo;
Ipnet_ip_link_info_parse_t parse_linkinfo;
Ipnet_ip_link_info_help_t help_linkinfo;
} Ipnet_ip_link_info_map;
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
IP_STATIC int ipnet_cmd_ip_link_usage(Ipnet_ip_config_t *cfg, int ret);
IP_STATIC void ipnet_ip_link_info_vlan_print(Ipnet_ip_config_t *cfg, Ipnet_ip_handle_msg_t *nlmsg, struct Ip_rtattr *link_info, const char *dev);
IP_STATIC int ipnet_ip_link_info_vlan_parse(Ipnet_ip_config_t *cfg, struct Ip_rtattr *link_data, Ip_size_t link_data_size, char **ifla_dev);
IP_STATIC void ipnet_ip_link_info_vlan_help(Ipnet_ip_config_t *cfg);
IP_STATIC void ipnet_ip_link_info_tunnel_print(Ipnet_ip_config_t *cfg, Ipnet_ip_handle_msg_t *nlmsg, struct Ip_rtattr *link_info, const char *dev);
IP_STATIC int ipnet_ip_link_info_tunnel_parse(Ipnet_ip_config_t *cfg, struct Ip_rtattr *link_data, Ip_size_t link_data_size, char **ifla_dev);
IP_STATIC void ipnet_ip_link_info_tunnel_help(Ipnet_ip_config_t *cfg);
#ifdef IPCOM_FORWARDER_NAE
IP_STATIC void ipnet_ip_link_info_nae_print(Ipnet_ip_config_t *cfg, Ipnet_ip_handle_msg_t *nlmsg, struct Ip_rtattr *link_info, const char *dev);
IP_STATIC int ipnet_ip_link_info_nae_parse(Ipnet_ip_config_t *cfg, struct Ip_rtattr *link_data, Ip_size_t link_data_size, char **ifla_dev);
IP_STATIC void ipnet_ip_link_info_nae_help(Ipnet_ip_config_t *cfg);
#endif
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
static Ipcom_cmd_int_str_map ipnet_ip_link_main[] =
{
{ IPNET_IP_LINK_MAIN_HELP, "help" },
{ IPNET_IP_LINK_MAIN_LIST, "show" },
{ IPNET_IP_LINK_MAIN_LIST, "list" },
{ IPNET_IP_LINK_MAIN_LIST, "lst" },
{ IPNET_IP_LINK_MAIN_LIST, "get" },
{ IPNET_IP_LINK_MAIN_FLUSH, "flush" },
{ IPNET_IP_LINK_MAIN_ADD, "add" },
{ IPNET_IP_LINK_MAIN_DEL, "delete" },
{ IPNET_IP_LINK_MAIN_DEL, "del" },
{ IPNET_IP_LINK_MAIN_SET, "set" },
{ IPNET_IP_LINK_MAIN_SET, "change" },
{ IPNET_IP_LINK_MAIN_SET, "chg" },
{ IPNET_IP_LINK_MAIN_REPLACE, "replace" },
{ IPNET_IP_LINK_MAIN_MONITOR, "monitor" },
{ -1, IP_NULL },
};
static Ipcom_cmd_int_str_map ipnet_ip_link_type[] =
{
{ IP_ARPHRD_ETHER, "ether" },
{ IP_ARPHRD_TUNNEL, "ipip" },
{ IP_ARPHRD_LOOPBACK, "loopback" },
{ IP_ARPHRD_VOID, "void" },
{ IP_ARPHRD_PPP, "ppp" },
{ IP_ARPHRD_IEEE80211, "ieee802.11" },
{ IP_ARPHRD_SIT, "sit" },
{ IP_ARPHRD_TUNNEL6, "tunnel6" },
{ IP_ARPHRD_IPGRE, "gre" },
{ IP_ARPHRD_NONE, "none" },
{ IP_ARPHRD_TUNNEL6TO4, "tunnel6to4" },
{ IP_ARPHRD_IPGRE6, "gre6" },
{ -1, IP_NULL },
};
static Ipcom_cmd_int_str_map ipnet_ip_link_tunnel_type[] =
{
{ IP_ARPHRD_TUNNEL, "ipip" },
{ IP_ARPHRD_SIT, "sit" },
{ IP_ARPHRD_TUNNEL6, "ip6ip6" },
{ IP_ARPHRD_TUNNEL6, "tunnel6" },
{ IP_ARPHRD_IPGRE, "gre" },
{ IP_ARPHRD_TUNNEL6TO4, "6to4" },
{ IP_ARPHRD_TUNNEL6TO4, "tunnel6to4" },
{ IP_ARPHRD_IPGRE6, "gre6" },
{ -1, IP_NULL },
};
static Ipnet_ip_link_type_map ipnet_ip_link_type_map[] =
{
{ IP_ARPHRD_ETHER, IP_AF_UNSPEC },
{ IP_ARPHRD_TUNNEL, IP_AF_INET },
{ IP_ARPHRD_LOOPBACK, IP_AF_UNSPEC },
{ IP_ARPHRD_VOID, IP_AF_UNSPEC },
{ IP_ARPHRD_PPP, IP_AF_UNSPEC },
{ IP_ARPHRD_IEEE80211, IP_AF_UNSPEC },
{ IP_ARPHRD_SIT, IP_AF_INET },
{ IP_ARPHRD_TUNNEL6, IP_AF_INET6 },
{ IP_ARPHRD_IPGRE, IP_AF_INET },
{ IP_ARPHRD_NONE, IP_AF_UNSPEC },
{ IP_ARPHRD_TUNNEL6TO4, IP_AF_INET6 },
{ IP_ARPHRD_IPGRE6, IP_AF_INET6 },
{ -1, -1 }
};
static Ipcom_cmd_int_str_map ipnet_ip_link_attributes[] =
{
{ IPNET_IP_LINK_ATTRIBUTE_DEVNAME, "dev" },
{ IPNET_IP_LINK_ATTRIBUTE_UP, "up" },
{ IPNET_IP_LINK_ATTRIBUTE_DOWN, "down" },
{ IPNET_IP_LINK_ATTRIBUTE_TYPE, "type" },
{ IPNET_IP_LINK_ATTRIBUTE_LINK, "link" },
{ IPNET_IP_LINK_ATTRIBUTE_NAME, "name" },
{ IPNET_IP_LINK_ATTRIBUTE_MTU, "mtu" },
{ IPNET_IP_LINK_ATTRIBUTE_ADDRESS, "address" },
{ IPNET_IP_LINK_ATTRIBUTE_BROADCAST, "broadcast" },
{ IPNET_IP_LINK_ATTRIBUTE_MULTICAST, "multicast" },
{ IPNET_IP_LINK_ATTRIBUTE_ALLMULTI, "allmulticast"},
{ IPNET_IP_LINK_ATTRIBUTE_PROMISC, "promisc" },
{ IPNET_IP_LINK_ATTRIBUTE_HELP, "help" },
{ IPNET_IP_LINK_ATTRIBUTE_NOOP_ARG, "txqueuelen" },
{ IPNET_IP_LINK_ATTRIBUTE_NOOP_ARG, "netns" },
{ IPNET_IP_LINK_ATTRIBUTE_NOOP_ARG, "trailers" },
{ IPNET_IP_LINK_ATTRIBUTE_NOOP_ARG, "arp" },
{ IPNET_IP_LINK_ATTRIBUTE_NOOP_ARG, "dynamic" },
{ -1, IP_NULL },
};
static Ipcom_cmd_int_str_map ipnet_ip_link_vlan_attributes[] =
{
{ IPNET_IP_LINK_VLAN_ATTRIBUTE_ID, "id" },
{ IPNET_IP_LINK_VLAN_ATTRIBUTE_DEVNAME, "dev" },
{ IPNET_IP_LINK_VLAN_ATTRIBUTE_EQM, "egress-qos-map" },
{ IPNET_IP_LINK_VLAN_ATTRIBUTE_IQM, "ingress-qos-map"},
{ -1, IP_NULL },
};
enum
{
IPNET_IP_TUNNEL_ATTRIBUTE_DEVNAME,
IPNET_IP_TUNNEL_ATTRIBUTE_MODE,
IPNET_IP_TUNNEL_ATTRIBUTE_LOCAL,
IPNET_IP_TUNNEL_ATTRIBUTE_REMOTE,
IPNET_IP_TUNNEL_ATTRIBUTE_KEY,
IPNET_IP_TUNNEL_ATTRIBUTE_IKEY,
IPNET_IP_TUNNEL_ATTRIBUTE_OKEY,
IPNET_IP_TUNNEL_ATTRIBUTE_ISEQ,
IPNET_IP_TUNNEL_ATTRIBUTE_NISEQ,
IPNET_IP_TUNNEL_ATTRIBUTE_OSEQ,
IPNET_IP_TUNNEL_ATTRIBUTE_NOSEQ,
IPNET_IP_TUNNEL_ATTRIBUTE_SEQ,
IPNET_IP_TUNNEL_ATTRIBUTE_NSEQ,
IPNET_IP_TUNNEL_ATTRIBUTE_ICSUM,
IPNET_IP_TUNNEL_ATTRIBUTE_NICSUM,
IPNET_IP_TUNNEL_ATTRIBUTE_OCSUM,
IPNET_IP_TUNNEL_ATTRIBUTE_NOCSUM,
IPNET_IP_TUNNEL_ATTRIBUTE_CSUM,
IPNET_IP_TUNNEL_ATTRIBUTE_NCSUM,
IPNET_IP_TUNNEL_ATTRIBUTE_TTL,
IPNET_IP_TUNNEL_ATTRIBUTE_HELP
};
static Ipcom_cmd_int_str_map ipnet_ip_link_tunnel_attributes[] =
{
{ IPNET_IP_TUNNEL_ATTRIBUTE_DEVNAME, "dev" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_MODE, "mode" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_LOCAL, "local" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_REMOTE, "remote" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_IKEY, "key" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_IKEY, "ikey" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_OKEY, "okey" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_ISEQ, "iseq" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_NISEQ, "-iseq" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_OSEQ, "oseq" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_NOSEQ, "-oseq" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_SEQ, "seq" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_NSEQ, "-seq" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_ICSUM, "icsum" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_NICSUM, "-icsum" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_OCSUM, "ocsum" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_NOCSUM, "-ocsum" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_CSUM, "csum" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_NCSUM, "-csum" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_TTL, "ttl" },
{ IPNET_IP_TUNNEL_ATTRIBUTE_HELP, "help" },
{ -1, IP_NULL },
};
#ifdef IPCOM_FORWARDER_NAE
static Ipcom_cmd_int_str_map ipnet_ip_link_nae_attributes[] =
{
{ IPNET_IP_LINK_NAE_RESET, "reset" },
{ -1, IP_NULL },
};
#endif
static Ipnet_ip_link_info_map ipnet_ip_link_info_map[] =
{
{ "vlan", ipnet_ip_link_info_vlan_print, ipnet_ip_link_info_vlan_parse, ipnet_ip_link_info_vlan_help },
{ "tunnel", ipnet_ip_link_info_tunnel_print, ipnet_ip_link_info_tunnel_parse, ipnet_ip_link_info_tunnel_help },
#ifdef IPCOM_FORWARDER_NAE
{ "nae", ipnet_ip_link_info_nae_print, ipnet_ip_link_info_nae_parse, ipnet_ip_link_info_nae_help },
#endif
{ IP_NULL, IP_NULL, IP_NULL, IP_NULL }
};
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* IPLINK - NAE
****************************************************************************
*/
#if defined(IPCOM_FORWARDER_NAE)
IP_STATIC void
ipnet_ip_link_info_nae_help(Ipnet_ip_config_t *cfg)
{
ipnet_ip_stdio_printf(cfg, " nae reset"IP_LF);
ipnet_ip_stdio_printf(cfg, " reset - Reset statistics for this NAE interface"IP_LF);
}
IP_STATIC void
ipnet_ip_link_info_nae_print(Ipnet_ip_config_t *cfg, Ipnet_ip_handle_msg_t *nlmsg, struct Ip_rtattr *link_info, const char *dev)
{
(void) cfg;
(void) nlmsg;
(void) dev;
if (IP_NULL != link_info)
{
struct Ip_rtattr *vattr[IP_IFPROXY_MAX + 1];
struct Ip_rtattr *attr = IP_RTA_DATA(link_info);
Ip_size_t attrlen = IP_RTA_PAYLOAD(link_info);
ipnet_ip_parse_attr(vattr, IP_IFPROXY_MAX, attr, attrlen);
if (IP_NULL != vattr[IP_IFPROXY_IFNAME])
ipnet_ip_stdio_printf(cfg, " end %s", ipnet_ip_rta_str(vattr[IP_IFPROXY_IFNAME]));
if (IP_NULL != vattr[IP_IFPROXY_PORT_INDEX])
ipnet_ip_stdio_printf(cfg, " port %u", ipnet_ip_rta_u32(vattr[IP_IFPROXY_PORT_INDEX]));
if (IP_NULL != vattr[IP_IFPROXY_MIPC_PORT])
ipnet_ip_stdio_printf(cfg, " mipc %u", ipnet_ip_rta_u32(vattr[IP_IFPROXY_MIPC_PORT]));
if (IP_NULL != vattr[IP_IFPROXY_CORES])
{
Ip_u64 cores;
ipcom_memcpy(&cores, IP_RTA_DATA(vattr[IP_IFPROXY_CORES]), sizeof(cores));
ipnet_ip_stdio_printf(cfg, " cores ");
if (0 == cores)
ipnet_ip_stdio_printf(cfg, "none");
else
{
int i;
for (i = 0; i < sizeof(cores) * 8; i++)
{
if (IP_BIT_ISSET(cores, IP_BIT_VAL(i)))
{
IP_BIT_CLR(cores, IP_BIT_VAL(i));
ipnet_ip_stdio_printf(cfg, "%d%s", i, cores? "," : "");
}
}
}
}
if (0 != cfg->show_stats && IP_NULL != vattr[IP_IFPROXY_STATS_DRIVER])
{
struct Ip_rtnl_link_stats64 stack_stats;
struct Ip_rtnl_link_stats64 total_stats;
ipcom_memcpy(&stack_stats, IP_RTA_DATA(vattr[IP_IFPROXY_STATS_STACK]), sizeof(stack_stats));
ipcom_memcpy(&total_stats, IP_RTA_DATA(vattr[IP_IFPROXY_STATS_DRIVER]), sizeof(total_stats));
ipnet_ip_stdio_printf(cfg, cfg->oneline);
ipnet_ip_stdio_printf(cfg, " NAE RX: layer %-10s %-8s %-8s %-8s",
"bytes", "packets", "mgmt", "dropped");
ipnet_ip_stdio_printf(cfg, cfg->oneline);
ipnet_ip_stdio_printf(cfg, " stack %-10llu %-8llu %-8llu %-8llu",
(unsigned long long)stack_stats.rx_bytes, (unsigned long long)stack_stats.rx_packets, (unsigned long long)stack_stats.rx_errors, (unsigned long long)stack_stats.rx_dropped);
ipnet_ip_stdio_printf(cfg, cfg->oneline);
ipnet_ip_stdio_printf(cfg, " driver %-10llu %-8llu %-8llu %-8llu",
(unsigned long long)total_stats.rx_bytes, (unsigned long long)total_stats.rx_packets, (unsigned long long)total_stats.rx_errors, (unsigned long long)total_stats.rx_dropped);
ipnet_ip_stdio_printf(cfg, cfg->oneline);
ipnet_ip_stdio_printf(cfg, " NAE TX: layer %-10s %-8s %-8s %-8s",
"bytes", "packets", "neigh", "dropped");
ipnet_ip_stdio_printf(cfg, cfg->oneline);
ipnet_ip_stdio_printf(cfg, " stack %-10llu %-8llu %-8llu %-8llu",
(unsigned long long)stack_stats.tx_bytes, (unsigned long long)stack_stats.tx_packets, (unsigned long long)stack_stats.tx_errors, (unsigned long long)stack_stats.tx_dropped);
ipnet_ip_stdio_printf(cfg, cfg->oneline);
ipnet_ip_stdio_printf(cfg, " driver %-10llu %-8llu %-8llu %-8llu",
(unsigned long long)total_stats.tx_bytes, (unsigned long long)total_stats.tx_packets, (unsigned long long)total_stats.tx_errors, (unsigned long long)total_stats.tx_dropped);
}
}
}
IP_STATIC int
ipnet_ip_link_info_nae_parse(Ipnet_ip_config_t *cfg, struct Ip_rtattr *link_data, Ip_size_t link_data_size, char **ifla_dev)
{
char *sarg;
int arg;
Ip_u32 uarg;
if (ifla_dev != IP_NULL)
return -1;
ipnet_cmd_ip_clear_mask(cfg);
/* 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_link_nae_attributes, sarg))
return ipnet_cmd_ip_unknown_keyword(cfg, sarg);
switch (arg)
{
case IPNET_IP_LINK_NAE_RESET:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "reset", arg))
return -1;
uarg = 1;
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFPROXY_RESET, &uarg, sizeof(uarg));
break;
}
}
return 0;
}
#endif
/*
****************************************************************************
* IPLINK - VLAN
****************************************************************************
*/
IP_STATIC void
ipnet_ip_link_info_vlan_help(Ipnet_ip_config_t *cfg)
{
ipnet_ip_stdio_printf(cfg, " vlan [id <vlan_id>] [egress-qos-map <from:to>]"IP_LF);
ipnet_ip_stdio_printf(cfg, " id <vlan_id> - VLAN ID for this interface"IP_LF);
ipnet_ip_stdio_printf(cfg, " egress-qos-map <from:to> - To is VLAN priority <0-7>. From is traffic class number"IP_LF);
ipnet_ip_stdio_printf(cfg, " ingress-qos-map <from:to> - From is VLAN priority<0-7>. To is traffic class number"IP_LF);
}
IP_STATIC void
ipnet_ip_link_info_vlan_print(Ipnet_ip_config_t *cfg, Ipnet_ip_handle_msg_t *nlmsg, struct Ip_rtattr *link_info, const char *dev)
{
(void) cfg;
(void) nlmsg;
if (IP_NULL != dev)
ipnet_ip_stdio_printf(cfg, "%s:", dev);
if (IP_NULL != link_info)
{
struct Ip_rtattr *vattr[IP_IFLA_VLAN_MAX + 1];
struct Ip_rtattr *attr = IP_RTA_DATA(link_info);
Ip_size_t attrlen = IP_RTA_PAYLOAD(link_info);
ipnet_ip_parse_attr(vattr, IP_IFLA_VLAN_MAX, attr, attrlen);
if (IP_NULL != vattr[IP_IFLA_VLAN_ID])
ipnet_ip_stdio_printf(cfg, " id %u", ipnet_ip_rta_u16(vattr[IP_IFLA_VLAN_ID]));
if (IP_NULL != vattr[IP_IFLA_VLAN_EGRESS_QOS])
{
struct Ip_rtattr *rta = IP_RTA_DATA(vattr[IP_IFLA_VLAN_EGRESS_QOS]);
Ip_size_t rtalen = IP_RTA_PAYLOAD(vattr[IP_IFLA_VLAN_EGRESS_QOS]);
ipnet_ip_stdio_printf(cfg, cfg->oneline);
ipnet_ip_stdio_printf(cfg, " egress-qos-map { ");
while (IP_RTA_OK(rta, rtalen))
{
struct Ip_ifla_vlan_qos_mapping vmap;
ipcom_memcpy(&vmap, IP_RTA_DATA(rta), sizeof(vmap));
ipnet_ip_stdio_printf(cfg, "%u:%u ", vmap.from, vmap.to);
rta = IP_RTA_NEXT(rta, rtalen);
}
ipnet_ip_stdio_printf(cfg, "}");
}
if (IP_NULL != vattr[IP_IFLA_VLAN_INGRESS_QOS])
{
struct Ip_rtattr *rta = IP_RTA_DATA(vattr[IP_IFLA_VLAN_INGRESS_QOS]);
Ip_size_t rtalen = IP_RTA_PAYLOAD(vattr[IP_IFLA_VLAN_INGRESS_QOS]);
ipnet_ip_stdio_printf(cfg, cfg->oneline);
ipnet_ip_stdio_printf(cfg, " ingress-qos-map { ");
while (IP_RTA_OK(rta, rtalen))
{
struct Ip_ifla_vlan_qos_mapping vmap;
ipcom_memcpy(&vmap, IP_RTA_DATA(rta), sizeof(vmap));
ipnet_ip_stdio_printf(cfg, "%u:%u ", vmap.from, vmap.to);
rta = IP_RTA_NEXT(rta, rtalen);
}
ipnet_ip_stdio_printf(cfg, "}");
}
}
}
IP_STATIC Ip_bool
ipnet_ip_link_info_vlan_parse_qos_map(Ipnet_ip_config_t *cfg, const char *str, struct Ip_ifla_vlan_qos_mapping *vmap)
{
char *sto;
char buf[64];
Ip_u32 uarg;
ipcom_strncpy(buf, str, sizeof(buf));
buf[sizeof(buf)-1] = '\0';
if (IP_NULL == (sto = ipcom_strchr(buf, ':')))
{
ipnet_ip_stdio_printf(cfg, "QOS MAP syntax is from:to <%s>"IP_LF, str, buf);
return IP_FALSE;
}
*sto++ = '\0';
if (!ipnet_ip_str_to_uint(&uarg, buf, IP_NULL))
{
ipnet_ip_stdio_printf(cfg, "Unable to parse QOS MAP %s [%s]"IP_LF, str, buf);
return IP_FALSE;
}
vmap->from = uarg;
if (!ipnet_ip_str_to_uint(&uarg, sto, IP_NULL))
{
ipnet_ip_stdio_printf(cfg, "Unable to parse QOS MAP %s [%s]"IP_LF, str, buf);
return IP_FALSE;
}
vmap->to = uarg;
return IP_TRUE;
}
IP_STATIC int
ipnet_ip_link_info_vlan_parse(Ipnet_ip_config_t *cfg, struct Ip_rtattr *link_data, Ip_size_t link_data_size, char **ifla_dev)
{
char *sarg;
int arg;
Ip_u16 uarg16;
struct Ip_ifla_vlan_qos_mapping vmap;
char emapbuf[64];
char imapbuf[64];
struct Ip_rtattr *egress = (struct Ip_rtattr *)emapbuf;
struct Ip_rtattr *ingress = (struct Ip_rtattr *)imapbuf;
egress->rta_type = IP_IFLA_VLAN_EGRESS_QOS;
egress->rta_len = IP_RTA_LENGTH(0);
ingress->rta_type = IP_IFLA_VLAN_INGRESS_QOS;
ingress->rta_len = IP_RTA_LENGTH(0);
ipnet_cmd_ip_clear_mask(cfg);
/* 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_link_vlan_attributes, sarg))
{
if (IP_NULL != ifla_dev && IP_BIT_ISFALSE(cfg->mask, IP_BIT_UVAL64(IPNET_IP_LINK_VLAN_ATTRIBUTE_DEVNAME)))
{
(void)ipnet_cmd_ip_check_mask(cfg, IP_NULL, IPNET_IP_LINK_VLAN_ATTRIBUTE_DEVNAME);
*ifla_dev = sarg;
continue;
}
return ipnet_cmd_ip_unknown_keyword(cfg, sarg);
}
switch (arg)
{
case IPNET_IP_LINK_VLAN_ATTRIBUTE_DEVNAME:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "dev <devname>", arg))
return -1;
if (IP_NULL == ifla_dev)
return ipnet_cmd_ip_unknown_keyword(cfg, sarg);
if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "dev <devname>");
*ifla_dev = sarg;
break;
case IPNET_IP_LINK_VLAN_ATTRIBUTE_ID:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "id <vlan_id>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_ushort(&uarg16, cfg, IP_NULL))
return ipnet_cmd_ip_requires_argument(cfg, "id <vlan_id>");
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_VLAN_ID, &uarg16, sizeof(uarg16));
break;
case IPNET_IP_LINK_VLAN_ATTRIBUTE_EQM:
if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "egress-qos-map <from:to>");
if (!ipnet_ip_link_info_vlan_parse_qos_map(cfg, sarg, &vmap))
return -1;
ipcom_netlink_rta_addattr_l(egress, sizeof(emapbuf), IP_IFLA_VLAN_QOS_MAPPING, &vmap, sizeof(vmap));
break;
case IPNET_IP_LINK_VLAN_ATTRIBUTE_IQM:
if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "ingress-qos-map <from:to>");
if (!ipnet_ip_link_info_vlan_parse_qos_map(cfg, sarg, &vmap))
return -1;
ipcom_netlink_rta_addattr_l(ingress, sizeof(imapbuf), IP_IFLA_VLAN_QOS_MAPPING, &vmap, sizeof(vmap));
break;
}
}
if (egress->rta_len != IP_RTA_LENGTH(0))
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_VLAN_EGRESS_QOS, IP_RTA_DATA(egress), IP_RTA_PAYLOAD(egress));
if (ingress->rta_len != IP_RTA_LENGTH(0))
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_VLAN_INGRESS_QOS, IP_RTA_DATA(ingress),
IP_RTA_PAYLOAD(ingress));
return 0;
}
/*
****************************************************************************
* IPLINK - TUNNEL
****************************************************************************
*/
IP_STATIC void
ipnet_ip_link_info_tunnel_help(Ipnet_ip_config_t *cfg)
{
ipnet_ip_stdio_printf(cfg, " vlan [id <vlan_id>] [egress-qos-map <from:to>]"IP_LF);
ipnet_ip_stdio_printf(cfg, " id <vlan_id> - VLAN ID for this interface"IP_LF);
ipnet_ip_stdio_printf(cfg, " egress-qos-map <from:to> - To is VLAN priority <0-7>. From is traffic class number"IP_LF);
ipnet_ip_stdio_printf(cfg, " ingress-qos-map <from:to> - From is VLAN priority<0-7>. To is traffic class number"IP_LF);
}
IP_STATIC void
ipnet_ip_link_info_tunnel_print(Ipnet_ip_config_t *cfg, Ipnet_ip_handle_msg_t *nlmsg, struct Ip_rtattr *link_info, const char *dev)
{
(void) cfg;
(void) nlmsg;
char buf[128];
if (IP_NULL != dev)
ipnet_ip_stdio_printf(cfg, "%s:", dev);
if (IP_NULL != link_info)
{
struct Ip_rtattr *vattr[IP_IFLA_TUNNEL_MAX + 1];
struct Ip_rtattr *attr = IP_RTA_DATA(link_info);
Ip_size_t attrlen = IP_RTA_PAYLOAD(link_info);
Ip_u32 ival, oval;
ipnet_ip_parse_attr(vattr, IP_IFLA_TUNNEL_MAX, attr, attrlen);
ipnet_ip_stdio_printf(cfg, " mode %s", ipnet_ip_key_to_str(ipnet_ip_link_tunnel_type, (int)ipnet_ip_rta_u32(vattr[IP_IFLA_VLAN_ID]), buf, sizeof(buf)));
if (vattr[IP_IFLA_TUNNEL_IKEY] || vattr[IP_IFLA_TUNNEL_OKEY])
{
if (IP_NULL == vattr[IP_IFLA_TUNNEL_IKEY])
ipnet_ip_stdio_printf(cfg, " okey %u", ipnet_ip_rta_u32(vattr[IP_IFLA_TUNNEL_OKEY]));
else if (IP_NULL == vattr[IP_IFLA_TUNNEL_IKEY])
ipnet_ip_stdio_printf(cfg, " ikey %u", ipnet_ip_rta_u32(vattr[IP_IFLA_TUNNEL_IKEY]));
else
{
ival = ipnet_ip_rta_u32(vattr[IP_IFLA_TUNNEL_IKEY]);
oval = ipnet_ip_rta_u32(vattr[IP_IFLA_TUNNEL_OKEY]);
if (ival == oval)
ipnet_ip_stdio_printf(cfg, " key %u", ival);
else
{
ipnet_ip_stdio_printf(cfg, " okey %u", oval);
ipnet_ip_stdio_printf(cfg, " ikey %u", ival);
}
}
}
if (vattr[IP_IFLA_TUNNEL_ICSUM] && vattr[IP_IFLA_TUNNEL_OCSUM])
{
ival = ipnet_ip_rta_u32(vattr[IP_IFLA_TUNNEL_ICSUM]);
oval = ipnet_ip_rta_u32(vattr[IP_IFLA_TUNNEL_OCSUM]);
if (ival == oval)
{
ipnet_ip_stdio_printf(cfg, " %scsum", ival == 0? "-" : "");
}
else
{
ipnet_ip_stdio_printf(cfg, " %sicsum", ival == 0? "-" : "");
ipnet_ip_stdio_printf(cfg, " %socsum", oval == 0? "-" : "");
}
}
if (vattr[IP_IFLA_TUNNEL_ISEQ] && vattr[IP_IFLA_TUNNEL_OSEQ])
{
ival = ipnet_ip_rta_u32(vattr[IP_IFLA_TUNNEL_ISEQ]);
oval = ipnet_ip_rta_u32(vattr[IP_IFLA_TUNNEL_OSEQ]);
if (ival == oval)
{
ipnet_ip_stdio_printf(cfg, " %sseq", ival == 0? "-" : "");
}
else
{
ipnet_ip_stdio_printf(cfg, " %siseq", ival == 0? "-" : "");
ipnet_ip_stdio_printf(cfg, " %soseq", oval == 0? "-" : "");
}
}
if (vattr[IP_IFLA_TUNNEL_TTL])
ipnet_ip_stdio_printf(cfg, " ttl %u", ipnet_ip_rta_u32(vattr[IP_IFLA_TUNNEL_TTL]));
}
}
IP_STATIC int
ipnet_ip_link_info_tunnel_parse(Ipnet_ip_config_t *cfg, struct Ip_rtattr *link_data, Ip_size_t link_data_size, char **ifla_dev)
{
char *sarg;
int arg;
Ip_u32 uarg;
ipnet_cmd_ip_clear_mask(cfg);
/* 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_link_tunnel_attributes, sarg))
{
if (IP_NULL != ifla_dev && IP_BIT_ISFALSE(cfg->mask, IP_BIT_UVAL64(IPNET_IP_TUNNEL_ATTRIBUTE_DEVNAME)))
{
(void)ipnet_cmd_ip_check_mask(cfg, IP_NULL, IPNET_IP_TUNNEL_ATTRIBUTE_DEVNAME);
*ifla_dev = sarg;
continue;
}
return ipnet_cmd_ip_unknown_keyword(cfg, sarg);
}
switch (arg)
{
case IPNET_IP_TUNNEL_ATTRIBUTE_DEVNAME:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "dev <devname>", arg))
return -1;
if (IP_NULL == ifla_dev)
return ipnet_cmd_ip_unknown_keyword(cfg, sarg);
if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "dev <devname>");
*ifla_dev = sarg;
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_MODE:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "mode <ipip|ipv6ipv6|sit|gre|gre6|6to4>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, ipnet_ip_link_tunnel_type))
return ipnet_cmd_ip_requires_argument(cfg, "mode <ipip|ipv6ipv6|sit|gre|gre6|6to4>");
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_MODE, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_LOCAL:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "local <addr>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_prefix(IP_AF_UNSPEC, &addr, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "local <addr>");
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_LOCAL, &addr.prefix, addr.prefix_max/8);
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_REMOTE:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "remote <addr>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_prefix(IP_AF_UNSPEC, &addr, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "remote <addr>");
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_REMOTE, &addr.prefix, addr.prefix_max/8);
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_KEY:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "key <key>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL))
return ipnet_cmd_ip_requires_argument(cfg, "key <key>");
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_IKEY, &uarg, sizeof(uarg));
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_OKEY, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_IKEY:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "ikey <key>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL))
return ipnet_cmd_ip_requires_argument(cfg, "ikey <key>");
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_IKEY, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_OKEY:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "okey <key>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL))
return ipnet_cmd_ip_requires_argument(cfg, "okey <key>");
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_OKEY, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_ISEQ:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "iseq", arg))
return -1;
uarg = 1;
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_ISEQ, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_NISEQ:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "-iseq", arg))
return -1;
uarg = 0;
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_ISEQ, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_OSEQ:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "oseq", arg))
return -1;
uarg = 1;
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_OSEQ, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_NOSEQ:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "-oseq", arg))
return -1;
uarg = 0;
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_OSEQ, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_SEQ:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "seq", arg))
return -1;
uarg = 1;
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_ISEQ, &uarg, sizeof(uarg));
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_OSEQ, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_NSEQ:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "-seq", arg))
return -1;
uarg = 0;
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_ISEQ, &uarg, sizeof(uarg));
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_OSEQ, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_ICSUM:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "icsum", arg))
return -1;
uarg = 1;
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_ICSUM, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_NICSUM:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "-icsum", arg))
return -1;
uarg = 0;
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_ICSUM, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_OCSUM:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "ocsum", arg))
return -1;
uarg = 1;
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_OCSUM, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_NOCSUM:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "-ocsum", arg))
return -1;
uarg = 0;
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_OCSUM, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_CSUM:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "csum", arg))
return -1;
uarg = 1;
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_ICSUM, &uarg, sizeof(uarg));
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_OCSUM, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_NCSUM:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "-csum", arg))
return -1;
uarg = 0;
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_ICSUM, &uarg, sizeof(uarg));
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_OCSUM, &uarg, sizeof(uarg));
break;
case IPNET_IP_TUNNEL_ATTRIBUTE_TTL:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "ttl <ttl>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL))
return ipnet_cmd_ip_requires_argument(cfg, "ttl <ttl>");
ipcom_netlink_rta_addattr_l(link_data, link_data_size, IP_IFLA_TUNNEL_TTL, &uarg, sizeof(uarg));
break;
}
}
return 0;
}
/*
****************************************************************************
* IPLINK
****************************************************************************
*/
IP_STATIC int
ipnet_cmd_ip_link_usage(Ipnet_ip_config_t *cfg, int ret)
{
int i;
ipnet_ip_stdio_printf(cfg, ""IP_LF);
ipnet_ip_stdio_printf(cfg, "NAME"IP_LF);
ipnet_ip_stdio_printf(cfg, " ip link - Display and modify the IPNET link 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 link list [dev <devname>]"IP_LF);
ipnet_ip_stdio_printf(cfg, " ip link flush"IP_LF);
ipnet_ip_stdio_printf(cfg, " ip link <add|set|delete> [dev <devname>] [name <devname>]"IP_LF);
ipnet_ip_stdio_printf(cfg, " [up] [down] [multicast <on|off>] [allmulticast <on|off>]"IP_LF);
ipnet_ip_stdio_printf(cfg, " [promisc <on|off>] [mtu <mtu>] [link <devname>]"IP_LF);
ipnet_ip_stdio_printf(cfg, " [vr <vr>] [type <typename> [type-specific-parameters]]"IP_LF);
ipnet_ip_stdio_printf(cfg, " ip link help"IP_LF);
ipnet_ip_stdio_printf(cfg, " ip link 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 List all links"IP_LF);
ipnet_ip_stdio_printf(cfg, " flush Delete all deletable links"IP_LF);
ipnet_ip_stdio_printf(cfg, " add Add a link"IP_LF);
ipnet_ip_stdio_printf(cfg, " set Manipulate paramters on an existing link"IP_LF);
ipnet_ip_stdio_printf(cfg, " delete Remove a link"IP_LF);
ipnet_ip_stdio_printf(cfg, " Selector Decription:"IP_LF);
ipnet_ip_stdio_printf(cfg, " dev <devname> - The name of the device we are working on"IP_LF);
ipnet_ip_stdio_printf(cfg, " name <devname> - Optional name, for example if we are changing a device name"IP_LF);
ipnet_ip_stdio_printf(cfg, " link <devname> - Device we want to link to"IP_LF);
ipnet_ip_stdio_printf(cfg, " up - Bring the interface UP"IP_LF);
ipnet_ip_stdio_printf(cfg, " down - Bring the interface DOWN"IP_LF);
ipnet_ip_stdio_printf(cfg, " multicast <on|off> - Turn multicast on or off"IP_LF);
ipnet_ip_stdio_printf(cfg, " allmulticast <on|off> - Turn allmulticast on or off"IP_LF);
ipnet_ip_stdio_printf(cfg, " promisc <on|off> - Turn promiscous on or off"IP_LF);
ipnet_ip_stdio_printf(cfg, " mtu <mtu> - Set the interface MTU"IP_LF);
ipnet_ip_stdio_printf(cfg, " vr <vr> - The Virtual Router Identifier"IP_LF);
ipnet_ip_stdio_printf(cfg, " type <typename> - The link type name. Must be last on the command line. Everything"IP_LF);
ipnet_ip_stdio_printf(cfg, " after this parameter is considered type-specific-parameters"IP_LF);
ipnet_ip_stdio_printf(cfg, " Registered typenames and type-specific-parameters:"IP_LF);
for (i = 0; IP_NULL != ipnet_ip_link_info_map[i].kind; i++)
{
if (ipnet_ip_link_info_map[i].help_linkinfo)
(*ipnet_ip_link_info_map[i].help_linkinfo) (cfg);
}
return ret;
}
IP_STATIC Ipnet_ip_link_info_map *
ipnet_cmd_ip_module_link_info_get(const char *kind)
{
int i;
for (i = 0; IP_NULL != ipnet_ip_link_info_map[i].kind; i++)
if (ipcom_strcmp(kind, ipnet_ip_link_info_map[i].kind) == 0)
return &ipnet_ip_link_info_map[i];
return IP_NULL;
}
IP_STATIC void
ipnet_cmd_ip_module_link_filter(Ipnet_ip_config_t *cfg, Ipnet_cmd_ip_module_link_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_ifinfomsg *ifm = IP_NLMSG_DATA(nlmsg->hdr);
nnlmsg = IPCOM_LIST_NEXT(&nlmsg->next);
if (0 != ipnet_ip_parse_reply(nlmsg, IP_IFLA_MAX, sizeof(struct Ip_ifinfomsg)))
{
ipnet_ip_free_reply(nlmsg);
continue;
}
if (IP_NULL != nlmsg->rta[IP_IFLA_VR] && (cfg->vr != IPCOM_VR_ANY && cfg->vr != ipnet_ip_rta_s32(nlmsg->rta[IP_IFLA_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)))
{
switch (i)
{
case IPNET_IP_LINK_ATTRIBUTE_DEVNAME:
if (filter->ifindex != (Ip_u32) ifm->ifi_index)
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
break;
case IPNET_IP_LINK_ATTRIBUTE_TYPE:
if (IP_NULL == nlmsg->rta[IP_IFLA_LINKINFO])
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
else
{
struct Ip_rtattr *lattr[IP_IFLA_INFO_MAX + 1];
struct Ip_rtattr *attr = IP_RTA_DATA(nlmsg->rta[IP_IFLA_LINKINFO]);
Ip_size_t attrlen = IP_RTA_PAYLOAD(nlmsg->rta[IP_IFLA_LINKINFO]);
ipnet_ip_parse_attr(lattr, IP_IFLA_INFO_MAX, attr, attrlen);
if (IP_NULL == lattr[IP_IFLA_INFO_KIND])
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
if (ipcom_strcmp(ipnet_ip_rta_str(lattr[IP_IFLA_INFO_KIND]), filter->type) != 0)
{
ipnet_ip_free_reply(nlmsg);
goto next_message;
}
}
break;
}
}
}
next_message:
IP_NOOP;
}
}
IP_STATIC IP_CONST char *
ipnet_cmd_ip_module_link_print_flags(Ip_u32 flags, char *str, Ip_size_t len)
{
Ip_size_t sz = 0;
unsigned i;
str[0] = '\0';
for (i = 0; i < 32; i++)
{
if (IP_BIT_ISSET(flags, IP_BIT_UVAL(i)))
{
switch (IP_BIT_UVAL(i))
{
case IP_IFF_UP:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "UP");
break;
case IP_IFF_RUNNING:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "RUNNING");
break;
case IP_IFF_LOOPBACK:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "LOOPBACK");
break;
case IP_IFF_SIMPLEX:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "SIMPLEX");
break;
case IP_IFF_POINTOPOINT:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "POINTOPOINT");
break;
case IP_IFF_BROADCAST:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "BROADCAST");
break;
case IP_IFF_X_DHCPRUNNING:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "DHCP");
break;
case IP_IFF_NOARP:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "NOARP");
break;
case IP_IFF_PROMISC:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "PROMISC");
break;
case IP_IFF_ALLMULTI:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "ALLMULTI");
break;
case IP_IFF_LINK0:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "LINK0");
break;
case IP_IFF_LINK1:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "LINK1");
break;
case IP_IFF_LINK2:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "LINK2");
break;
case IP_IFF_DEBUG:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "DEBUG");
break;
case IP_IFF_MASTER:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "MASTER");
break;
case IP_IFF_SLAVE:
sz += (Ip_size_t)ipcom_snprintf(&str[sz], len - sz, "%s%s", sz? "," : "", "SLAVE");
break;
}
}
}
return str;
}
IP_STATIC int
ipnet_cmd_ip_module_link_print_internal(Ipnet_ip_config_t *cfg, int family, int print_link, Ipnet_ip_handle_msg_t *nlmsg, const char *link_type)
{
char buf[512];
struct Ip_ifinfomsg *ifm = IP_NLMSG_DATA(nlmsg->hdr);
if (cfg->is_silent)
return 0;
(void)ipnet_ip_parse_reply(nlmsg, IP_IFLA_MAX, sizeof(struct Ip_ifinfomsg));
if (IP_NULL != link_type)
{
if (IP_NULL != nlmsg->rta[IP_IFLA_LINKINFO])
{
struct Ip_rtattr *lattr[IP_IFLA_INFO_MAX + 1];
struct Ip_rtattr *attr = IP_RTA_DATA(nlmsg->rta[IP_IFLA_LINKINFO]);
Ip_size_t attrlen = IP_RTA_PAYLOAD(nlmsg->rta[IP_IFLA_LINKINFO]);
ipnet_ip_parse_attr(lattr, IP_IFLA_INFO_MAX, attr, attrlen);
if (IP_NULL != lattr[IP_IFLA_INFO_KIND])
{
Ipnet_ip_link_info_map *linfo = ipnet_cmd_ip_module_link_info_get(link_type);
if (IP_NULL != linfo && IP_NULL != linfo->print_linkinfo)
{
(*linfo->print_linkinfo) (cfg, nlmsg, lattr[IP_IFLA_INFO_DATA], nlmsg->rta[IP_IFLA_IFNAME]? ipnet_ip_rta_str(nlmsg->rta[IP_IFLA_IFNAME]) : "<nil>");
ipnet_ip_stdio_printf(cfg, IP_LF);
}
}
}
return 0;
}
if (nlmsg->hdr->nlmsg_type == IP_RTM_DELLINK)
ipnet_ip_stdio_printf(cfg, "Deleted ");
/* Index & Name */
ipnet_ip_stdio_printf(cfg, "%d: %s", ifm->ifi_index, nlmsg->rta[IP_IFLA_IFNAME]? ipnet_ip_rta_str(nlmsg->rta[IP_IFLA_IFNAME]) : "<nil>");
if (IP_NULL != nlmsg->rta[IP_IFLA_LINK])
{
Ip_u32 link = ipnet_ip_rta_u32(nlmsg->rta[IP_IFLA_LINK]);
ipnet_ip_stdio_printf(cfg, "@%s:", link == 0? "NONE" : ipnet_ip_if_indextoname(buf, link, ipnet_ip_rta_vr(cfg, nlmsg->rta[IP_IFLA_VR])));
}
else
ipnet_ip_stdio_printf(cfg, ":");
ipnet_ip_stdio_printf(cfg, "<%s>", ipnet_cmd_ip_module_link_print_flags(ifm->ifi_flags, buf, sizeof(buf)));
if (IP_NULL != nlmsg->rta[IP_IFLA_MTU])
ipnet_ip_stdio_printf(cfg, " mtu %d", ipnet_ip_rta_u32(nlmsg->rta[IP_IFLA_MTU]));
if (IP_NULL != nlmsg->rta[IP_IFLA_QDISC])
ipnet_ip_stdio_printf(cfg, " qdisc %s", ipnet_ip_rta_str(nlmsg->rta[IP_IFLA_QDISC]));
if (IP_NULL != nlmsg->rta[IP_IFLA_MASTER])
ipnet_ip_stdio_printf(cfg, " master %s", ipnet_ip_if_indextoname(buf, ipnet_ip_rta_u32(nlmsg->rta[IP_IFLA_MASTER]), ipnet_ip_rta_vr(cfg, nlmsg->rta[IP_IFLA_VR])));
if (IP_NULL != nlmsg->rta[IP_IFLA_TXQLEN])
ipnet_ip_stdio_printf(cfg, " qlen %d", ipnet_ip_rta_u32(nlmsg->rta[IP_IFLA_TXQLEN]));
if (IP_NULL != nlmsg->rta[IP_IFLA_VR] && cfg->vr != ipnet_ip_rta_s32(nlmsg->rta[IP_IFLA_VR]))
ipnet_ip_stdio_printf(cfg, " vr %u", ipnet_ip_rta_u32(nlmsg->rta[IP_IFLA_VR]));
/* Dump link information */
if (IP_AF_UNSPEC == family || IP_AF_PACKET == family)
{
int i;
ipnet_ip_stdio_printf(cfg, cfg->oneline);
ipnet_ip_stdio_printf(cfg, " link/%s", ipnet_ip_key_to_str(ipnet_ip_link_type, ifm->ifi_type, buf, sizeof(buf)));
for (i = 0; ipnet_ip_link_type_map[i].family != -1; i++)
if (ipnet_ip_link_type_map[i].type == ifm->ifi_type)
break;
if (IP_NULL != nlmsg->rta[IP_IFLA_ADDRESS])
ipnet_ip_stdio_printf(cfg, " %s", ipnet_ip_format_address(ipnet_ip_link_type_map[i].family,
IP_RTA_DATA(nlmsg->rta[IP_IFLA_ADDRESS]),
IP_RTA_PAYLOAD(nlmsg->rta[IP_IFLA_ADDRESS]),
buf,
sizeof(buf)));
if (IP_NULL != nlmsg->rta[IP_IFLA_BROADCAST])
ipnet_ip_stdio_printf(cfg, " %s %s",
IP_BIT_ISSET(ifm->ifi_flags, IP_IFF_POINTOPOINT)? "peer" : "brd",
ipnet_ip_format_address(ipnet_ip_link_type_map[i].family,
IP_RTA_DATA(nlmsg->rta[IP_IFLA_BROADCAST]),
IP_RTA_PAYLOAD(nlmsg->rta[IP_IFLA_BROADCAST]),
buf,
sizeof(buf)));
}
if (print_link)
{
if (0 != cfg->show_details && IP_NULL != nlmsg->rta[IP_IFLA_LINKINFO])
{
struct Ip_rtattr *lattr[IP_IFLA_INFO_MAX + 1];
struct Ip_rtattr *attr = IP_RTA_DATA(nlmsg->rta[IP_IFLA_LINKINFO]);
Ip_size_t attrlen = IP_RTA_PAYLOAD(nlmsg->rta[IP_IFLA_LINKINFO]);
ipnet_ip_parse_attr(lattr, IP_IFLA_INFO_MAX, attr, attrlen);
if (IP_NULL != lattr[IP_IFLA_INFO_KIND])
{
Ipnet_ip_link_info_map *linfo = ipnet_cmd_ip_module_link_info_get(ipnet_ip_rta_str(lattr[IP_IFLA_INFO_KIND]));
ipnet_ip_stdio_printf(cfg, cfg->oneline);
ipnet_ip_stdio_printf(cfg, " %s", ipnet_ip_rta_str(lattr[IP_IFLA_INFO_KIND]));
if (IP_NULL != linfo && IP_NULL != linfo->print_linkinfo)
(*linfo->print_linkinfo) (cfg, nlmsg, lattr[IP_IFLA_INFO_DATA], IP_NULL);
}
}
if (IP_NULL != nlmsg->rta[IP_IFLA_IFALIAS])
{
ipnet_ip_stdio_printf(cfg, cfg->oneline);
ipnet_ip_stdio_printf(cfg, " alias %s", ipnet_ip_rta_str(nlmsg->rta[IP_IFLA_IFALIAS]));
}
if (0 != cfg->show_stats && (IP_NULL != nlmsg->rta[IP_IFLA_STATS] || IP_NULL != nlmsg->rta[IP_IFLA_STATS64]))
{
struct Ip_rtnl_link_stats stats;
struct Ip_rtnl_link_stats64 stats64;
ipnet_ip_stdio_printf(cfg, cfg->oneline);
ipnet_ip_stdio_printf(cfg, " RX: %-10s %-8s %-8s %-8s %-8s %-8s",
"bytes", "packets", "errors", "dropped", "overrun", "mcast");
ipnet_ip_stdio_printf(cfg, cfg->oneline);
if (IP_NULL != nlmsg->rta[IP_IFLA_STATS64])
{
ipcom_memcpy(&stats64, IP_RTA_DATA(nlmsg->rta[IP_IFLA_STATS64]), sizeof(stats64));
ipnet_ip_stdio_printf(cfg, " %-10llu %-8llu %-8llu %-8llu %-8llu %-8llu",
(unsigned long long)stats64.rx_bytes, (unsigned long long)stats64.rx_packets, (unsigned long long)stats64.rx_errors, (unsigned long long)stats64.rx_dropped, (unsigned long long)stats64.rx_over_errors, (unsigned long long)stats64.multicast);
}
else
{
/* Fix alignment -- why do they use structures here, really? */
ipcom_memcpy(&stats, IP_RTA_DATA(nlmsg->rta[IP_IFLA_STATS]), sizeof(stats));
ipnet_ip_stdio_printf(cfg, " %-10u %-8u %-8u %-8u %-8u %-8u",
stats.rx_bytes, stats.rx_packets, stats.rx_errors, stats.rx_dropped, stats.rx_over_errors, stats.multicast);
}
ipnet_ip_stdio_printf(cfg, cfg->oneline);
ipnet_ip_stdio_printf(cfg, " TX: %-10s %-8s %-8s %-8s %-8s %-8s",
"bytes", "packets", "errors", "dropped", "carrier", "collsns");
ipnet_ip_stdio_printf(cfg, cfg->oneline);
if (IP_NULL != nlmsg->rta[IP_IFLA_STATS64])
{
ipnet_ip_stdio_printf(cfg, " %-10llu %-8llu %-8llu %-8llu %-8llu %-8llu",
(unsigned long long)stats64.tx_bytes, (unsigned long long)stats64.tx_packets, (unsigned long long)stats64.tx_errors, (unsigned long long)stats64.tx_dropped, (unsigned long long)stats64.tx_carrier_errors, (unsigned long long)stats64.collisions);
}
else
{
ipnet_ip_stdio_printf(cfg, " %-10u %-8u %-8u %-8u %-8u %-8u",
stats.tx_bytes, stats.tx_packets, stats.tx_errors, stats.tx_dropped, stats.tx_carrier_errors, stats.collisions);
}
}
}
ipnet_ip_stdio_printf(cfg, IP_LF);
return 0;
}
IP_GLOBAL int
ipnet_cmd_ip_module_link_print(Ipnet_ip_config_t *cfg, int family, int print_link, Ipnet_ip_handle_msg_t *nlmsg)
{
return ipnet_cmd_ip_module_link_print_internal(cfg, family, print_link, nlmsg, IP_NULL);
}
IP_STATIC Ip_ssize_t
ipnet_cmd_ip_module_link_list_parse(Ipnet_ip_config_t *cfg, Ipnet_cmd_ip_module_link_filter_t *filter, const char *link_type)
{
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_link_attributes, sarg))
{
if (IP_BIT_ISFALSE(cfg->mask, IP_BIT_UVAL64(IPNET_IP_LINK_ATTRIBUTE_DEVNAME)))
{
(void)ipnet_cmd_ip_check_mask(cfg, IP_NULL, IPNET_IP_LINK_ATTRIBUTE_DEVNAME);
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;
}
continue;
}
return ipnet_cmd_ip_unknown_keyword(cfg, sarg);
}
switch (arg)
{
case IPNET_IP_LINK_ATTRIBUTE_TYPE:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "type <name>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "type <name>");
ipcom_strncpy(filter->type, sarg, sizeof(filter->type));
filter->type[sizeof(filter->type)-1] = '\0';
break;
case IPNET_IP_LINK_ATTRIBUTE_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;
default:
return ipnet_cmd_ip_link_usage(cfg, -1);
}
}
if (IP_NULL != link_type)
{
(void)ipnet_cmd_ip_check_mask(cfg, IP_NULL, IPNET_IP_LINK_ATTRIBUTE_TYPE);
ipcom_strncpy(filter->type, link_type, sizeof(filter->type));
filter->type[sizeof(filter->type)-1] = '\0';
}
/* 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_link_list(Ipnet_ip_config_t *cfg, const char *link_type)
{
Ipnet_cmd_ip_module_link_filter_t filter;
Ip_ssize_t ret = ipnet_cmd_ip_module_link_list_parse(cfg, &filter, link_type);
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_GETLINK, 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_link_filter(cfg, &filter);
for (nlmsg = IPCOM_LIST_FIRST(&cfg->handle->replies); IP_NULL != nlmsg; nlmsg = IPCOM_LIST_NEXT(&nlmsg->next))
ipnet_cmd_ip_module_link_print_internal(cfg, IP_AF_UNSPEC, IP_TRUE, nlmsg, link_type);
}
return ret;
}
IP_STATIC Ip_ssize_t
ipnet_cmd_ip_module_link_flush(Ipnet_ip_config_t *cfg, const char *link_type)
{
Ipnet_cmd_ip_module_link_filter_t filter;
Ip_ssize_t ret = ipnet_cmd_ip_module_link_list_parse(cfg, &filter, link_type);
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_GETLINK, 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_link_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_NEWLINK)
continue;
nlmsg->hdr->nlmsg_type = IP_RTM_DELLINK;
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_link_print_internal(cfg, IP_AF_UNSPEC, IP_TRUE, nlmsg, link_type);
}
}
return ret;
}
IP_STATIC Ip_ssize_t
ipnet_cmd_ip_module_link_ifla_modify(Ipnet_ip_config_t *cfg, const char *ifla_type, char **ifla_dev)
{
struct Ip_rtattr *ifla = (struct Ip_rtattr *)&cfg->handle->rx[0];
struct Ip_rtattr *ifla_data = (struct Ip_rtattr *)&cfg->handle->rx[IPNET_IP_HANDLE_BUFFER/2];
Ipnet_ip_link_info_map *linfo = ipnet_cmd_ip_module_link_info_get(ifla_type);
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->tx[0];
Ip_u64 mask = cfg->mask;
ifla->rta_type = IP_IFLA_LINKINFO;
ifla->rta_len = IP_RTA_LENGTH(0);
ipcom_netlink_rta_addattr_l(ifla, IPNET_IP_HANDLE_BUFFER/2, IP_IFLA_INFO_KIND, ifla_type, ipcom_strlen(ifla_type) + 1);
if (IP_NULL != linfo && IP_NULL != linfo->parse_linkinfo)
{
Ip_ssize_t ret;
ifla_data->rta_type = IP_IFLA_INFO_DATA;
ifla_data->rta_len = IP_RTA_LENGTH(0);
if (0 > (ret = (*linfo->parse_linkinfo) (cfg, ifla_data, IPNET_IP_HANDLE_BUFFER/2, ifla_dev)))
return ret;
if (IP_RTA_LENGTH(0) != ifla_data->rta_len)
ipcom_netlink_rta_addattr_l(ifla, IPNET_IP_HANDLE_BUFFER/2, IP_IFLA_INFO_DATA, IP_RTA_DATA(ifla_data), IP_RTA_PAYLOAD(ifla_data));
}
ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_IFLA_LINKINFO, IP_RTA_DATA(ifla), IP_RTA_PAYLOAD(ifla));
ipnet_cmd_ip_set_mask(cfg, mask);
return 0;
}
IP_STATIC Ip_ssize_t
ipnet_cmd_ip_module_link_modify(Ipnet_ip_config_t *cfg, char **ifla_dev, const char *link_type)
{
char *sarg;
Ip_size_t sz;
int arg;
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->tx[0];
struct Ip_ifinfomsg *ifm;
Ip_u32 uarg;
unsigned char pbuf[64];
ipcom_memset(nlh, 0, sizeof(*nlh));
nlh->nlmsg_len = IP_NLMSG_LENGTH(0);
/* Start of the routing message */
ifm = (struct Ip_ifinfomsg *)IP_NLMSG_DATA(nlh);
ipcom_memset(ifm, 0, sizeof(*ifm));
ifm->ifi_family = IP_AF_UNSPEC;
/* Move past the routing header */
nlh->nlmsg_len = (Ip_u32) (IP_NLMSG_ALIGN(nlh->nlmsg_len) + sizeof(*ifm));
/* */
*ifla_dev = IP_NULL;
if (IP_NULL != link_type)
{
(void)ipnet_cmd_ip_check_mask(cfg, IP_NULL, IPNET_IP_LINK_ATTRIBUTE_TYPE);
return ipnet_cmd_ip_module_link_ifla_modify(cfg, link_type, ifla_dev);
}
/* 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_link_attributes, sarg))
{
if (IP_BIT_ISFALSE(cfg->mask, IP_BIT_UVAL64(IPNET_IP_LINK_ATTRIBUTE_DEVNAME)))
{
(void)ipnet_cmd_ip_check_mask(cfg, IP_NULL, IPNET_IP_LINK_ATTRIBUTE_DEVNAME);
*ifla_dev = sarg;
continue;
}
return ipnet_cmd_ip_unknown_keyword(cfg, sarg);
}
switch (arg)
{
case IPNET_IP_LINK_ATTRIBUTE_HELP:
return ipnet_cmd_ip_link_usage(cfg, 0);
case IPNET_IP_LINK_ATTRIBUTE_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>");
*ifla_dev = sarg;
break;
case IPNET_IP_LINK_ATTRIBUTE_NAME:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "name <devname>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "name <devname>");
ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_IFLA_IFNAME, sarg, ipcom_strlen(sarg) + 1);
break;
case IPNET_IP_LINK_ATTRIBUTE_LINK:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "link <devname>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "link <devname>");
/* RESOLVE SPARAM TO IFINDEX */
uarg = ipnet_ip_if_nametoindex(sarg, cfg->vr);
if (0 == arg)
{
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_IFLA_LINK, &uarg, sizeof(Ip_u32));
break;
case IPNET_IP_LINK_ATTRIBUTE_ADDRESS:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "address <address>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "address <address>");
sz = ipnet_ip_str_to_link_address(sarg, pbuf);
if (0 == sz)
{
ipnet_ip_stdio_printf(cfg, "Unable to parse \"%s\" to a valid address"IP_LF, sarg);
return -1;
}
ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_IFLA_ADDRESS, pbuf, sz);
break;
case IPNET_IP_LINK_ATTRIBUTE_BROADCAST:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "broadcast <address>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "broadcast <address>");
sz = ipnet_ip_str_to_link_address(sarg, pbuf);
if (0 == sz)
{
ipnet_ip_stdio_printf(cfg, "Unable to parse \"%s\" to a valid address"IP_LF, sarg);
return -1;
}
ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_IFLA_BROADCAST, pbuf, sz);
break;
case IPNET_IP_LINK_ATTRIBUTE_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_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_IFLA_MTU, &uarg, sizeof(Ip_u32));
break;
case IPNET_IP_LINK_ATTRIBUTE_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_IFLA_VR, &uarg, sizeof(Ip_u32));
break;
case IPNET_IP_LINK_ATTRIBUTE_UP:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "up", arg))
return -1;
ifm->ifi_change |= IP_IFF_UP;
ifm->ifi_flags |= IP_IFF_UP;
break;
case IPNET_IP_LINK_ATTRIBUTE_DOWN:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "down", arg))
return -1;
ifm->ifi_change |= (Ip_u32)IP_IFF_UP;
ifm->ifi_flags &= (Ip_u32)~IP_IFF_UP;
break;
case IPNET_IP_LINK_ATTRIBUTE_MULTICAST:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "multicast <on|off>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, ipnet_ip_onoff_values))
return ipnet_cmd_ip_requires_argument(cfg, "multicast <on|off>");
ifm->ifi_change |= (Ip_u32)IP_IFF_MULTICAST;
if (uarg)
ifm->ifi_flags |= (Ip_u32)IP_IFF_MULTICAST;
else
ifm->ifi_flags &= (Ip_u32)~IP_IFF_MULTICAST;
break;
case IPNET_IP_LINK_ATTRIBUTE_ALLMULTI:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "allmulticast <on|off>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, ipnet_ip_onoff_values))
return ipnet_cmd_ip_requires_argument(cfg, "allmulticast <on|off>");
ifm->ifi_change |= (Ip_u32)IP_IFF_ALLMULTI;
if (uarg)
ifm->ifi_flags |= (Ip_u32)IP_IFF_ALLMULTI;
else
ifm->ifi_flags &= (Ip_u32)~IP_IFF_ALLMULTI;
break;
case IPNET_IP_LINK_ATTRIBUTE_PROMISC:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "promisc <on|off>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, ipnet_ip_onoff_values))
return ipnet_cmd_ip_requires_argument(cfg, "promisc <on|off>");
ifm->ifi_change |= (Ip_u32)IP_IFF_PROMISC;
if (uarg)
ifm->ifi_flags |= (Ip_u32)IP_IFF_PROMISC;
else
ifm->ifi_flags &= (Ip_u32)~IP_IFF_PROMISC;
break;
case IPNET_IP_LINK_ATTRIBUTE_TYPE:
if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "type <typename>", arg))
return -1;
if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg))
return ipnet_cmd_ip_requires_argument(cfg, "type <typename>");
return ipnet_cmd_ip_module_link_ifla_modify(cfg, sarg, IP_NULL);
case IPNET_IP_LINK_ATTRIBUTE_NOOP_ARG:
if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg))
return ipnet_cmd_ip_requires_argument(cfg, sarg);
/* FALL THROUGH */
case IPNET_IP_LINK_ATTRIBUTE_NOOP:
/* Dont do anything */
break;
}
}
return 0;
}
IP_STATIC Ip_ssize_t
ipnet_cmd_ip_module_link_add(Ipnet_ip_config_t *cfg, Ip_u16 nlmsg_flags, const char *link_type)
{
char *ifla_dev;
Ip_ssize_t ret = ipnet_cmd_ip_module_link_modify(cfg, &ifla_dev, link_type);
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->tx[0];
if (0 <= ret)
{
nlh->nlmsg_flags = nlmsg_flags|IP_NLM_F_REQUEST|IP_NLM_F_ACK;
nlh->nlmsg_type = IP_RTM_NEWLINK;
if (IP_BIT_ISFALSE(cfg->mask, IP_BIT_UVAL64(IPNET_IP_LINK_ATTRIBUTE_TYPE)))
{
ipnet_ip_stdio_printf(cfg, "\'type <typename>\' argument is required"IP_LF);
return -1;
}
if (IP_BIT_ISFALSE(cfg->mask, IP_BIT_UVAL64(IPNET_IP_LINK_ATTRIBUTE_NAME)))
{
if (IP_NULL == ifla_dev)
{
ipnet_ip_stdio_printf(cfg, "\'dev <devname>\' or \'name <devname>\' argument is required"IP_LF);
return -1;
}
ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_IFLA_IFNAME, ifla_dev, ipcom_strlen(ifla_dev) + 1);
}
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_link_set(Ipnet_ip_config_t *cfg, const char *link_type)
{
char *ifla_dev;
Ip_ssize_t ret = ipnet_cmd_ip_module_link_modify(cfg, &ifla_dev, link_type);
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->tx[0];
struct Ip_ifinfomsg *ifm = (struct Ip_ifinfomsg *)IP_NLMSG_DATA(nlh);
if (0 <= ret)
{
nlh->nlmsg_flags = IP_NLM_F_REQUEST|IP_NLM_F_ACK;
nlh->nlmsg_type = IP_RTM_SETLINK;
if (IP_NULL == ifla_dev)
{
ipnet_ip_stdio_printf(cfg, "\'dev <devname>\' argument is required"IP_LF);
return -1;
}
ifm->ifi_index = (Ip_s32) ipnet_ip_if_nametoindex(ifla_dev, cfg->vr);
if (0 == ifm->ifi_index)
{
ipnet_ip_stdio_printf(cfg, "Cannot find device \"%s\""IP_LF, ifla_dev);
return -1;
}
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_link_del(Ipnet_ip_config_t *cfg, const char *link_type)
{
char *ifla_dev;
Ip_ssize_t ret = ipnet_cmd_ip_module_link_modify(cfg, &ifla_dev, link_type);
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->tx[0];
struct Ip_ifinfomsg *ifm = (struct Ip_ifinfomsg *)IP_NLMSG_DATA(nlh);
if (0 <= ret)
{
nlh->nlmsg_flags = IP_NLM_F_REQUEST|IP_NLM_F_ACK;
nlh->nlmsg_type = IP_RTM_DELLINK;
if (IP_NULL == ifla_dev)
{
ipnet_ip_stdio_printf(cfg, "\'dev <devname>\' argument is required"IP_LF);
return -1;
}
ifm->ifi_index = (Ip_s32)ipnet_ip_if_nametoindex(ifla_dev, cfg->vr);
if (0 == ifm->ifi_index)
{
ipnet_ip_stdio_printf(cfg, "Cannot find device \"%s\""IP_LF, ifla_dev);
return -1;
}
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_link(Ipnet_ip_config_t *cfg, const char *link_type)
{
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_link_usage(cfg, -1);
/* Resolve the module */
if (IP_FALSE == ipnet_ip_str_to_key(&arg, ipnet_ip_link_main, sparam))
return ipnet_cmd_ip_unknown_keyword(cfg, sparam);
else
{
ipnet_cmd_ip_clear_mask(cfg);
switch (arg)
{
case IPNET_IP_LINK_MAIN_HELP:
return ipnet_cmd_ip_link_usage(cfg, 0);
case IPNET_IP_LINK_MAIN_LIST:
return ipnet_cmd_ip_module_link_list(cfg, link_type);
case IPNET_IP_LINK_MAIN_FLUSH:
return ipnet_cmd_ip_module_link_flush(cfg, link_type);
case IPNET_IP_LINK_MAIN_ADD:
return ipnet_cmd_ip_module_link_add(cfg, IP_NLM_F_CREATE|IP_NLM_F_EXCL, link_type);
case IPNET_IP_LINK_MAIN_REPLACE:
return ipnet_cmd_ip_module_link_add(cfg, IP_NLM_F_CREATE|IP_NLM_F_REPLACE, link_type);
case IPNET_IP_LINK_MAIN_SET:
return ipnet_cmd_ip_module_link_set(cfg, link_type);
case IPNET_IP_LINK_MAIN_DEL:
return ipnet_cmd_ip_module_link_del(cfg, link_type);
case IPNET_IP_LINK_MAIN_MONITOR:
return ipnet_cmd_ip_module_monitor(cfg, IP_BIT_VAL(IPNET_IP_MODULE_LINK));
}
}
return 0;
}
IP_GLOBAL Ip_u32
ipnet_cmd_ip_module_link_monitor_groups(Ipnet_ip_config_t *cfg)
{
(void) cfg;
return IP_RTMGRP_LINK;
}
IP_GLOBAL Ip_bool
ipnet_cmd_ip_module_link_monitor(Ipnet_ip_config_t *cfg, Ipnet_ip_handle_msg_t *nlmsg)
{
if (nlmsg->hdr->nlmsg_type == IP_RTM_NEWLINK || nlmsg->hdr->nlmsg_type == IP_RTM_DELLINK)
{
ipnet_cmd_ip_module_link_print(cfg, IP_AF_UNSPEC, 1, nlmsg);
return IP_TRUE;
}
return IP_FALSE;
}
IP_GLOBAL Ip_ssize_t
ipnet_cmd_ip_module_link_flush_all(Ipnet_ip_config_t *cfg)
{
Ip_ssize_t ret;
Ipnet_ip_handle_msg_t *nlmsg;
/* Dump the NETLINK information */
if (0 > (ret = ipnet_ip_dump_netlink(cfg, cfg->handle, IP_RTM_GETLINK, cfg->family, cfg->core, IP_TRUE)))
{
ipnet_ip_stdio_printf(cfg, "Unable to dump routing table, error = %d"IP_LF, (int)ret);
return ret;
}
for (nlmsg = IPCOM_LIST_FIRST(&cfg->handle->replies); IP_NULL != nlmsg; nlmsg = IPCOM_LIST_NEXT(&nlmsg->next))
{
struct Ip_ifinfomsg *ifm = IP_NLMSG_DATA(nlmsg->hdr);
if (nlmsg->hdr->nlmsg_type != IP_RTM_NEWLINK)
continue;
/* DOWN */
nlmsg->hdr->nlmsg_type = IP_RTM_SETLINK;
nlmsg->hdr->nlmsg_flags = IP_NLM_F_REQUEST|IP_NLM_F_ACK;
ifm->ifi_change = IP_IFF_UP|IP_IFF_RUNNING;
ifm->ifi_flags = 0;
(void)ipnet_ip_request_netlink(cfg, cfg->handle, nlmsg->hdr, cfg->core, IP_TRUE);
/* DELETE */
nlmsg->hdr->nlmsg_type = IP_RTM_DELLINK;
(void)ipnet_ip_request_netlink(cfg, cfg->handle, nlmsg->hdr, cfg->core, IP_TRUE);
ipnet_cmd_ip_module_link_print(cfg, IP_AF_UNSPEC, IP_TRUE, nlmsg);
}
return 0;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
#endif /* IPNET_USE_NETLINK */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/