forked from sonic-net/sonic-buildimage
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
DHCP Relay: add option -si to support using src intf ip in relay (son…
…ic-net#7052) * add option si to support using src intf ip in relay
- Loading branch information
trzhang-msft
authored
Mar 19, 2021
1 parent
a3cafee
commit 8f83b33
Showing
2 changed files
with
193 additions
and
0 deletions.
There are no files selected for viewing
192 changes: 192 additions & 0 deletions
192
src/isc-dhcp/patch/0012-add-option-si-to-support-using-src-intf-ip-in-relay.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
From 16163f0693e30588216f0f280d5eba8bb53f7001 Mon Sep 17 00:00:00 2001 | ||
From: Tianrong Zhang <trzhang@microsoft.com> | ||
Date: Fri, 12 Mar 2021 23:30:56 -0800 | ||
Subject: [PATCH] add option -si to support using src intf ip in relay | ||
|
||
--- | ||
common/socket.c | 119 ++++++++++++++++++++++++++++++++++++----------- | ||
includes/dhcpd.h | 1 + | ||
relay/dhcrelay.c | 8 ++++ | ||
3 files changed, 100 insertions(+), 28 deletions(-) | ||
|
||
diff --git a/common/socket.c b/common/socket.c | ||
index 483eb9c..da9f501 100644 | ||
--- a/common/socket.c | ||
+++ b/common/socket.c | ||
@@ -83,6 +83,29 @@ static unsigned int global_v4_socket_references = 0; | ||
static int global_v4_socket = -1; | ||
#endif | ||
|
||
+/* | ||
+ * If set, uses "from" interface IP for packet Tx. | ||
+ * If not set, kernel chooses appropriate src ip for tx pkts | ||
+ */ | ||
+int use_src_intf_ip_for_tx; | ||
+ | ||
+/* | ||
+ * For both send_packet6() and receive_packet6() we need to allocate | ||
+ * space for the cmsg header information. We do this once and reuse | ||
+ * the buffer. We also need the control buf for send_packet() and | ||
+ * receive_packet() when we use a single socket and IP_PKTINFO to | ||
+ * send the packet out the correct interface. | ||
+ */ | ||
+static void *v4_control_buf = NULL; | ||
+static size_t v4_control_buf_len = 0; | ||
+ | ||
+static void | ||
+v4_allocate_cmsg_cbuf(void) { | ||
+ v4_control_buf_len = CMSG_SPACE(sizeof(struct in_pktinfo)); | ||
+ v4_control_buf = dmalloc(v4_control_buf_len, MDL); | ||
+ return; | ||
+} | ||
+ | ||
/* | ||
* If we can't bind() to a specific interface, then we can only have | ||
* a single socket. This variable insures that we don't try to listen | ||
@@ -712,37 +735,77 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto) | ||
struct hardware *hto; | ||
{ | ||
int result; | ||
-#ifdef IGNORE_HOSTUNREACH | ||
- int retry = 0; | ||
- do { | ||
-#endif | ||
-#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO) | ||
- struct in_pktinfo pktinfo; | ||
- | ||
- if (interface->ifp != NULL) { | ||
- memset(&pktinfo, 0, sizeof (pktinfo)); | ||
- pktinfo.ipi_ifindex = interface->ifp->ifr_index; | ||
- if (setsockopt(interface->wfdesc, IPPROTO_IP, | ||
- IP_PKTINFO, (char *)&pktinfo, | ||
- sizeof(pktinfo)) < 0) | ||
- log_fatal("setsockopt: IP_PKTINFO: %m"); | ||
+ struct msghdr m; | ||
+ struct iovec v; | ||
+ struct sockaddr_in dst; | ||
+ struct in_pktinfo *pktinfo; | ||
+ struct cmsghdr *cmsg; | ||
+ unsigned int ifindex; | ||
+ | ||
+ /* | ||
+ * If necessary allocate space for the control message header. | ||
+ * The space is common between send and receive. | ||
+ */ | ||
+ | ||
+ if (v4_control_buf == NULL) { | ||
+ v4_allocate_cmsg_cbuf(); | ||
+ if (v4_control_buf == NULL) { | ||
+ log_error("send_packet: unable to allocate cmsg header"); | ||
+ return(ENOMEM); | ||
} | ||
-#endif | ||
- result = sendto (interface -> wfdesc, (char *)raw, len, 0, | ||
- (struct sockaddr *)to, sizeof *to); | ||
-#ifdef IGNORE_HOSTUNREACH | ||
- } while (to -> sin_addr.s_addr == htonl (INADDR_BROADCAST) && | ||
- result < 0 && | ||
- (errno == EHOSTUNREACH || | ||
- errno == ECONNREFUSED) && | ||
- retry++ < 10); | ||
-#endif | ||
+ } | ||
+ memset(v4_control_buf, 0, v4_control_buf_len); | ||
+ | ||
+ /* | ||
+ * Initialize our message header structure. | ||
+ */ | ||
+ memset(&m, 0, sizeof(m)); | ||
+ | ||
+ /* | ||
+ * Set the target address we're sending to. | ||
+ */ | ||
+ memcpy(&dst, to, sizeof(dst)); | ||
+ m.msg_name = &dst; | ||
+ m.msg_namelen = sizeof(dst); | ||
+ ifindex = if_nametoindex(interface->name); | ||
+ | ||
+ /* | ||
+ * Set the data buffer we're sending. (Using this wacky | ||
+ * "scatter-gather" stuff... we only have a single chunk | ||
+ * of data to send, so we declare a single vector entry.) | ||
+ */ | ||
+ v.iov_base = (char *)raw; | ||
+ v.iov_len = len; | ||
+ m.msg_iov = &v; | ||
+ m.msg_iovlen = 1; | ||
+ | ||
+ /* | ||
+ * Setting the interface is a bit more involved. | ||
+ * | ||
+ * We have to create a "control message", and set that to | ||
+ * define the IP packet information. We let he kernel decide | ||
+ * the source IP address unless 'use_src_intf_ip_for_tx' is | ||
+ * set, in which case we use the IP address of the ingress | ||
+ * interface we received the request on as the source IP. | ||
+ */ | ||
+ m.msg_control = v4_control_buf; | ||
+ m.msg_controllen = v4_control_buf_len; | ||
+ cmsg = CMSG_FIRSTHDR(&m); | ||
+ INSIST(cmsg != NULL); | ||
+ cmsg->cmsg_level = IPPROTO_IP; | ||
+ cmsg->cmsg_type = IP_PKTINFO; | ||
+ cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo)); | ||
+ pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); | ||
+ memset(pktinfo, 0, sizeof(*pktinfo)); | ||
+ pktinfo->ipi_ifindex = ifindex; | ||
+ if (use_src_intf_ip_for_tx) | ||
+ pktinfo->ipi_spec_dst = from; | ||
+ | ||
+ result = sendmsg(interface->wfdesc, &m, 0); | ||
if (result < 0) { | ||
- log_error ("send_packet: %m"); | ||
- if (errno == ENETUNREACH) | ||
- log_error ("send_packet: please consult README file%s", | ||
- " regarding broadcast address."); | ||
+ log_error("send_packet: %m"); | ||
} | ||
+ | ||
return result; | ||
} | ||
|
||
diff --git a/includes/dhcpd.h b/includes/dhcpd.h | ||
index 36cd518..0c25582 100644 | ||
--- a/includes/dhcpd.h | ||
+++ b/includes/dhcpd.h | ||
@@ -2660,6 +2660,7 @@ ssize_t send_fallback6(struct interface_info *, struct packet *, | ||
#endif | ||
|
||
#ifdef USE_SOCKET_SEND | ||
+extern int use_src_intf_ip_for_tx; | ||
void if_reinitialize_send (struct interface_info *); | ||
void if_register_send (struct interface_info *); | ||
void if_deregister_send (struct interface_info *); | ||
diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c | ||
index 221106a..c44a79d 100644 | ||
--- a/relay/dhcrelay.c | ||
+++ b/relay/dhcrelay.c | ||
@@ -97,6 +97,12 @@ struct downstream_intf_list { | ||
isc_boolean_t use_if_id = ISC_FALSE; | ||
#endif | ||
|
||
+/* | ||
+ * If not set, kernel chooses what the src ip is. | ||
+ * If set, uses "from" interface IP for packet Tx. | ||
+ */ | ||
+extern int use_src_intf_ip_for_tx = 0; | ||
+ | ||
/* Maximum size of a packet with agent options added. */ | ||
int dhcp_max_agent_option_packet_length = DHCP_MTU_MIN; | ||
|
||
@@ -431,6 +437,8 @@ main(int argc, char **argv) { | ||
#endif | ||
} else if (!strcmp(argv[i], "-d")) { | ||
/* no_daemon = 1; */ | ||
+ } else if (!strcmp(argv[i], "-si")) { | ||
+ use_src_intf_ip_for_tx = 1; | ||
} else if (!strcmp(argv[i], "-q")) { | ||
quiet = 1; | ||
quiet_interface_discovery = 1; | ||
-- | ||
2.17.1 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters