diff options
author | Donald Sharp <sharpd@cumulusnetworks.com> | 2016-09-08 14:42:04 +0200 |
---|---|---|
committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2016-12-22 02:26:08 +0100 |
commit | c305ed63eba226a78fff6179b2b9aef84826b728 (patch) | |
tree | d72c01c71fb17540f7e974b43690256be5664b73 /pimd/pim_pim.c | |
parent | pimd: Fix display of rp information in 'show run' (diff) | |
download | frr-c305ed63eba226a78fff6179b2b9aef84826b728.tar.xz frr-c305ed63eba226a78fff6179b2b9aef84826b728.zip |
pimd: Allow breaking up of packet.
When a packet is too large to send in one go, break it up.
Ticket: CM-12768
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
Diffstat (limited to 'pimd/pim_pim.c')
-rw-r--r-- | pimd/pim_pim.c | 84 |
1 files changed, 57 insertions, 27 deletions
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 4924acea7..8b34a4557 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -480,14 +480,62 @@ void pim_sock_reset(struct interface *ifp) static uint16_t ip_id = 0; -int pim_msg_send(int fd, - struct in_addr src, - struct in_addr dst, - uint8_t *pim_msg, - int pim_msg_size, - const char *ifname) + +static int +pim_msg_send_frame (int fd, char *buf, size_t len, + struct sockaddr *dst, size_t salen) +{ + struct ip *ip = (struct ip *)buf; + + while (sendto (fd, buf, len, MSG_DONTWAIT, dst, salen) < 0) + { + char dst_str[100]; + + 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) == 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); + } + } + + return -1; + break; + default: + pim_inet4_dump ("<dst?>", ip->ip_dst, dst_str, sizeof (dst_str)); + zlog_warn ("%s: sendto() failure to %s: fd=%d msg_size=%zd: errno=%d: %s", + __PRETTY_FUNCTION__, + dst_str, fd, len, + errno, safe_strerror(errno)); + break; + return -1; + } + } + + return 0; +} + +int +pim_msg_send(int fd, struct in_addr src, + struct in_addr dst, uint8_t *pim_msg, + int pim_msg_size, const char *ifname) { - ssize_t sent; struct sockaddr_in to; socklen_t tolen; unsigned char buffer[3000]; @@ -528,26 +576,8 @@ int pim_msg_send(int fd, pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size); } - sent = sendto(fd, buffer, sendlen, MSG_DONTWAIT, - (struct sockaddr *)&to, tolen); - if (sent != (ssize_t) sendlen) { - char dst_str[100]; - pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str)); - if (sent < 0) { - zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s", - __PRETTY_FUNCTION__, - dst_str, ifname, fd, pim_msg_size, - errno, safe_strerror(errno)); - } - else { - zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd", - __PRETTY_FUNCTION__, - dst_str, ifname, fd, - pim_msg_size, sent); - } - return -1; - } - + pim_msg_send_frame (fd, (char *)buffer, sendlen, + (struct sockaddr *)&to, tolen); return 0; } |