mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-17 02:22:17 +00:00
Merge pull request #10399 from g-balaji1/pimv6-sock
pim6d: PIMv6 socket related changes
This commit is contained in:
commit
6ea4244514
@ -455,8 +455,7 @@ static void pim_show_membership(struct pim_instance *pim, struct vty *vty,
|
||||
json_object_free(json);
|
||||
}
|
||||
|
||||
static void pim_print_ifp_flags(struct vty *vty, struct interface *ifp,
|
||||
int mloop)
|
||||
static void pim_print_ifp_flags(struct vty *vty, struct interface *ifp)
|
||||
{
|
||||
vty_out(vty, "Flags\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, "Multicast : %s\n",
|
||||
if_is_multicast(ifp) ? "yes" : "no");
|
||||
vty_out(vty, "Multicast Loop : %d\n", mloop);
|
||||
vty_out(vty, "Promiscuous : %s\n",
|
||||
(ifp->flags & IFF_PROMISC) ? "yes" : "no");
|
||||
vty_out(vty, "\n");
|
||||
@ -576,7 +574,6 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
|
||||
char other_hhmmss[10];
|
||||
int found_ifname = 0;
|
||||
int sqi;
|
||||
int mloop = 0;
|
||||
long gmi_msec; /* Group Membership Interval */
|
||||
long lmqt_msec;
|
||||
long ohpi_msec;
|
||||
@ -639,11 +636,6 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
|
||||
|
||||
qri_msec =
|
||||
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;
|
||||
|
||||
if (uj) {
|
||||
@ -776,7 +768,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
|
||||
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 stat_uptime[10];
|
||||
char uptime[10];
|
||||
int mloop = 0;
|
||||
int found_ifname = 0;
|
||||
int print_header;
|
||||
json_object *json = NULL;
|
||||
@ -945,10 +936,6 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
|
||||
pim_ifp->pim_hello_period);
|
||||
pim_time_uptime(stat_uptime, sizeof(stat_uptime),
|
||||
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) {
|
||||
char pbuf[PREFIX2STR_BUFFER];
|
||||
@ -1096,8 +1083,6 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
|
||||
pim_ifp->pim_ifstat_hello_sendfail);
|
||||
json_object_int_add(json_row, "helloGenerationId",
|
||||
pim_ifp->pim_generation_id);
|
||||
json_object_int_add(json_row, "flagMulticastLoop",
|
||||
mloop);
|
||||
|
||||
json_object_int_add(
|
||||
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");
|
||||
|
||||
pim_print_ifp_flags(vty, ifp, mloop);
|
||||
pim_print_ifp_flags(vty, ifp);
|
||||
|
||||
vty_out(vty, "Join Prune Interval\n");
|
||||
vty_out(vty, "-------------------\n");
|
||||
|
@ -1185,8 +1185,8 @@ static void pim_igmp_read(struct thread *t)
|
||||
{
|
||||
uint8_t buf[10000];
|
||||
struct gm_sock *igmp = (struct gm_sock *)THREAD_ARG(t);
|
||||
struct sockaddr_in from;
|
||||
struct sockaddr_in to;
|
||||
struct sockaddr_storage from;
|
||||
struct sockaddr_storage to;
|
||||
socklen_t fromlen = sizeof(from);
|
||||
socklen_t tolen = sizeof(to);
|
||||
ifindex_t ifindex = -1;
|
||||
|
@ -331,8 +331,8 @@ static void pim_sock_read(struct thread *t)
|
||||
struct interface *ifp, *orig_ifp;
|
||||
struct pim_interface *pim_ifp;
|
||||
int fd;
|
||||
struct sockaddr_in from;
|
||||
struct sockaddr_in to;
|
||||
struct sockaddr_storage from;
|
||||
struct sockaddr_storage to;
|
||||
socklen_t fromlen = sizeof(from);
|
||||
socklen_t tolen = sizeof(to);
|
||||
uint8_t buf[PIM_PIM_BUFSIZE_READ];
|
||||
|
467
pimd/pim_sock.c
467
pimd/pim_sock.c
@ -34,22 +34,27 @@
|
||||
#include "vrf.h"
|
||||
#include "sockopt.h"
|
||||
#include "lib_errors.h"
|
||||
#include "network.h"
|
||||
|
||||
#include "pimd.h"
|
||||
#include "pim_mroute.h"
|
||||
#include "pim_sock.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 fd;
|
||||
|
||||
frr_with_privs(&pimd_privs) {
|
||||
|
||||
fd = socket(AF_INET, SOCK_RAW, protocol);
|
||||
|
||||
fd = socket(PIM_AF, SOCK_RAW, protocol);
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
@ -66,10 +71,16 @@ void pim_socket_ip_hdr(int fd)
|
||||
const int on = 1;
|
||||
|
||||
frr_with_privs(&pimd_privs) {
|
||||
|
||||
#if PIM_IPV == 4
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)))
|
||||
zlog_err("%s: Could not turn on IP_HDRINCL option: %s",
|
||||
__func__, safe_strerror(errno));
|
||||
zlog_err("%s: Could not turn on IP_HDRINCL option: %m",
|
||||
__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 ret = 0;
|
||||
|
||||
#ifdef SO_BINDTODEVICE
|
||||
|
||||
frr_with_privs(&pimd_privs) {
|
||||
|
||||
ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifp->name,
|
||||
strlen(ifp->name));
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
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)
|
||||
{
|
||||
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 ret;
|
||||
|
||||
fd = pim_socket_raw(protocol);
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef SO_BINDTODEVICE
|
||||
int ret;
|
||||
|
||||
/* XXX: if SO_BINDTODEVICE isn't available, use IP_PKTINFO / IP_RECVIF
|
||||
* to emulate behaviour? Or change to only use 1 socket for all
|
||||
* interfaces? */
|
||||
ret = pim_socket_bind(fd, ifp);
|
||||
if (ret) {
|
||||
close(fd);
|
||||
zlog_warn(
|
||||
"Could not set fd: %d for interface: %s to device",
|
||||
fd, ifp->name);
|
||||
zlog_warn("Could not set fd: %d for interface: %s to device",
|
||||
fd, ifp->name);
|
||||
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() */
|
||||
{
|
||||
#if defined(HAVE_IP_PKTINFO)
|
||||
/* Linux and Solaris IP_PKTINFO */
|
||||
int opt = 1;
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt))) {
|
||||
zlog_warn(
|
||||
"Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
|
||||
fd, errno, safe_strerror(errno));
|
||||
}
|
||||
#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
|
||||
set_nonblocking(fd);
|
||||
sockopt_reuseaddr(fd);
|
||||
setsockopt_so_recvbuf(fd, 8 * 1024 * 1024);
|
||||
|
||||
ret = pim_setsockopt(protocol, fd, ifp);
|
||||
if (ret) {
|
||||
zlog_warn("pim_setsockopt failed for interface: %s to device ",
|
||||
ifp->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* 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: 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)) {
|
||||
/* leftover common sockopts */
|
||||
if (setsockopt_multicast_loop(fd, loop)) {
|
||||
zlog_warn(
|
||||
"Could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s",
|
||||
loop ? "enable" : "disable", fd, errno,
|
||||
safe_strerror(errno));
|
||||
"Could not %s Multicast Loopback Option on socket fd=%d: %m",
|
||||
loop ? "enable" : "disable", fd);
|
||||
close(fd);
|
||||
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 */
|
||||
if (setsockopt_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL)) {
|
||||
zlog_warn("can't set sockopt IP_TOS to PIM/IGMP socket %d: %s",
|
||||
fd, safe_strerror(errno));
|
||||
}
|
||||
if (setsockopt_iptos(fd, IPTOS_PREC_INTERNETCONTROL))
|
||||
zlog_warn("can't set sockopt IP[V6]_TOS to socket %d: %m", fd);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr,
|
||||
ifindex_t ifindex)
|
||||
int pim_socket_join(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
|
||||
struct ip_mreqn opt;
|
||||
#if PIM_IPV == 4
|
||||
ret = setsockopt_ipv4_multicast(fd, IP_ADD_MEMBERSHIP, ifaddr,
|
||||
group.s_addr, ifindex);
|
||||
#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
|
||||
|
||||
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) {
|
||||
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(
|
||||
EC_LIB_SOCKET,
|
||||
"Failure socket joining fd=%d group %s on interface address %s: errno=%d: %s",
|
||||
fd, group_str, ifaddr_str, errno, safe_strerror(errno));
|
||||
"Failure socket joining fd=%d group %pPAs on interface address %pPAs: %m",
|
||||
fd, &group, &ifaddr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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?>");
|
||||
|
||||
if (PIM_DEBUG_TRACE)
|
||||
zlog_debug(
|
||||
"Socket fd=%d joined group %s on interface address %s",
|
||||
fd, group_str, ifaddr_str);
|
||||
}
|
||||
|
||||
"Socket fd=%d joined group %pPAs on interface address %pPAs",
|
||||
fd, &group, &ifaddr);
|
||||
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,
|
||||
struct sockaddr_in *from, socklen_t *fromlen,
|
||||
struct sockaddr_in *to, socklen_t *tolen,
|
||||
struct sockaddr_storage *from, socklen_t *fromlen,
|
||||
struct sockaddr_storage *to, socklen_t *tolen,
|
||||
ifindex_t *ifindex)
|
||||
{
|
||||
struct msghdr msgh;
|
||||
struct cmsghdr *cmsg;
|
||||
struct iovec iov;
|
||||
char cbuf[1000];
|
||||
int err;
|
||||
@ -331,19 +346,12 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
|
||||
* Use getsockname() to get sin_port.
|
||||
*/
|
||||
if (to) {
|
||||
struct sockaddr_in si;
|
||||
socklen_t si_len = sizeof(si);
|
||||
socklen_t to_len = sizeof(*to);
|
||||
|
||||
memset(&si, 0, sizeof(si));
|
||||
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;
|
||||
pim_socket_getsockname(fd, (struct sockaddr *)to, &to_len);
|
||||
|
||||
if (tolen)
|
||||
*tolen = sizeof(si);
|
||||
*tolen = sizeof(*to);
|
||||
}
|
||||
|
||||
memset(&msgh, 0, sizeof(struct msghdr));
|
||||
@ -364,66 +372,11 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
|
||||
if (fromlen)
|
||||
*fromlen = msgh.msg_namelen;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
|
||||
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) */
|
||||
cmsg_getdstaddr(&msgh, to, ifindex);
|
||||
|
||||
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)
|
||||
{
|
||||
if (getsockname(fd, name, namelen)) {
|
||||
|
@ -38,16 +38,14 @@
|
||||
int pim_socket_bind(int fd, struct interface *ifp);
|
||||
void pim_socket_ip_hdr(int fd);
|
||||
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);
|
||||
int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr,
|
||||
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_join(int fd, pim_addr group, pim_addr ifaddr, 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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct sockaddr_in from;
|
||||
struct sockaddr_in to;
|
||||
struct sockaddr_storage from;
|
||||
struct sockaddr_storage to;
|
||||
socklen_t fromlen = sizeof(from);
|
||||
socklen_t tolen = sizeof(to);
|
||||
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,
|
||||
&fromlen, &to, &tolen, &ifindex);
|
||||
|
||||
if (len < 0) {
|
||||
char source_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", ss->source_addr, source_str,
|
||||
sizeof(source_str));
|
||||
zlog_warn(
|
||||
"%s: failure receiving ssmping for source %s on fd=%d: errno=%d: %s",
|
||||
__func__, source_str, ss->sock_fd, errno,
|
||||
"%s: failure receiving ssmping for source %pI4 on fd=%d: errno=%d: %s",
|
||||
__func__, &ss->source_addr, ss->sock_fd, errno,
|
||||
safe_strerror(errno));
|
||||
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);
|
||||
|
||||
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(
|
||||
"%s: bad ssmping type=%d from %s,%d to %s,%d on interface %s ifindex=%d fd=%d src=%s",
|
||||
__func__, buf[0], from_str, ntohs(from.sin_port),
|
||||
to_str, ntohs(to.sin_port),
|
||||
"%s: bad ssmping type=%d from %pSUp to %pSUp on interface %s ifindex=%d fd=%d src=%pI4",
|
||||
__func__, buf[0], &from, &to,
|
||||
ifp ? ifp->name : "<iface?>", ifindex, ss->sock_fd,
|
||||
source_str);
|
||||
&ss->source_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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(
|
||||
"%s: recv ssmping from %s,%d to %s,%d on interface %s ifindex=%d fd=%d src=%s",
|
||||
__func__, from_str, ntohs(from.sin_port), to_str,
|
||||
ntohs(to.sin_port), ifp ? ifp->name : "<iface?>",
|
||||
ifindex, ss->sock_fd, source_str);
|
||||
"%s: recv ssmping from %pSUp, to %pSUp, on interface %s ifindex=%d fd=%d src=%pI4",
|
||||
__func__, &from, &to, ifp ? ifp->name : "<iface?>",
|
||||
ifindex, ss->sock_fd, &ss->source_addr);
|
||||
}
|
||||
|
||||
buf[0] = PIM_SSMPINGD_REPLY;
|
||||
|
||||
struct sockaddr_in *from_addr = (struct sockaddr_in *)&from;
|
||||
|
||||
/* unicast reply */
|
||||
ssmpingd_sendto(ss, buf, len, from);
|
||||
ssmpingd_sendto(ss, buf, len, *from_addr);
|
||||
|
||||
/* multicast reply */
|
||||
from.sin_addr = ss->pim->ssmpingd_group_addr;
|
||||
ssmpingd_sendto(ss, buf, len, from);
|
||||
from_addr->sin_addr = ss->pim->ssmpingd_group_addr;
|
||||
ssmpingd_sendto(ss, buf, len, *from_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user