summaryrefslogtreecommitdiff
path: root/pimd/pim_pim.c
diff options
context:
space:
mode:
Diffstat (limited to 'pimd/pim_pim.c')
-rw-r--r--pimd/pim_pim.c259
1 files changed, 147 insertions, 112 deletions
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c
index 535448f013..50bbc0fe18 100644
--- a/pimd/pim_pim.c
+++ b/pimd/pim_pim.c
@@ -138,31 +138,34 @@ void pim_sock_delete(struct interface *ifp, const char *delete_message)
}
/* For now check dst address for hello, assrt and join/prune is all pim rtr */
-static bool pim_pkt_dst_addr_ok(enum pim_msg_type type, in_addr_t addr)
+static bool pim_pkt_dst_addr_ok(enum pim_msg_type type, pim_addr addr)
{
if ((type == PIM_MSG_TYPE_HELLO) || (type == PIM_MSG_TYPE_ASSERT)
|| (type == PIM_MSG_TYPE_JOIN_PRUNE)) {
- if (addr != qpim_all_pim_routers_addr.s_addr)
+ if (pim_addr_cmp(addr, qpim_all_pim_routers_addr))
return false;
}
return true;
}
-int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
+int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
+ pim_sgaddr sg)
{
- struct ip *ip_hdr;
+ struct iovec iov[2], *iovp = iov;
+#if PIM_IPV == 4
+ struct ip *ip_hdr = (struct ip *)buf;
size_t ip_hlen; /* ip header length in bytes */
- char src_str[INET_ADDRSTRLEN];
- char dst_str[INET_ADDRSTRLEN];
+#endif
uint8_t *pim_msg;
- int pim_msg_len;
+ uint32_t pim_msg_len = 0;
uint16_t pim_checksum; /* received checksum */
uint16_t checksum; /* computed checksum */
struct pim_neighbor *neigh;
struct pim_msg_header *header;
bool no_fwd;
+#if PIM_IPV == 4
if (len < sizeof(*ip_hdr)) {
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug(
@@ -171,11 +174,31 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
return -1;
}
- ip_hdr = (struct ip *)buf;
ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
+ sg = pim_sgaddr_from_iphdr(ip_hdr);
pim_msg = buf + ip_hlen;
pim_msg_len = len - ip_hlen;
+#else
+ struct ipv6_ph phdr = {
+ .src = sg.src,
+ .dst = sg.grp,
+ .ulpl = htonl(len),
+ .next_hdr = IPPROTO_PIM,
+ };
+
+ iovp->iov_base = &phdr;
+ iovp->iov_len = sizeof(phdr);
+ iovp++;
+
+ /* NB: header is not included in IPv6 RX */
+ pim_msg = buf;
+ pim_msg_len = len;
+#endif
+
+ iovp->iov_base = pim_msg;
+ iovp->iov_len = pim_msg_len;
+ iovp++;
header = (struct pim_msg_header *)pim_msg;
if (pim_msg_len < PIM_PIM_MIN_LEN) {
@@ -208,10 +231,21 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
pim_msg_len, PIM_MSG_REGISTER_LEN);
return -1;
}
+
+#if PIM_IPV == 6
+ phdr.ulpl = htonl(PIM_MSG_REGISTER_LEN);
+#endif
/* First 8 byte header checksum */
- checksum = in_cksum(pim_msg, PIM_MSG_REGISTER_LEN);
+ iovp[-1].iov_len = PIM_MSG_REGISTER_LEN;
+ checksum = in_cksumv(iov, iovp - iov);
+
if (checksum != pim_checksum) {
- checksum = in_cksum(pim_msg, pim_msg_len);
+#if PIM_IPV == 6
+ phdr.ulpl = htonl(pim_msg_len);
+#endif
+ iovp[-1].iov_len = pim_msg_len;
+
+ checksum = in_cksumv(iov, iovp - iov);
if (checksum != pim_checksum) {
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug(
@@ -223,7 +257,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
}
}
} else {
- checksum = in_cksum(pim_msg, pim_msg_len);
+ checksum = in_cksumv(iov, iovp - iov);
if (checksum != pim_checksum) {
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug(
@@ -235,43 +269,29 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
}
if (PIM_DEBUG_PIM_PACKETS) {
- pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str,
- sizeof(src_str));
- pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str,
- sizeof(dst_str));
zlog_debug(
- "Recv PIM %s packet from %s to %s on %s: ttl=%d pim_version=%d pim_msg_size=%d checksum=%x",
- pim_pim_msgtype2str(header->type), src_str, dst_str,
- ifp->name, ip_hdr->ip_ttl, header->ver, pim_msg_len,
- checksum);
- if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
+ "Recv PIM %s packet from %pPA to %pPA on %s: pim_version=%d pim_msg_size=%d checksum=%x",
+ pim_pim_msgtype2str(header->type), &sg.src, &sg.grp,
+ ifp->name, header->ver, pim_msg_len, checksum);
+ if (PIM_DEBUG_PIM_PACKETDUMP_RECV)
pim_pkt_dump(__func__, pim_msg, pim_msg_len);
- }
}
- if (!pim_pkt_dst_addr_ok(header->type, ip_hdr->ip_dst.s_addr)) {
- char dst_str[INET_ADDRSTRLEN];
- char src_str[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str,
- sizeof(dst_str));
- pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str,
- sizeof(src_str));
+ if (!pim_pkt_dst_addr_ok(header->type, sg.grp)) {
zlog_warn(
- "%s: Ignoring Pkt. Unexpected IP destination %s for %s (Expected: all_pim_routers_addr) from %s",
- __func__, dst_str, pim_pim_msgtype2str(header->type),
- src_str);
+ "%s: Ignoring Pkt. Unexpected IP destination %pPA for %s (Expected: all_pim_routers_addr) from %pPA",
+ __func__, &sg.grp, pim_pim_msgtype2str(header->type),
+ &sg.src);
return -1;
}
switch (header->type) {
case PIM_MSG_TYPE_HELLO:
- return pim_hello_recv(ifp, ip_hdr->ip_src,
- pim_msg + PIM_MSG_HEADER_LEN,
+ return pim_hello_recv(ifp, sg.src, pim_msg + PIM_MSG_HEADER_LEN,
pim_msg_len - PIM_MSG_HEADER_LEN);
break;
case PIM_MSG_TYPE_REGISTER:
- return pim_register_recv(ifp, ip_hdr->ip_dst, ip_hdr->ip_src,
+ return pim_register_recv(ifp, sg.grp, sg.src,
pim_msg + PIM_MSG_HEADER_LEN,
pim_msg_len - PIM_MSG_HEADER_LEN);
break;
@@ -280,38 +300,37 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
pim_msg_len - PIM_MSG_HEADER_LEN);
break;
case PIM_MSG_TYPE_JOIN_PRUNE:
- neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
+ neigh = pim_neighbor_find(ifp, sg.src);
if (!neigh) {
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug(
- "%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
+ "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s",
__FILE__, __func__, header->type,
- src_str, ifp->name);
+ &sg.src, ifp->name);
return -1;
}
pim_neighbor_timer_reset(neigh, neigh->holdtime);
- return pim_joinprune_recv(ifp, neigh, ip_hdr->ip_src,
+ return pim_joinprune_recv(ifp, neigh, sg.src,
pim_msg + PIM_MSG_HEADER_LEN,
pim_msg_len - PIM_MSG_HEADER_LEN);
break;
case PIM_MSG_TYPE_ASSERT:
- neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
+ neigh = pim_neighbor_find(ifp, sg.src);
if (!neigh) {
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug(
- "%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
+ "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s",
__FILE__, __func__, header->type,
- src_str, ifp->name);
+ &sg.src, ifp->name);
return -1;
}
pim_neighbor_timer_reset(neigh, neigh->holdtime);
- return pim_assert_recv(ifp, neigh, ip_hdr->ip_src,
+ return pim_assert_recv(ifp, neigh, sg.src,
pim_msg + PIM_MSG_HEADER_LEN,
pim_msg_len - PIM_MSG_HEADER_LEN);
break;
case PIM_MSG_TYPE_BOOTSTRAP:
- return pim_bsm_process(ifp, ip_hdr, pim_msg, pim_msg_len,
- no_fwd);
+ return pim_bsm_process(ifp, &sg, pim_msg, pim_msg_len, no_fwd);
break;
default:
@@ -348,6 +367,8 @@ static void pim_sock_read(struct thread *t)
pim_ifp = ifp->info;
while (cont) {
+ pim_sgaddr sg;
+
len = pim_socket_recvfromto(fd, buf, sizeof(buf), &from,
&fromlen, &to, &tolen, &ifindex);
if (len < 0) {
@@ -377,7 +398,15 @@ static void pim_sock_read(struct thread *t)
ifindex);
goto done;
}
- int fail = pim_pim_packet(ifp, buf, len);
+#if PIM_IPV == 4
+ sg.src = ((struct sockaddr_in *)&from)->sin_addr;
+ sg.grp = ((struct sockaddr_in *)&to)->sin_addr;
+#else
+ sg.src = ((struct sockaddr_in6 *)&from)->sin6_addr;
+ sg.grp = ((struct sockaddr_in6 *)&to)->sin6_addr;
+#endif
+
+ int fail = pim_pim_packet(ifp, buf, len, sg);
if (fail) {
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("%s: pim_pim_packet() return=%d",
@@ -520,75 +549,62 @@ void pim_sock_reset(struct interface *ifp)
pim_ifstat_reset(ifp);
}
+#if PIM_IPV == 4
static uint16_t ip_id = 0;
-
+#endif
static int pim_msg_send_frame(int fd, char *buf, size_t len,
struct sockaddr *dst, size_t salen,
const char *ifname)
{
- struct ip *ip = (struct ip *)buf;
-
- if (sendto(fd, buf, len, MSG_DONTWAIT, dst, salen) < 0) {
- char dst_str[INET_ADDRSTRLEN];
-
- switch (errno) {
- case EMSGSIZE: {
- size_t hdrsize = sizeof(struct ip);
- size_t newlen1 = ((len - hdrsize) / 2) & 0xFFF8;
- size_t sendlen = newlen1 + hdrsize;
- size_t offset = ntohs(ip->ip_off);
-
- ip->ip_len = htons(sendlen);
- ip->ip_off = htons(offset | IP_MF);
- if (pim_msg_send_frame(fd, buf, sendlen, dst, salen,
- ifname) == 0) {
- struct ip *ip2 = (struct ip *)(buf + newlen1);
- size_t newlen2 = len - sendlen;
- sendlen = newlen2 + hdrsize;
-
- memcpy(ip2, ip, hdrsize);
- ip2->ip_len = htons(sendlen);
- ip2->ip_off = htons(offset + (newlen1 >> 3));
- return pim_msg_send_frame(fd, (char *)ip2,
- sendlen, dst, salen,
- ifname);
- }
- }
+ if (sendto(fd, buf, len, MSG_DONTWAIT, dst, salen) >= 0)
+ return 0;
- return -1;
- default:
- if (PIM_DEBUG_PIM_PACKETS) {
- pim_inet4_dump("<dst?>", ip->ip_dst, dst_str,
- sizeof(dst_str));
- zlog_warn(
- "%s: sendto() failure to %s: iface=%s fd=%d msg_size=%zd: errno=%d: %s",
- __func__, dst_str, ifname, fd, len,
- errno, safe_strerror(errno));
- }
- return -1;
- }
+#if PIM_IPV == 4
+ if (errno == EMSGSIZE) {
+ struct ip *ip = (struct ip *)buf;
+ size_t hdrsize = sizeof(struct ip);
+ size_t newlen1 = ((len - hdrsize) / 2) & 0xFFF8;
+ size_t sendlen = newlen1 + hdrsize;
+ size_t offset = ntohs(ip->ip_off);
+ int ret;
+
+ ip->ip_len = htons(sendlen);
+ ip->ip_off = htons(offset | IP_MF);
+
+ ret = pim_msg_send_frame(fd, buf, sendlen, dst, salen, ifname);
+ if (ret)
+ return ret;
+
+ struct ip *ip2 = (struct ip *)(buf + newlen1);
+ size_t newlen2 = len - sendlen;
+
+ sendlen = newlen2 + hdrsize;
+
+ memcpy(ip2, ip, hdrsize);
+ ip2->ip_len = htons(sendlen);
+ ip2->ip_off = htons(offset + (newlen1 >> 3));
+ return pim_msg_send_frame(fd, (char *)ip2, sendlen, dst, salen,
+ ifname);
}
+#endif
- return 0;
+ zlog_warn(
+ "%s: sendto() failure to %pSU: iface=%s fd=%d msg_size=%zd: %m",
+ __func__, dst, ifname, fd, len);
+ return -1;
}
int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
int pim_msg_size, const char *ifname)
{
- struct sockaddr_in to;
socklen_t tolen;
unsigned char buffer[10000];
unsigned char *msg_start;
uint8_t ttl;
struct pim_msg_header *header;
- struct ip *ip;
memset(buffer, 0, 10000);
- int sendlen = sizeof(struct ip) + pim_msg_size;
-
- msg_start = buffer + sizeof(struct ip);
- memcpy(msg_start, pim_msg, pim_msg_size);
header = (struct pim_msg_header *)pim_msg;
/*
@@ -618,7 +634,11 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
break;
}
- ip = (struct ip *)buffer;
+#if PIM_IPV == 4
+ struct ip *ip = (struct ip *)buffer;
+ struct sockaddr_in to = {};
+ int sendlen = sizeof(*ip) + pim_msg_size;
+
ip->ip_id = htons(++ip_id);
ip->ip_hl = 5;
ip->ip_v = 4;
@@ -629,17 +649,34 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
ip->ip_ttl = ttl;
ip->ip_len = htons(sendlen);
- if (PIM_DEBUG_PIM_PACKETS) {
- char dst_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
- zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x", __func__,
- dst_str, ifname, pim_msg_size, header->checksum);
- }
-
- memset(&to, 0, sizeof(to));
to.sin_family = AF_INET;
to.sin_addr = dst;
tolen = sizeof(to);
+#else
+ struct ip6_hdr *ip = (struct ip6_hdr *)buffer;
+ struct sockaddr_in6 to = {};
+ int sendlen = sizeof(*ip) + pim_msg_size;
+
+ ip->ip6_flow = 0;
+ ip->ip6_vfc = (6 << 4) | (IPTOS_PREC_INTERNETCONTROL >> 4);
+ ip->ip6_plen = htons(pim_msg_size);
+ ip->ip6_nxt = PIM_IP_PROTO_PIM;
+ ip->ip6_hlim = ttl;
+ ip->ip6_src = src;
+ ip->ip6_dst = dst;
+
+ to.sin6_family = AF_INET6;
+ to.sin6_addr = dst;
+ tolen = sizeof(to);
+#endif
+
+ msg_start = buffer + sizeof(*ip);
+ memcpy(msg_start, pim_msg, pim_msg_size);
+
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("%s: to %pPA on %s: msg_size=%d checksum=%x",
+ __func__, &dst, ifname, pim_msg_size,
+ header->checksum);
if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
pim_pkt_dump(__func__, pim_msg, pim_msg_size);
@@ -659,20 +696,16 @@ static int hello_send(struct interface *ifp, uint16_t holdtime)
pim_ifp = ifp->info;
- if (PIM_DEBUG_PIM_HELLO) {
- char dst_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str,
- sizeof(dst_str));
+ if (PIM_DEBUG_PIM_HELLO)
zlog_debug(
- "%s: to %s on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d",
- __func__, dst_str, ifp->name, holdtime,
- pim_ifp->pim_propagation_delay_msec,
+ "%s: to %pPA on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d",
+ __func__, &qpim_all_pim_routers_addr, ifp->name,
+ holdtime, pim_ifp->pim_propagation_delay_msec,
pim_ifp->pim_override_interval_msec,
PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPPRESSION(
pim_ifp->options),
pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
listcount(ifp->connected));
- }
pim_tlv_size = pim_hello_build_tlv(
ifp, pim_msg + PIM_PIM_MIN_LEN,
@@ -690,7 +723,9 @@ static int hello_send(struct interface *ifp, uint16_t holdtime)
assert(pim_msg_size >= PIM_PIM_MIN_LEN);
assert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
- pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_HELLO, false);
+ pim_msg_build_header(pim_ifp->primary_address,
+ qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
+ PIM_MSG_TYPE_HELLO, false);
if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
qpim_all_pim_routers_addr, pim_msg, pim_msg_size,