Merge pull request #10399 from g-balaji1/pimv6-sock

pim6d: PIMv6 socket related changes
This commit is contained in:
Donald Sharp 2022-03-13 10:03:45 -04:00 committed by GitHub
commit 6ea4244514
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 239 additions and 321 deletions

View File

@ -455,8 +455,7 @@ static void pim_show_membership(struct pim_instance *pim, struct vty *vty,
json_object_free(json); json_object_free(json);
} }
static void pim_print_ifp_flags(struct vty *vty, struct interface *ifp, static void pim_print_ifp_flags(struct vty *vty, struct interface *ifp)
int mloop)
{ {
vty_out(vty, "Flags\n"); vty_out(vty, "Flags\n");
vty_out(vty, "-----\n"); vty_out(vty, "-----\n");
@ -469,7 +468,6 @@ static void pim_print_ifp_flags(struct vty *vty, struct interface *ifp,
vty_out(vty, "Interface Index : %d\n", ifp->ifindex); vty_out(vty, "Interface Index : %d\n", ifp->ifindex);
vty_out(vty, "Multicast : %s\n", vty_out(vty, "Multicast : %s\n",
if_is_multicast(ifp) ? "yes" : "no"); if_is_multicast(ifp) ? "yes" : "no");
vty_out(vty, "Multicast Loop : %d\n", mloop);
vty_out(vty, "Promiscuous : %s\n", vty_out(vty, "Promiscuous : %s\n",
(ifp->flags & IFF_PROMISC) ? "yes" : "no"); (ifp->flags & IFF_PROMISC) ? "yes" : "no");
vty_out(vty, "\n"); vty_out(vty, "\n");
@ -576,7 +574,6 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
char other_hhmmss[10]; char other_hhmmss[10];
int found_ifname = 0; int found_ifname = 0;
int sqi; int sqi;
int mloop = 0;
long gmi_msec; /* Group Membership Interval */ long gmi_msec; /* Group Membership Interval */
long lmqt_msec; long lmqt_msec;
long ohpi_msec; long ohpi_msec;
@ -639,11 +636,6 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
qri_msec = qri_msec =
pim_ifp->gm_query_max_response_time_dsec * 100; pim_ifp->gm_query_max_response_time_dsec * 100;
if (pim_ifp->pim_sock_fd >= 0)
mloop = pim_socket_mcastloop_get(
pim_ifp->pim_sock_fd);
else
mloop = 0;
lmqc = pim_ifp->gm_last_member_query_count; lmqc = pim_ifp->gm_last_member_query_count;
if (uj) { if (uj) {
@ -776,7 +768,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
vty_out(vty, "\n"); vty_out(vty, "\n");
vty_out(vty, "\n"); vty_out(vty, "\n");
pim_print_ifp_flags(vty, ifp, mloop); pim_print_ifp_flags(vty, ifp);
} }
} }
} }
@ -903,7 +895,6 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
char src_str[INET_ADDRSTRLEN]; char src_str[INET_ADDRSTRLEN];
char stat_uptime[10]; char stat_uptime[10];
char uptime[10]; char uptime[10];
int mloop = 0;
int found_ifname = 0; int found_ifname = 0;
int print_header; int print_header;
json_object *json = NULL; json_object *json = NULL;
@ -945,10 +936,6 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
pim_ifp->pim_hello_period); pim_ifp->pim_hello_period);
pim_time_uptime(stat_uptime, sizeof(stat_uptime), pim_time_uptime(stat_uptime, sizeof(stat_uptime),
now - pim_ifp->pim_ifstat_start); now - pim_ifp->pim_ifstat_start);
if (pim_ifp->pim_sock_fd >= 0)
mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd);
else
mloop = 0;
if (uj) { if (uj) {
char pbuf[PREFIX2STR_BUFFER]; char pbuf[PREFIX2STR_BUFFER];
@ -1096,8 +1083,6 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
pim_ifp->pim_ifstat_hello_sendfail); pim_ifp->pim_ifstat_hello_sendfail);
json_object_int_add(json_row, "helloGenerationId", json_object_int_add(json_row, "helloGenerationId",
pim_ifp->pim_generation_id); pim_ifp->pim_generation_id);
json_object_int_add(json_row, "flagMulticastLoop",
mloop);
json_object_int_add( json_object_int_add(
json_row, "effectivePropagationDelay", json_row, "effectivePropagationDelay",
@ -1250,7 +1235,7 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
vty_out(vty, "\n"); vty_out(vty, "\n");
vty_out(vty, "\n"); vty_out(vty, "\n");
pim_print_ifp_flags(vty, ifp, mloop); pim_print_ifp_flags(vty, ifp);
vty_out(vty, "Join Prune Interval\n"); vty_out(vty, "Join Prune Interval\n");
vty_out(vty, "-------------------\n"); vty_out(vty, "-------------------\n");

View File

@ -1185,8 +1185,8 @@ static void pim_igmp_read(struct thread *t)
{ {
uint8_t buf[10000]; uint8_t buf[10000];
struct gm_sock *igmp = (struct gm_sock *)THREAD_ARG(t); struct gm_sock *igmp = (struct gm_sock *)THREAD_ARG(t);
struct sockaddr_in from; struct sockaddr_storage from;
struct sockaddr_in to; struct sockaddr_storage to;
socklen_t fromlen = sizeof(from); socklen_t fromlen = sizeof(from);
socklen_t tolen = sizeof(to); socklen_t tolen = sizeof(to);
ifindex_t ifindex = -1; ifindex_t ifindex = -1;

View File

@ -331,8 +331,8 @@ static void pim_sock_read(struct thread *t)
struct interface *ifp, *orig_ifp; struct interface *ifp, *orig_ifp;
struct pim_interface *pim_ifp; struct pim_interface *pim_ifp;
int fd; int fd;
struct sockaddr_in from; struct sockaddr_storage from;
struct sockaddr_in to; struct sockaddr_storage to;
socklen_t fromlen = sizeof(from); socklen_t fromlen = sizeof(from);
socklen_t tolen = sizeof(to); socklen_t tolen = sizeof(to);
uint8_t buf[PIM_PIM_BUFSIZE_READ]; uint8_t buf[PIM_PIM_BUFSIZE_READ];

View File

@ -34,22 +34,27 @@
#include "vrf.h" #include "vrf.h"
#include "sockopt.h" #include "sockopt.h"
#include "lib_errors.h" #include "lib_errors.h"
#include "network.h"
#include "pimd.h" #include "pimd.h"
#include "pim_mroute.h" #include "pim_mroute.h"
#include "pim_sock.h" #include "pim_sock.h"
#include "pim_str.h" #include "pim_str.h"
/* GLOBAL VARS */ #if PIM_IPV == 4
#define setsockopt_iptos setsockopt_ipv4_tos
#define setsockopt_multicast_loop setsockopt_ipv4_multicast_loop
#else
#define setsockopt_iptos setsockopt_ipv6_tclass
#define setsockopt_multicast_loop setsockopt_ipv6_multicast_loop
#endif
int pim_socket_raw(int protocol) int pim_socket_raw(int protocol)
{ {
int fd; int fd;
frr_with_privs(&pimd_privs) { frr_with_privs(&pimd_privs) {
fd = socket(PIM_AF, SOCK_RAW, protocol);
fd = socket(AF_INET, SOCK_RAW, protocol);
} }
if (fd < 0) { if (fd < 0) {
@ -66,10 +71,16 @@ void pim_socket_ip_hdr(int fd)
const int on = 1; const int on = 1;
frr_with_privs(&pimd_privs) { frr_with_privs(&pimd_privs) {
#if PIM_IPV == 4
if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on))) if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)))
zlog_err("%s: Could not turn on IP_HDRINCL option: %s", zlog_err("%s: Could not turn on IP_HDRINCL option: %m",
__func__, safe_strerror(errno)); __func__);
#else
if (setsockopt(fd, IPPROTO_IPV6, IPV6_HDRINCL, &on, sizeof(on)))
zlog_err(
"%s: Could not turn on IPV6_HDRINCL option: %m",
__func__);
#endif
} }
} }
@ -80,29 +91,102 @@ void pim_socket_ip_hdr(int fd)
int pim_socket_bind(int fd, struct interface *ifp) int pim_socket_bind(int fd, struct interface *ifp)
{ {
int ret = 0; int ret = 0;
#ifdef SO_BINDTODEVICE #ifdef SO_BINDTODEVICE
frr_with_privs(&pimd_privs) { frr_with_privs(&pimd_privs) {
ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifp->name, ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifp->name,
strlen(ifp->name)); strlen(ifp->name));
} }
#endif #endif
return ret; return ret;
} }
int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp, #if PIM_IPV == 4
static inline int pim_setsockopt(int protocol, int fd, struct interface *ifp)
{
int one = 1;
int ttl = 1;
#if defined(HAVE_IP_PKTINFO)
/* Linux and Solaris IP_PKTINFO */
if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)))
zlog_warn("Could not set PKTINFO on socket fd=%d: %m", fd);
#elif defined(HAVE_IP_RECVDSTADDR)
/* BSD IP_RECVDSTADDR */
if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &one, sizeof(one)))
zlog_warn("Could not set IP_RECVDSTADDR on socket fd=%d: %m",
fd);
#else
flog_err(
EC_LIB_DEVELOPMENT,
"Missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()");
close(fd);
return PIM_SOCK_ERR_DSTADDR;
#endif
/* Set router alert (RFC 2113) for all IGMP messages (RFC
* 3376 4. Message Formats)*/
if (protocol == IPPROTO_IGMP) {
uint8_t ra[4];
ra[0] = 148;
ra[1] = 4;
ra[2] = 0;
ra[3] = 0;
if (setsockopt(fd, IPPROTO_IP, IP_OPTIONS, ra, 4)) {
zlog_warn(
"Could not set Router Alert Option on socket fd=%d: %m",
fd);
close(fd);
return PIM_SOCK_ERR_RA;
}
}
if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl))) {
zlog_warn("Could not set multicast TTL=%d on socket fd=%d: %m",
ttl, fd);
close(fd);
return PIM_SOCK_ERR_TTL;
}
if (setsockopt_ipv4_multicast_if(fd, PIMADDR_ANY, ifp->ifindex)) {
zlog_warn(
"Could not set Outgoing Interface Option on socket fd=%d: %m",
fd);
close(fd);
return PIM_SOCK_ERR_IFACE;
}
return 0;
}
#else /* PIM_IPV != 4 */
static inline int pim_setsockopt(int protocol, int fd, struct interface *ifp)
{
int ttl = 1;
struct ipv6_mreq mreq = {};
setsockopt_ipv6_pktinfo(fd, 1);
setsockopt_ipv6_multicast_hops(fd, ttl);
mreq.ipv6mr_interface = ifp->ifindex;
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &mreq,
sizeof(mreq))) {
zlog_warn(
"Could not set Outgoing Interface Option on socket fd=%d: %m",
fd);
close(fd);
return PIM_SOCK_ERR_IFACE;
}
return 0;
}
#endif
int pim_socket_mcast(int protocol, pim_addr ifaddr, struct interface *ifp,
uint8_t loop) uint8_t loop)
{ {
int rcvbuf = 1024 * 1024 * 8;
#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
struct ip_mreqn mreq;
#else
struct ip_mreq mreq;
#endif
int fd; int fd;
int ret;
fd = pim_socket_raw(protocol); fd = pim_socket_raw(protocol);
if (fd < 0) { if (fd < 0) {
@ -111,217 +195,148 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp,
return PIM_SOCK_ERR_SOCKET; return PIM_SOCK_ERR_SOCKET;
} }
#ifdef SO_BINDTODEVICE /* XXX: if SO_BINDTODEVICE isn't available, use IP_PKTINFO / IP_RECVIF
int ret; * to emulate behaviour? Or change to only use 1 socket for all
* interfaces? */
ret = pim_socket_bind(fd, ifp); ret = pim_socket_bind(fd, ifp);
if (ret) { if (ret) {
close(fd); close(fd);
zlog_warn( zlog_warn("Could not set fd: %d for interface: %s to device",
"Could not set fd: %d for interface: %s to device", fd, ifp->name);
fd, ifp->name);
return PIM_SOCK_ERR_BIND; return PIM_SOCK_ERR_BIND;
} }
#else
/* XXX: use IP_PKTINFO / IP_RECVIF to emulate behaviour? Or change to
* only use 1 socket for all interfaces? */
#endif
/* Needed to obtain destination address from recvmsg() */ set_nonblocking(fd);
{ sockopt_reuseaddr(fd);
#if defined(HAVE_IP_PKTINFO) setsockopt_so_recvbuf(fd, 8 * 1024 * 1024);
/* Linux and Solaris IP_PKTINFO */
int opt = 1; ret = pim_setsockopt(protocol, fd, ifp);
if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt))) { if (ret) {
zlog_warn( zlog_warn("pim_setsockopt failed for interface: %s to device ",
"Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", ifp->name);
fd, errno, safe_strerror(errno)); return ret;
}
#elif defined(HAVE_IP_RECVDSTADDR)
/* BSD IP_RECVDSTADDR */
int opt = 1;
if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt,
sizeof(opt))) {
zlog_warn(
"Could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s",
fd, errno, safe_strerror(errno));
}
#else
flog_err(
EC_LIB_DEVELOPMENT,
"%s %s: Missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()",
__FILE__, __func__);
close(fd);
return PIM_SOCK_ERR_DSTADDR;
#endif
} }
/* leftover common sockopts */
/* Set router alert (RFC 2113) for all IGMP messages (RFC 3376 4. if (setsockopt_multicast_loop(fd, loop)) {
* Message Formats)*/
if (protocol == IPPROTO_IGMP) {
uint8_t ra[4];
ra[0] = 148;
ra[1] = 4;
ra[2] = 0;
ra[3] = 0;
if (setsockopt(fd, IPPROTO_IP, IP_OPTIONS, ra, 4)) {
zlog_warn(
"Could not set Router Alert Option on socket fd=%d: errno=%d: %s",
fd, errno, safe_strerror(errno));
close(fd);
return PIM_SOCK_ERR_RA;
}
}
{
int reuse = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse,
sizeof(reuse))) {
zlog_warn(
"Could not set Reuse Address Option on socket fd=%d: errno=%d: %s",
fd, errno, safe_strerror(errno));
close(fd);
return PIM_SOCK_ERR_REUSE;
}
}
{
const int MTTL = 1;
int ttl = MTTL;
if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl,
sizeof(ttl))) {
zlog_warn(
"Could not set multicast TTL=%d on socket fd=%d: errno=%d: %s",
MTTL, fd, errno, safe_strerror(errno));
close(fd);
return PIM_SOCK_ERR_TTL;
}
}
if (setsockopt_ipv4_multicast_loop(fd, loop)) {
zlog_warn( zlog_warn(
"Could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s", "Could not %s Multicast Loopback Option on socket fd=%d: %m",
loop ? "enable" : "disable", fd, errno, loop ? "enable" : "disable", fd);
safe_strerror(errno));
close(fd); close(fd);
return PIM_SOCK_ERR_LOOP; return PIM_SOCK_ERR_LOOP;
} }
memset(&mreq, 0, sizeof(mreq));
#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
mreq.imr_ifindex = ifp->ifindex;
#else
/*
* I am not sure what to do here yet for *BSD
*/
// mreq.imr_interface = ifindex;
#endif
if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (void *)&mreq,
sizeof(mreq))) {
zlog_warn(
"Could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s",
fd, errno, safe_strerror(errno));
close(fd);
return PIM_SOCK_ERR_IFACE;
}
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)))
zlog_warn("%s: Failure to set buffer size to %d", __func__,
rcvbuf);
{
long flags;
flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) {
zlog_warn(
"Could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
fd, errno, safe_strerror(errno));
close(fd);
return PIM_SOCK_ERR_NONBLOCK_GETFL;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
zlog_warn(
"Could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
fd, errno, safe_strerror(errno));
close(fd);
return PIM_SOCK_ERR_NONBLOCK_SETFL;
}
}
/* Set Tx socket DSCP byte */ /* Set Tx socket DSCP byte */
if (setsockopt_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL)) { if (setsockopt_iptos(fd, IPTOS_PREC_INTERNETCONTROL))
zlog_warn("can't set sockopt IP_TOS to PIM/IGMP socket %d: %s", zlog_warn("can't set sockopt IP[V6]_TOS to socket %d: %m", fd);
fd, safe_strerror(errno));
}
return fd; return fd;
} }
int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr, int pim_socket_join(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex)
ifindex_t ifindex)
{ {
int ret; int ret;
#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX #if PIM_IPV == 4
struct ip_mreqn opt; ret = setsockopt_ipv4_multicast(fd, IP_ADD_MEMBERSHIP, ifaddr,
group.s_addr, ifindex);
#else #else
struct ip_mreq opt; struct ipv6_mreq opt;
memcpy(&opt.ipv6mr_multiaddr, &group, 16);
opt.ipv6mr_interface = ifindex;
ret = setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &opt, sizeof(opt));
#endif #endif
opt.imr_multiaddr = group;
#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
opt.imr_address = ifaddr;
opt.imr_ifindex = ifindex;
#else
opt.imr_interface = ifaddr;
#endif
ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &opt, sizeof(opt));
if (ret) { if (ret) {
char group_str[INET_ADDRSTRLEN];
char ifaddr_str[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, &group, group_str, sizeof(group_str)))
snprintf(group_str, sizeof(group_str), "<group?>");
if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str,
sizeof(ifaddr_str)))
snprintf(ifaddr_str, sizeof(ifaddr_str), "<ifaddr?>");
flog_err( flog_err(
EC_LIB_SOCKET, EC_LIB_SOCKET,
"Failure socket joining fd=%d group %s on interface address %s: errno=%d: %s", "Failure socket joining fd=%d group %pPAs on interface address %pPAs: %m",
fd, group_str, ifaddr_str, errno, safe_strerror(errno)); fd, &group, &ifaddr);
return ret; return ret;
} }
if (PIM_DEBUG_TRACE) { if (PIM_DEBUG_TRACE)
char group_str[INET_ADDRSTRLEN];
char ifaddr_str[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, &group, group_str, sizeof(group_str)))
snprintf(group_str, sizeof(group_str), "<group?>");
if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str,
sizeof(ifaddr_str)))
snprintf(ifaddr_str, sizeof(ifaddr_str), "<ifaddr?>");
zlog_debug( zlog_debug(
"Socket fd=%d joined group %s on interface address %s", "Socket fd=%d joined group %pPAs on interface address %pPAs",
fd, group_str, ifaddr_str); fd, &group, &ifaddr);
}
return ret; return ret;
} }
#if PIM_IPV == 4
static void cmsg_getdstaddr(struct msghdr *mh, struct sockaddr_storage *dst,
ifindex_t *ifindex)
{
struct cmsghdr *cmsg;
struct sockaddr_in *dst4 = (struct sockaddr_in *)dst;
for (cmsg = CMSG_FIRSTHDR(mh); cmsg != NULL;
cmsg = CMSG_NXTHDR(mh, cmsg)) {
#ifdef HAVE_IP_PKTINFO
if ((cmsg->cmsg_level == IPPROTO_IP) &&
(cmsg->cmsg_type == IP_PKTINFO)) {
struct in_pktinfo *i;
i = (struct in_pktinfo *)CMSG_DATA(cmsg);
if (dst4)
dst4->sin_addr = i->ipi_addr;
if (ifindex)
*ifindex = i->ipi_ifindex;
break;
}
#endif
#ifdef HAVE_IP_RECVDSTADDR
if ((cmsg->cmsg_level == IPPROTO_IP) &&
(cmsg->cmsg_type == IP_RECVDSTADDR)) {
struct in_addr *i = (struct in_addr *)CMSG_DATA(cmsg);
if (dst4)
dst4->sin_addr = *i;
break;
}
#endif
#if defined(HAVE_IP_RECVIF) && defined(CMSG_IFINDEX)
if (cmsg->cmsg_type == IP_RECVIF)
if (ifindex)
*ifindex = CMSG_IFINDEX(cmsg);
#endif
}
}
#else /* PIM_IPV != 4 */
static void cmsg_getdstaddr(struct msghdr *mh, struct sockaddr_storage *dst,
ifindex_t *ifindex)
{
struct cmsghdr *cmsg;
struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst;
for (cmsg = CMSG_FIRSTHDR(mh); cmsg != NULL;
cmsg = CMSG_NXTHDR(mh, cmsg)) {
if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
(cmsg->cmsg_type == IPV6_PKTINFO)) {
struct in6_pktinfo *i;
i = (struct in6_pktinfo *)CMSG_DATA(cmsg);
if (dst6)
dst6->sin6_addr = i->ipi6_addr;
if (ifindex)
*ifindex = i->ipi6_ifindex;
break;
}
}
}
#endif /* PIM_IPV != 4 */
int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
struct sockaddr_in *from, socklen_t *fromlen, struct sockaddr_storage *from, socklen_t *fromlen,
struct sockaddr_in *to, socklen_t *tolen, struct sockaddr_storage *to, socklen_t *tolen,
ifindex_t *ifindex) ifindex_t *ifindex)
{ {
struct msghdr msgh; struct msghdr msgh;
struct cmsghdr *cmsg;
struct iovec iov; struct iovec iov;
char cbuf[1000]; char cbuf[1000];
int err; int err;
@ -331,19 +346,12 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
* Use getsockname() to get sin_port. * Use getsockname() to get sin_port.
*/ */
if (to) { if (to) {
struct sockaddr_in si; socklen_t to_len = sizeof(*to);
socklen_t si_len = sizeof(si);
memset(&si, 0, sizeof(si)); pim_socket_getsockname(fd, (struct sockaddr *)to, &to_len);
to->sin_family = AF_INET;
pim_socket_getsockname(fd, (struct sockaddr *)&si, &si_len);
to->sin_port = si.sin_port;
to->sin_addr = si.sin_addr;
if (tolen) if (tolen)
*tolen = sizeof(si); *tolen = sizeof(*to);
} }
memset(&msgh, 0, sizeof(struct msghdr)); memset(&msgh, 0, sizeof(struct msghdr));
@ -364,66 +372,11 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
if (fromlen) if (fromlen)
*fromlen = msgh.msg_namelen; *fromlen = msgh.msg_namelen;
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg_getdstaddr(&msgh, to, ifindex);
cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
#ifdef HAVE_IP_PKTINFO
if ((cmsg->cmsg_level == IPPROTO_IP)
&& (cmsg->cmsg_type == IP_PKTINFO)) {
struct in_pktinfo *i =
(struct in_pktinfo *)CMSG_DATA(cmsg);
if (to)
to->sin_addr = i->ipi_addr;
if (tolen)
*tolen = sizeof(struct sockaddr_in);
if (ifindex)
*ifindex = i->ipi_ifindex;
break;
}
#endif
#ifdef HAVE_IP_RECVDSTADDR
if ((cmsg->cmsg_level == IPPROTO_IP)
&& (cmsg->cmsg_type == IP_RECVDSTADDR)) {
struct in_addr *i = (struct in_addr *)CMSG_DATA(cmsg);
if (to)
to->sin_addr = *i;
if (tolen)
*tolen = sizeof(struct sockaddr_in);
break;
}
#endif
#if defined(HAVE_IP_RECVIF) && defined(CMSG_IFINDEX)
if (cmsg->cmsg_type == IP_RECVIF)
if (ifindex)
*ifindex = CMSG_IFINDEX(cmsg);
#endif
} /* for (cmsg) */
return err; /* len */ return err; /* len */
} }
int pim_socket_mcastloop_get(int fd)
{
int loop;
socklen_t loop_len = sizeof(loop);
if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, &loop_len)) {
int e = errno;
zlog_warn(
"Could not get Multicast Loopback Option on socket fd=%d: errno=%d: %s",
fd, errno, safe_strerror(errno));
errno = e;
return PIM_SOCK_ERR_LOOP;
}
return loop;
}
int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen) int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen)
{ {
if (getsockname(fd, name, namelen)) { if (getsockname(fd, name, namelen)) {

View File

@ -38,16 +38,14 @@
int pim_socket_bind(int fd, struct interface *ifp); int pim_socket_bind(int fd, struct interface *ifp);
void pim_socket_ip_hdr(int fd); void pim_socket_ip_hdr(int fd);
int pim_socket_raw(int protocol); int pim_socket_raw(int protocol);
int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp, int pim_socket_mcast(int protocol, pim_addr ifaddr, struct interface *ifp,
uint8_t loop); uint8_t loop);
int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr, int pim_socket_join(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex);
ifindex_t ifindex);
int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
struct sockaddr_in *from, socklen_t *fromlen,
struct sockaddr_in *to, socklen_t *tolen,
ifindex_t *ifindex);
int pim_socket_mcastloop_get(int fd); int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
struct sockaddr_storage *from, socklen_t *fromlen,
struct sockaddr_storage *to, socklen_t *tolen,
ifindex_t *ifindex);
int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen); int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen);

View File

@ -244,8 +244,8 @@ static void ssmpingd_sendto(struct ssmpingd_sock *ss, const uint8_t *buf,
static int ssmpingd_read_msg(struct ssmpingd_sock *ss) static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
{ {
struct interface *ifp; struct interface *ifp;
struct sockaddr_in from; struct sockaddr_storage from;
struct sockaddr_in to; struct sockaddr_storage to;
socklen_t fromlen = sizeof(from); socklen_t fromlen = sizeof(from);
socklen_t tolen = sizeof(to); socklen_t tolen = sizeof(to);
ifindex_t ifindex = -1; ifindex_t ifindex = -1;
@ -256,13 +256,11 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
len = pim_socket_recvfromto(ss->sock_fd, buf, sizeof(buf), &from, len = pim_socket_recvfromto(ss->sock_fd, buf, sizeof(buf), &from,
&fromlen, &to, &tolen, &ifindex); &fromlen, &to, &tolen, &ifindex);
if (len < 0) { if (len < 0) {
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", ss->source_addr, source_str,
sizeof(source_str));
zlog_warn( zlog_warn(
"%s: failure receiving ssmping for source %s on fd=%d: errno=%d: %s", "%s: failure receiving ssmping for source %pI4 on fd=%d: errno=%d: %s",
__func__, source_str, ss->sock_fd, errno, __func__, &ss->source_addr, ss->sock_fd, errno,
safe_strerror(errno)); safe_strerror(errno));
return -1; return -1;
} }
@ -270,47 +268,31 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
ifp = if_lookup_by_index(ifindex, ss->pim->vrf->vrf_id); ifp = if_lookup_by_index(ifindex, ss->pim->vrf->vrf_id);
if (buf[0] != PIM_SSMPINGD_REQUEST) { if (buf[0] != PIM_SSMPINGD_REQUEST) {
char source_str[INET_ADDRSTRLEN];
char from_str[INET_ADDRSTRLEN];
char to_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", ss->source_addr, source_str,
sizeof(source_str));
pim_inet4_dump("<from?>", from.sin_addr, from_str,
sizeof(from_str));
pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str));
zlog_warn( zlog_warn(
"%s: bad ssmping type=%d from %s,%d to %s,%d on interface %s ifindex=%d fd=%d src=%s", "%s: bad ssmping type=%d from %pSUp to %pSUp on interface %s ifindex=%d fd=%d src=%pI4",
__func__, buf[0], from_str, ntohs(from.sin_port), __func__, buf[0], &from, &to,
to_str, ntohs(to.sin_port),
ifp ? ifp->name : "<iface?>", ifindex, ss->sock_fd, ifp ? ifp->name : "<iface?>", ifindex, ss->sock_fd,
source_str); &ss->source_addr);
return 0; return 0;
} }
if (PIM_DEBUG_SSMPINGD) { if (PIM_DEBUG_SSMPINGD) {
char source_str[INET_ADDRSTRLEN];
char from_str[INET_ADDRSTRLEN];
char to_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", ss->source_addr, source_str,
sizeof(source_str));
pim_inet4_dump("<from?>", from.sin_addr, from_str,
sizeof(from_str));
pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str));
zlog_debug( zlog_debug(
"%s: recv ssmping from %s,%d to %s,%d on interface %s ifindex=%d fd=%d src=%s", "%s: recv ssmping from %pSUp, to %pSUp, on interface %s ifindex=%d fd=%d src=%pI4",
__func__, from_str, ntohs(from.sin_port), to_str, __func__, &from, &to, ifp ? ifp->name : "<iface?>",
ntohs(to.sin_port), ifp ? ifp->name : "<iface?>", ifindex, ss->sock_fd, &ss->source_addr);
ifindex, ss->sock_fd, source_str);
} }
buf[0] = PIM_SSMPINGD_REPLY; buf[0] = PIM_SSMPINGD_REPLY;
struct sockaddr_in *from_addr = (struct sockaddr_in *)&from;
/* unicast reply */ /* unicast reply */
ssmpingd_sendto(ss, buf, len, from); ssmpingd_sendto(ss, buf, len, *from_addr);
/* multicast reply */ /* multicast reply */
from.sin_addr = ss->pim->ssmpingd_group_addr; from_addr->sin_addr = ss->pim->ssmpingd_group_addr;
ssmpingd_sendto(ss, buf, len, from); ssmpingd_sendto(ss, buf, len, *from_addr);
return 0; return 0;
} }