diff --git a/src/ptp/ptpd2/datatypes.h b/src/ptp/ptpd2/datatypes.h index 743ffd77..eb58cf0e 100644 --- a/src/ptp/ptpd2/datatypes.h +++ b/src/ptp/ptpd2/datatypes.h @@ -656,6 +656,10 @@ struct ptpd_transport { const struct sfptpd_ptp_bond_info *bond_info; int bondSocks[SFPTP_BOND_BYPASS_SOCK_COUNT]; + /* This keeps track of how many sockets we tried creating, and is only + * used for diagnostics. See `bondSocksValidMask` for checking which + * entires in `bondSocks` are usable. */ + int bondSocksCreatedCount; /* A mask of the above array for those sockets which are valid. Here, * valid means that we were able to create and set all of the socket * options that we wanted. */ diff --git a/src/ptp/ptpd2/sfptpd_lacp.c b/src/ptp/ptpd2/sfptpd_lacp.c index 6d20993e..44c5b375 100644 --- a/src/ptp/ptpd2/sfptpd_lacp.c +++ b/src/ptp/ptpd2/sfptpd_lacp.c @@ -105,6 +105,10 @@ void createBondSocks(struct ptpd_transport *transport, int transportAF) transport->bondSocks[i] = sockfd; transport->bondSocksValidMask |= (1 << i); } + + /* We want to include even those that might have failed for the sake of + * being able to log which sockets have been invalidated. */ + transport->bondSocksCreatedCount = sockCount; } void destroyBondSocks(struct ptpd_transport *transport) @@ -253,3 +257,85 @@ void copyTimestampingToBondSocks(struct ptpd_transport *transport, setBondSockopt(transport, SOL_SOCKET, tsSetupMethod->sockopt, &flags, sizeof(flags)); } + +#define BOND_SOCK_INVALID_REASON_STRLEN 39 +void getBondSockInvalidReason(struct ptpd_transport *transport, int idx, + char *reason) +{ + union bond_sock_invalid_description *invalid_desc = + &transport->bondSocksInvalidDescriptions[idx]; + + switch (invalid_desc->anonymous.reason) { + case BOND_SOCK_INVALID_REASON_SOCKET: + snprintf(reason, BOND_SOCK_INVALID_REASON_STRLEN, + "INVALID: socket = %d", + invalid_desc->socket.rc); + break; + case BOND_SOCK_INVALID_REASON_BIND: + snprintf(reason, BOND_SOCK_INVALID_REASON_STRLEN, + "INVALID: bind = %d", + invalid_desc->bind.rc); + break; + case BOND_SOCK_INVALID_REASON_SETSOCKOPT: + snprintf(reason, BOND_SOCK_INVALID_REASON_STRLEN, + "INVALID: setsockopt(%d, %d) = %d", + invalid_desc->setsockopt.level, + invalid_desc->setsockopt.sockopt, + invalid_desc->setsockopt.rc); + break; + case BOND_SOCK_INVALID_REASON_ADD_TO_EPOLL_SET: + snprintf(reason, BOND_SOCK_INVALID_REASON_STRLEN, + "INVALID: add_to_epoll = %d", + invalid_desc->add_to_epoll_set.rc); + break; + case BOND_SOCK_INVALID_REASON_SHUTDOWN: + snprintf(reason, BOND_SOCK_INVALID_REASON_STRLEN, + "INVALID: shutdown"); + break; + default: + snprintf(reason, BOND_SOCK_INVALID_REASON_STRLEN, + "INVALID: unknown reason"); + break; + } +} + +void bondSocksDumpState(struct ptpd_intf_context *intf, int sev) +{ + const char *header[] = { "#", "fd", "port", "mcast ifindex" }; + const char *formatHeader = "| %-2s | %-10s | %-10s | %-13s |\n"; + const char *formatRecordValid = "| %-2d | %-10d | %-10d | %-13d |\n"; + const char *formatRecordInvalid = + "| %-2d | %-" STRINGIFY(BOND_SOCK_INVALID_REASON_STRLEN) "s |\n"; + const char *separator = + "|----+------------+------------+---------------|\n"; + char invalidReason[BOND_SOCK_INVALID_REASON_STRLEN]; + struct ptpd_transport *transport = &intf->transport; + int i; + + if (transport->bondSocksCreatedCount <= 0) + return; + + TRACE_LX(sev, "LACP bypass sockets state for interface %s:\n", + transport->bond_info->bond_if); + TRACE_LX(sev, formatHeader, header[0], header[1], header[2], header[3]); + TRACE_LX(sev, separator); + for (i = 0; i < transport->bondSocksCreatedCount; i++) { + if (transport->bondSocksValidMask & (1 << i)) { + int fd = transport->bondSocks[i]; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + int getsockname_rc; + struct socket_ifindex *mapping; + + getsockname_rc = getsockname(fd, &addr, &addrlen); + mapping = bondSockFindMulticastMappingByFd(transport, fd); + + TRACE_LX(sev, formatRecordValid, i, fd, + (getsockname_rc == 0) ? ntohs(addr.sin_port) : 0, + (mapping) ? mapping->ifindex : 0); + } else { + getBondSockInvalidReason(transport, i, invalidReason); + TRACE_LX(sev, formatRecordInvalid, i, invalidReason); + } + } +} diff --git a/src/ptp/ptpd2/sfptpd_lacp.h b/src/ptp/ptpd2/sfptpd_lacp.h index 91407a9d..d3e409b8 100644 --- a/src/ptp/ptpd2/sfptpd_lacp.h +++ b/src/ptp/ptpd2/sfptpd_lacp.h @@ -93,4 +93,6 @@ void copyMulticastTTLToBondSocks(struct ptpd_transport *transport); void copyTimestampingToBondSocks(struct ptpd_transport *transport, TsSetupMethod *tsMethodVerbose); +void bondSocksDumpState(struct ptpd_intf_context *intf, int sev); + #endif /* _SFPTPD_LACP_H */ diff --git a/src/ptp/sfptpd_ptp_module.c b/src/ptp/sfptpd_ptp_module.c index 73b9df04..c3e9e29a 100644 --- a/src/ptp/sfptpd_ptp_module.c +++ b/src/ptp/sfptpd_ptp_module.c @@ -3986,8 +3986,10 @@ static void on_dump_tables(struct sfptpd_ptp_module *ptp, { struct sfptpd_ptp_intf *interface; - for (interface = ptp->intf_list; interface; interface = interface->next) + for (interface = ptp->intf_list; interface; interface = interface->next) { ptpd_process_intf_stats(interface->ptpd_intf_private, true); + bondSocksDumpState(interface->ptpd_intf_private, 0); + } SFPTPD_MSG_FREE(msg); }