xref: /mOS-networking-stack/core/src/ip_out.c (revision 9d76ceb8)
1 #include <string.h>
2 
3 #include "ip_out.h"
4 #include "ip_in.h"
5 #include "eth_out.h"
6 #include "arp.h"
7 #include "debug.h"
8 #include "config.h"
9 
10 /*----------------------------------------------------------------------------*/
11 inline int
12 GetOutputInterface(uint32_t daddr)
13 {
14 	int nif = -1;
15 	int i;
16 	int prefix = -1;
17 
18 	/* Longest prefix matching */
19 	for (i = 0; i < g_config.mos->route_table->num; i++) {
20 		if ((daddr & g_config.mos->route_table->ent[i]->mask)
21 			== g_config.mos->route_table->ent[i]->masked_ip) {
22 			if (g_config.mos->route_table->ent[i]->prefix > prefix) {
23 				nif = g_config.mos->route_table->ent[i]->nif;
24 				prefix = g_config.mos->route_table->ent[i]->prefix;
25 			}
26 		}
27 	}
28 
29 	if (nif < 0) {
30 		uint8_t *da = (uint8_t *)&daddr;
31 		TRACE_ERROR("[WARNING] No route to %u.%u.%u.%u\n",
32 				da[0], da[1], da[2], da[3]);
33 		assert(0);
34 	}
35 
36 	return nif;
37 }
38 /*----------------------------------------------------------------------------*/
39 void
40 ForwardIPPacket(mtcp_manager_t mtcp, struct pkt_ctx *pctx)
41 {
42 	unsigned char * haddr;
43 	struct iphdr *iph;
44 	uint32_t daddr = 0;
45 
46 	if (g_config.mos->nic_forward_table != NULL) {
47 		pctx->out_ifidx =
48 			g_config.mos->nic_forward_table->nic_fwd_table[pctx->p.in_ifidx];
49 		if (pctx->out_ifidx != -1) {
50 			haddr = pctx->p.ethh->h_dest;
51 			goto fast_tx;
52 		}
53 	}
54 
55 	/* set daddr for easy code writing */
56 	daddr = pctx->p.iph->daddr;
57 
58 	if (pctx->out_ifidx < 0) {
59 		pctx->out_ifidx = GetOutputInterface(pctx->p.iph->daddr);
60 		if (pctx->out_ifidx < 0) {
61 			return;
62 		}
63 	}
64 
65 	haddr = GetDestinationHWaddr(daddr);
66 	if (!haddr) {
67 #ifdef RUN_ARP
68 		/* ARP requests will not be created if it's a standalone middlebox */
69 		if (!pctx->forward)
70 			RequestARP(mtcp, daddr,
71 				   pctx->out_ifidx, pctx->p.cur_ts);
72 #else
73 		uint8_t *da = (uint8_t *)&(pctx->p.iph->daddr);
74 		TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u "
75 			  "is not in ARP table!\n",
76 			  da[0], da[1], da[2], da[3]);
77 #endif
78 		return;
79 	}
80 
81 #ifdef SHARE_IO_BUFFER
82 	if (likely(mtcp->iom->set_wptr != NULL)) {
83 		int i;
84 		for (i = 0; i < ETH_ALEN; i++) {
85 			pctx->p.ethh->h_source[i] = g_config.mos->netdev_table->ent[pctx->out_ifidx]->haddr[i];
86 			pctx->p.ethh->h_dest[i] = haddr[i];
87 		}
88 		mtcp->iom->set_wptr(mtcp->ctx, pctx->out_ifidx, pctx->p.in_ifidx, pctx->batch_index);
89 		return;
90 	}
91 #endif
92 
93  fast_tx:
94 	iph = (struct iphdr *) EthernetOutput (mtcp, pctx, ETH_P_IP,
95 			pctx->out_ifidx, haddr, pctx->p.ip_len, pctx->p.cur_ts);
96 	if (iph)
97 		memcpy(iph, pctx->p.iph, pctx->p.ip_len);
98 	else
99 		TRACE_ERROR("Failed to send a packet\n"
100 				"NULL = EthernetOutput(%p, %d, %d, %p, %d)\n",
101 				mtcp, ETH_P_IP, pctx->out_ifidx, haddr, pctx->p.ip_len);
102 
103 #ifdef PKTDUMP
104 	DumpPacket(mtcp,
105 			(char *)iph - sizeof(struct ethhdr),
106 			pctx->p.ip_len + sizeof(struct ethhdr),
107 			"OUT", pctx->out_ifidx);
108 #endif
109 
110 }
111 /*----------------------------------------------------------------------------*/
112 inline void
113 FillOutPacketIPContext(struct pkt_ctx *pctx, struct iphdr *iph, int ip_len)
114 {
115 	pctx->p.iph = iph;
116 	pctx->p.ip_len = ip_len;
117 
118 	return;
119 }
120 /*----------------------------------------------------------------------------*/
121 uint8_t *
122 IPOutputStandalone(struct mtcp_manager *mtcp,
123 		uint16_t ip_id, uint32_t saddr, uint32_t daddr, uint16_t tcplen,
124 		struct pkt_ctx *pctx, uint32_t cur_ts)
125 {
126 	struct iphdr *iph;
127 	int nif;
128 	unsigned char * haddr;
129 	int rc = -1;
130 
131 	nif = GetOutputInterface(daddr);
132 	if (nif < 0)
133 		return NULL;
134 
135 	haddr = GetDestinationHWaddr(daddr);
136 	if (!haddr) {
137 #ifdef RUN_ARP
138 		/* ARP requests will not be created if it's a standalone middlebox */
139 		/* tcp will retry sending the packet later */
140 		if (!pctx->forward)
141 			RequestARP(mtcp, daddr, nif, mtcp->cur_ts);
142 #else
143 		uint8_t *da = (uint8_t *)&daddr;
144 		TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u "
145 			"is not in ARP table!\n",
146 			da[0], da[1], da[2], da[3]);
147 #endif
148 		return NULL;
149 	}
150 
151 	iph = (struct iphdr *)EthernetOutput(mtcp, pctx,
152 			ETH_P_IP, nif, haddr, tcplen + IP_HEADER_LEN, cur_ts);
153 	if (!iph) {
154 		return NULL;
155 	}
156 
157 	iph->ihl = IP_HEADER_LEN >> 2;
158 	iph->version = 4;
159 	iph->tos = 0;
160 	iph->tot_len = htons(IP_HEADER_LEN + tcplen);
161 	iph->id = htons(ip_id);
162 	iph->frag_off = htons(0x4000);	// no fragmentation
163 	iph->ttl = 64;
164 	iph->protocol = IPPROTO_TCP;
165 	iph->saddr = saddr;
166 	iph->daddr = daddr;
167 	iph->check = 0;
168 
169 	/* offload IP checkum if possible */
170 	if (likely(mtcp->iom->dev_ioctl != NULL))
171 		rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_IP_CSUM, iph);
172 	/* otherwise calculate IP checksum in S/W */
173 	if (rc == -1)
174 		iph->check = ip_fast_csum(iph, iph->ihl);
175 
176 	FillOutPacketIPContext(pctx, iph, tcplen + IP_HEADER_LEN);
177 
178 	return (uint8_t *)(iph + 1);
179 }
180 /*----------------------------------------------------------------------------*/
181 uint8_t *
182 IPOutput(struct mtcp_manager *mtcp, tcp_stream *stream, uint16_t tcplen,
183 			struct pkt_ctx *pctx, uint32_t cur_ts)
184 {
185 	struct iphdr *iph;
186 	int nif;
187 	unsigned char *haddr;
188 	int rc = -1;
189 
190 	if (stream->sndvar->nif_out >= 0) {
191 		nif = stream->sndvar->nif_out;
192 	} else {
193 		nif = GetOutputInterface(stream->daddr);
194 		stream->sndvar->nif_out = nif;
195 	}
196 
197 	haddr = GetDestinationHWaddr(stream->daddr);
198 	if (!haddr) {
199 #ifdef RUN_ARP
200 		/* if not found in the arp table, send arp request and return NULL */
201 		/* ARP requests will not be created if it's a standalone middlebox */
202 		/* tcp will retry sending the packet later */
203 		if (!pctx->forward)
204 			RequestARP(mtcp, stream->daddr, stream->sndvar->nif_out, mtcp->cur_ts);
205 #else
206 		uint8_t *da = (uint8_t *)&stream->daddr;
207 		TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u "
208 			  "is not in ARP table!\n",
209 			  da[0], da[1], da[2], da[3]);
210 #endif
211 		return NULL;
212 	}
213 	iph = (struct iphdr *)EthernetOutput(mtcp, pctx, ETH_P_IP,
214 			stream->sndvar->nif_out, haddr, tcplen + IP_HEADER_LEN, cur_ts);
215 	if (!iph) {
216 		return NULL;
217 	}
218 
219 	iph->ihl = IP_HEADER_LEN >> 2;
220 	iph->version = 4;
221 	iph->tos = 0;
222 	iph->tot_len = htons(IP_HEADER_LEN + tcplen);
223 	iph->id = htons(stream->sndvar->ip_id++);
224 	iph->frag_off = htons(0x4000);	// no fragmentation
225 	iph->ttl = 64;
226 	iph->protocol = IPPROTO_TCP;
227 	iph->saddr = stream->saddr;
228 	iph->daddr = stream->daddr;
229 	iph->check = 0;
230 
231 	/* offload IP checkum if possible */
232 	if (likely(mtcp->iom->dev_ioctl != NULL))
233 		rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_IP_CSUM, iph);
234 	/* otherwise calculate IP checksum in S/W */
235 	if (rc == -1)
236 		iph->check = ip_fast_csum(iph, iph->ihl);
237 
238 	FillOutPacketIPContext(pctx, iph, tcplen + IP_HEADER_LEN);
239 
240 	return (uint8_t *)(iph + 1);
241 }
242