/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 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_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 ] [egress-qos-map ]"IP_LF); ipnet_ip_stdio_printf(cfg, " id - VLAN ID for this interface"IP_LF); ipnet_ip_stdio_printf(cfg, " egress-qos-map - To is VLAN priority <0-7>. From is traffic class number"IP_LF); ipnet_ip_stdio_printf(cfg, " ingress-qos-map - 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 ", 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 "); *ifla_dev = sarg; break; case IPNET_IP_LINK_VLAN_ATTRIBUTE_ID: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "id ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_ushort(&uarg16, cfg, IP_NULL)) return ipnet_cmd_ip_requires_argument(cfg, "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 "); 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 "); 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 ] [egress-qos-map ]"IP_LF); ipnet_ip_stdio_printf(cfg, " id - VLAN ID for this interface"IP_LF); ipnet_ip_stdio_printf(cfg, " egress-qos-map - To is VLAN priority <0-7>. From is traffic class number"IP_LF); ipnet_ip_stdio_printf(cfg, " ingress-qos-map - 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 ", 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 "); *ifla_dev = sarg; break; case IPNET_IP_TUNNEL_ATTRIBUTE_MODE: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "mode ", 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 "); 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_prefix(IP_AF_UNSPEC, &addr, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "local "); 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_prefix(IP_AF_UNSPEC, &addr, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "remote "); 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL)) return ipnet_cmd_ip_requires_argument(cfg, "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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL)) return ipnet_cmd_ip_requires_argument(cfg, "ikey "); 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL)) return ipnet_cmd_ip_requires_argument(cfg, "okey "); 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL)) return ipnet_cmd_ip_requires_argument(cfg, "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 ]"IP_LF); ipnet_ip_stdio_printf(cfg, " ip link flush"IP_LF); ipnet_ip_stdio_printf(cfg, " ip link [dev ] [name ]"IP_LF); ipnet_ip_stdio_printf(cfg, " [up] [down] [multicast ] [allmulticast ]"IP_LF); ipnet_ip_stdio_printf(cfg, " [promisc ] [mtu ] [link ]"IP_LF); ipnet_ip_stdio_printf(cfg, " [vr ] [type [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 - The name of the device we are working on"IP_LF); ipnet_ip_stdio_printf(cfg, " name - Optional name, for example if we are changing a device name"IP_LF); ipnet_ip_stdio_printf(cfg, " link - 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 - Turn multicast on or off"IP_LF); ipnet_ip_stdio_printf(cfg, " allmulticast - Turn allmulticast on or off"IP_LF); ipnet_ip_stdio_printf(cfg, " promisc - Turn promiscous on or off"IP_LF); ipnet_ip_stdio_printf(cfg, " mtu - Set the interface MTU"IP_LF); ipnet_ip_stdio_printf(cfg, " vr - The Virtual Router Identifier"IP_LF); ipnet_ip_stdio_printf(cfg, " type - 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]) : ""); 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]) : ""); 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "type "); 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 ", 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; 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "dev "); *ifla_dev = sarg; break; case IPNET_IP_LINK_ATTRIBUTE_NAME: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "name ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "name "); 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "link "); /* 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
", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "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
", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "broadcast
"); 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 ", 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_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 ", 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_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 ", 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 "); 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 ", 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 "); 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 ", 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 "); 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 ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "type "); 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 \' 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 \' or \'name \' 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 \' 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 \' 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 **************************************************************************** */