/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmcp_cmd.c,v $ $Revision: 1.16 $ * $Source: /home/interpeak/CVSRoot/ipmcp/src/ipmcp_cmd.c,v $ * $Author: jhorteli $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Kenneth Jonsson ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** * Shows statistics about multicast interfaces and multicast routes. */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmcp_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #ifdef IPMCP_USE_MLD #include #endif #include "ipmcp_mcast.h" #include "ipmcp_h.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #define IPMCP_CMD_SHOW_IF_STAT 1 #define IPMCP_CMD_SHOW_RT_STAT 2 #define IPMCP_CMD_SHOW_JG_STAT 3 /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ IP_PUBLIC int ipmcp_cmd(int argc, char **argv); /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipmcp_cmd_link_state_to_str *=========================================================================== * Description: Returns a string representation of the link state. * Parameters: * Returns: * */ IP_STATIC IP_CONST char * ipmcp_cmd_link_state_to_str(int state) { switch (state) { case IPMCP_LINK_STATE_INACTIVE: return "INACTIVE"; case IPMCP_LINK_STATE_NON_QUERIER: return "NON-QUERIER"; case IPMCP_LINK_STATE_QUERIER: return "QUERIER"; default: IP_PANIC(); return "unknown state"; } } /* *=========================================================================== * ipmcp_cmd_show_maddr_source_addr_cb *=========================================================================== * Description: Prints one multicast source address. * Parameters: * Returns: * */ IP_STATIC void ipmcp_cmd_show_maddr_source_addr_cb(Ipmcp_saddr_t *saddr, const char *prefix) { char addrstr[IPMCP_ADDRSTRLEN]; ipcom_printf("%s%-20s %u" IP_LF, prefix, ipcom_inet_ntop(saddr->maddr->domain, saddr->ops->get_addr(saddr), addrstr, sizeof(addrstr)), ipcom_tmo2_get(&saddr->timer) / 1000); } /* *=========================================================================== * ipmcp_cmd_show_joined_groups_cb *=========================================================================== * Description: Prints one joined multicast group. * Parameters: * Returns: * */ IP_STATIC void ipmcp_cmd_show_joined_groups_cb(Ipmcp_maddr_t *maddr, void *unused) { char addrstr[IPMCP_ADDRSTRLEN]; char *set_indent = "\t\t"; (void) unused; ipcom_printf("\t%s%-19s %s %u" IP_LF, maddr->domain == IP_AF_INET6 ? " " : "", ipcom_inet_ntop(maddr->domain, maddr->ops->get_addr(maddr), addrstr, sizeof(addrstr)), maddr->mode_is_include ? "INCLUDE" : "EXCLUDE", ipcom_tmo2_get(&maddr->group_timer) / 1000); ipcom_printf("%sInclude set:" IP_LF, set_indent); ipcom_hash_for_each(maddr->include_set, (Ipcom_hash_foreach_cb_func) ipmcp_cmd_show_maddr_source_addr_cb, set_indent); ipcom_printf("%sExclude set:" IP_LF, set_indent); ipcom_hash_for_each(maddr->exclude_set, (Ipcom_hash_foreach_cb_func) ipmcp_cmd_show_maddr_source_addr_cb, set_indent); } #ifdef IPMCP_USE_IGMP /* *=========================================================================== * ipmcp_cmd_show_inet_ifs *=========================================================================== * Description: Shows all the IPv4 multicast intefaces. * Parameters: * Returns: * */ IP_STATIC void ipmcp_cmd_show_inet_ifs(void) { struct Ip_sioc_vif_req vif_req; char ifname[IP_IFNAMSIZ]; Ipmcp_netif_t *netif; vif_req.vifi = ipmcp.upstream_if.igmp.vif_index; if (ipcom_socketioctl(ipmcp.igmp.fd, IP_SIOCGETVIFCNT, &vif_req) < 0) { ipcom_printf("ioctl IP_SIOCGETVIFCNT failed for upstream interface: %s" IP_LF, ipcom_strerror(ipcom_errno)); return; } ipcom_printf("Upstream interface IPv4 statistics"IP_LF); ipcom_printf("\t%-16s%-10s%-10s"IP_LF, "Name", "Pkts", "Bytes"); ipcom_printf("\t%-16s%-10d%-10d"IP_LF, ipcom_if_indextoname(ipmcp.upstream_if.ifindex, ifname), vif_req.icount, vif_req.ibytes); ipcom_printf("Downstream interface IPv4 statistics"IP_LF); ipcom_printf("\t%-16s%-10s%-10s%s"IP_LF, "Name", "Pkts", "Bytes", "State"); for (netif = IPCOM_LIST_FIRST(&ipmcp.downstream_ifs_head); netif; netif = IPCOM_LIST_NEXT(&netif->list)) { vif_req.vifi = netif->igmp.vif_index; if (ipcom_socketioctl(ipmcp.igmp.fd, IP_SIOCGETVIFCNT, &vif_req) < 0) { ipcom_printf("ioctl IP_SIOCGETVIFCNT failed for upstream interface: %s" IP_LF, ipcom_strerror(ipcom_errno)); return; } ipcom_printf("\t%-16s%-10d%-10d%s"IP_LF, netif->ifname, vif_req.ocount, vif_req.obytes, ipmcp_cmd_link_state_to_str(netif->igmp.state)); } } /* *=========================================================================== * ipmcp_cmd_show_inet_route_cb *=========================================================================== * Description: Prints all routes to one IPv4 group. * Parameters: * Returns: * */ IP_STATIC void ipmcp_cmd_show_inet_route_cb(Ipmcp_igmp_upstream_maddr_t *maddr, void *unused) { char dst[IP_INET_ADDRSTRLEN]; char src[IP_INET_ADDRSTRLEN]; int i; struct Ip_sioc_sg_req sg; Ipmcp_netif_t *netif; (void) unused; if (&maddr->saddrs[0].s_addr == 0) return; ipmcp.log_buf[0] = '\0'; for (netif = IPCOM_LIST_FIRST(&ipmcp.downstream_ifs_head); netif; netif = IPCOM_LIST_NEXT(&netif->list)) { if (ipcom_hash_get(netif->igmp.maddr_head, &maddr->maddr)) { if (ipmcp.log_buf[0] != '\0') ipcom_strcat(ipmcp.log_buf, ", "); ipcom_strcat(ipmcp.log_buf, netif->ifname); } } for (i = 0; i < IPMCP_IGMP_MAX_SRC_ADDRS; i++) { if (maddr->saddrs[i].s_addr == IP_INADDR_ANY) continue; sg.src = maddr->saddrs[i]; sg.grp = maddr->maddr; if (ipcom_socketioctl(ipmcp.igmp.fd, IP_SIOCGETSGCNT, &sg) < 0) { ipcom_printf("ioctl IP_SIOCGETSGCNT: %s" IP_LF, ipcom_strerror(ipcom_errno)); return; } ipcom_printf("\t%-20s%-20s%-8d%-8d%s"IP_LF, ipcom_inet_ntop(IP_AF_INET, &maddr->maddr, dst, sizeof(dst)), ipcom_inet_ntop(IP_AF_INET, &maddr->saddrs[i], src, sizeof(src)), sg.pktcnt, sg.bytecnt, ipmcp.log_buf); } } /* *=========================================================================== * ipmcp_cmd_show_inet_routes *=========================================================================== * Description: Shows all the IPv4 multicast routes. * Parameters: * Returns: * */ IP_STATIC void ipmcp_cmd_show_inet_routes(void) { if (ipmcp.upstream_if.igmp.maddr_head) { ipcom_printf("IPv4 routes"IP_LF); ipcom_printf("\t%-20s%-20s%-8s%-8s%s" IP_LF, "Group", "Source", "Pkt", "Bytes", "Dwnstr ifs"); ipcom_hash_for_each(ipmcp.upstream_if.igmp.maddr_head, (Ipcom_hash_foreach_cb_func) ipmcp_cmd_show_inet_route_cb, IP_NULL); } } /* *=========================================================================== * ipmcp_cmd_show_inet_joined_groups *=========================================================================== * Description: Shows all the groups that joined by clients * Parameters: * Returns: * */ IP_STATIC void ipmcp_cmd_show_inet_joined_groups(void) { Ipmcp_netif_t *netif; for (netif = IPCOM_LIST_FIRST(&ipmcp.downstream_ifs_head); netif; netif = IPCOM_LIST_NEXT(&netif->list)) { ipcom_printf("IPv4 groups joined at %s"IP_LF, netif->ifname); if (netif->igmp.maddr_head == IP_NULL || netif->igmp.maddr_head->elem == 0) ipcom_printf("\tNone"IP_LF); else { ipcom_printf("\t%-20s%-8s%s" IP_LF, "Group", "State", "Timer"); ipcom_hash_for_each(netif->igmp.maddr_head, (Ipcom_hash_foreach_cb_func) ipmcp_cmd_show_joined_groups_cb, IP_NULL); } } } #endif /* IPMCP_USE_IGMP */ #ifdef IPMCP_USE_MLD /* *=========================================================================== * ipmcp_cmd_show_inet6_ifs *=========================================================================== * Description: Shows all the IPv6 multicast intefaces. * Parameters: * Returns: * */ IP_STATIC void ipmcp_cmd_show_inet6_ifs(void) { struct Ip_sioc_mif_req6 mif_req; char ifname[IP_IFNAMSIZ]; Ipmcp_netif_t *netif; mif_req.mifi = ipmcp.upstream_if.mld.mif_index; if (ipcom_socketioctl(ipmcp.mld.mrt_fd, IP_SIOCGETMIFCNT_IN6, &mif_req) < 0) { ipcom_printf("ioctl IP_SIOCGETVIFCNT failed for upstream interface: %s" IP_LF, ipcom_strerror(ipcom_errno)); return; } ipcom_printf("Upstream interface IPv6 statistics"IP_LF); ipcom_printf("\t%-16s%-10s%-10s"IP_LF, "Name", "Pkts", "Bytes"); ipcom_printf("\t%-16s%-10d%-10d"IP_LF, ipcom_if_indextoname(ipmcp.upstream_if.ifindex, ifname), IP_U64_GETLO(mif_req.icount), IP_U64_GETLO(mif_req.ibytes)); ipcom_printf("Downstream interface IPv6 statistics"IP_LF); ipcom_printf("\t%-16s%-10s%-10s%s"IP_LF, "Name", "Pkts", "Bytes", "State"); for (netif = IPCOM_LIST_FIRST(&ipmcp.downstream_ifs_head); netif; netif = IPCOM_LIST_NEXT(&netif->list)) { mif_req.mifi = netif->mld.mif_index; if (ipcom_socketioctl(ipmcp.mld.mrt_fd, IP_SIOCGETMIFCNT_IN6, &mif_req) < 0) { ipcom_printf("ioctl IP_SIOCGETVIFCNT failed for upstream interface: %s" IP_LF, ipcom_strerror(ipcom_errno)); return; } ipcom_printf("\t%-16s%-10d%-10d%s"IP_LF, netif->ifname, IP_U64_GETLO(mif_req.ocount), IP_U64_GETLO(mif_req.obytes), ipmcp_cmd_link_state_to_str(netif->mld.state)); } } /* *=========================================================================== * ipmcp_cmd_show_inet6_route_cb *=========================================================================== * Description: Prints all routes to one IPv6 group. * Parameters: * Returns: * */ IP_STATIC void ipmcp_cmd_show_inet6_route_cb(Ipmcp_mld_upstream_maddr_t *maddr, void *unused) { char dst[IP_INET6_ADDRSTRLEN]; char src[IP_INET6_ADDRSTRLEN]; int i; struct Ip_sioc_sg_req6 sg; Ipmcp_netif_t *netif; (void) unused; if (IP_IN6_IS_ADDR_UNSPECIFIED(&maddr->saddrs[0])) return; ipcom_memset(&sg, 0, sizeof(sg)); sg.src.sin6_family = IP_AF_INET6; IPCOM_SA_LEN_SET(&sg.src, sizeof(sg.src)); sg.grp.sin6_family = IP_AF_INET6; IPCOM_SA_LEN_SET(&sg.grp, sizeof(sg.grp)); ipmcp.log_buf[0] = '\0'; for (netif = IPCOM_LIST_FIRST(&ipmcp.downstream_ifs_head); netif; netif = IPCOM_LIST_NEXT(&netif->list)) { if (ipcom_hash_get(netif->mld.maddr_head, &maddr->maddr)) { if (ipmcp.log_buf[0] != '\0') ipcom_strcat(ipmcp.log_buf, ", "); ipcom_strcat(ipmcp.log_buf, netif->ifname); } } for (i = 0; i < IPMCP_MLD_MAX_SRC_ADDRS; i++) { if (IP_IN6_IS_ADDR_UNSPECIFIED(&maddr->saddrs[i])) continue; sg.src.sin6_addr = maddr->saddrs[i]; sg.grp.sin6_addr = maddr->maddr; if (ipcom_socketioctl(ipmcp.mld.mrt_fd, IP_SIOCGETSGCNT_IN6, &sg) < 0) { ipcom_printf("ioctl IP_SIOCGETSGCNT_IN6: %s" IP_LF, ipcom_strerror(ipcom_errno)); return; } ipcom_printf("\t%-30s%-30s%-8d%-8d%s"IP_LF, ipcom_inet_ntop(IP_AF_INET6, &maddr->maddr, dst, sizeof(dst)), ipcom_inet_ntop(IP_AF_INET6, &maddr->saddrs[i], src, sizeof(src)), IP_U64_GETLO(sg.pktcnt), IP_U64_GETLO(sg.bytecnt), ipmcp.log_buf); } } /* *=========================================================================== * ipmcp_cmd_show_inet6_routes *=========================================================================== * Description: Shows all the IPv6 multicast routes. * Parameters: * Returns: * */ IP_STATIC void ipmcp_cmd_show_inet6_routes(void) { if (ipmcp.upstream_if.mld.maddr_head) { ipcom_printf("IPv6 routes"IP_LF); ipcom_printf("\t%-30s%-30s%-8s%-8s%s" IP_LF, "Group", "Source", "Pkt", "Bytes", "Dwnstr ifs"); ipcom_hash_for_each(ipmcp.upstream_if.mld.maddr_head, (Ipcom_hash_foreach_cb_func) ipmcp_cmd_show_inet6_route_cb, IP_NULL); } } /* *=========================================================================== * ipmcp_cmd_show_inet6_joined_groups *=========================================================================== * Description: Shows all the groups that joined by clients * Parameters: * Returns: * */ IP_STATIC void ipmcp_cmd_show_inet6_joined_groups(void) { Ipmcp_netif_t *netif; for (netif = IPCOM_LIST_FIRST(&ipmcp.downstream_ifs_head); netif; netif = IPCOM_LIST_NEXT(&netif->list)) { ipcom_printf("IPv6 groups joined at %s"IP_LF, netif->ifname); if (netif->mld.maddr_head->elem == 0) ipcom_printf("\tNone"IP_LF); else { ipcom_printf("\t%-30s%s" IP_LF, "Group", "State"); ipcom_hash_for_each(netif->mld.maddr_head, (Ipcom_hash_foreach_cb_func) ipmcp_cmd_show_joined_groups_cb, IP_NULL); } } } #endif /* IPMCP_USE_MLD */ /* *=========================================================================== * ipmcp_cmd_show_usage *=========================================================================== * Description: Shows the usage of the multicast proxy shell command. * Parameters: * Returns: * */ IP_STATIC void ipmcp_cmd_show_usage(void) { ipcom_printf("Interpeak multicast proxy statistics"IP_LF "usage: "IP_LF " mcastproxy [-4|-6] <-i|-j|-r>"IP_LF " -4 show IPv4 only (default both)"IP_LF " -6 show IPv6 only (default both)"IP_LF " -i show interface statistics"IP_LF " -j show groups joined by clients"IP_LF " -r show route statistics"IP_LF IP_LF ); } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipmcp_cmd *=========================================================================== * Description: Shell command that shows statistics * Parameters: * Returns: * */ IP_PUBLIC int ipmcp_cmd(int argc, char **argv) { Ipcom_getopt opt; int domain = 0; int cmd = IPMCP_CMD_SHOW_IF_STAT; int c; if (argc < 2) { ipmcp_cmd_show_usage(); return 0; } ipcom_getopt_clear_r(&opt); while ((c = ipcom_getopt_r(argc, argv, "46ijr", &opt)) != -1) { switch(c) { case '4': domain = IP_AF_INET; break; case '6': domain = IP_AF_INET6; break; case 'i': break; case 'j': cmd = IPMCP_CMD_SHOW_JG_STAT; break; case 'r': cmd = IPMCP_CMD_SHOW_RT_STAT; break; default: ipcom_printf("sockperf: unknown option %c"IP_LF, (char)c); return -1; } } (void)ipcom_mutex_lock(ipmcp.daemon_mutex); if (ipcom_ipd_send(IPMCP_IPD_NAME, IPMCP_IPD_EVENT_WAIT_FOR_SHELL_CMD) != IPCOM_SUCCESS) { (void)ipcom_mutex_unlock(ipmcp.daemon_mutex); ipcom_printf("The IPMCP daemon is not running"IP_LF); return -1; } (void)ipcom_sem_wait(ipmcp.cmd_sem); switch (cmd) { case IPMCP_CMD_SHOW_IF_STAT: #ifdef IPMCP_USE_IGMP if (domain == 0 || domain == IP_AF_INET) ipmcp_cmd_show_inet_ifs(); #endif #ifdef IPMCP_USE_MLD if (domain == 0 || domain == IP_AF_INET6) ipmcp_cmd_show_inet6_ifs(); #endif break; case IPMCP_CMD_SHOW_RT_STAT: #ifdef IPMCP_USE_IGMP if (domain == 0 || domain == IP_AF_INET) ipmcp_cmd_show_inet_routes(); #endif #ifdef IPMCP_USE_MLD if (domain == 0 || domain == IP_AF_INET6) ipmcp_cmd_show_inet6_routes(); #endif break; case IPMCP_CMD_SHOW_JG_STAT: #ifdef IPMCP_USE_IGMP if (domain == 0 || domain == IP_AF_INET) ipmcp_cmd_show_inet_joined_groups(); #endif #ifdef IPMCP_USE_MLD if (domain == 0 || domain == IP_AF_INET6) ipmcp_cmd_show_inet6_joined_groups(); #endif break; default: break; } (void)ipcom_mutex_unlock(ipmcp.daemon_mutex); return 0; } /* **************************************************************************** * END OF FILE **************************************************************************** */