xref: /mOS-networking-stack/core/src/ip_out.c (revision dcdbbb98)
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 #ifdef PKTDUMP
103 	DumpPacket(mtcp,
104 			(char *)iph - sizeof(struct ethhdr),
105 			pctx->p.ip_len + sizeof(struct ethhdr),
106 			"OUT", pctx->out_ifidx);
107 #endif
108 }
109 /*----------------------------------------------------------------------------*/
110 inline void
111 FillOutPacketIPContext(struct pkt_ctx *pctx, struct iphdr *iph, int ip_len)
112 {
113 	pctx->p.iph = iph;
114 	pctx->p.ip_len = ip_len;
115 
116 	return;
117 }
118 /*----------------------------------------------------------------------------*/
119 uint8_t *
120 IPOutputStandalone(struct mtcp_manager *mtcp,
121 		uint16_t ip_id, uint32_t saddr, uint32_t daddr, uint16_t tcplen,
122 		struct pkt_ctx *pctx, uint32_t cur_ts)
123 {
124 	struct iphdr *iph;
125 	int nif;
126 	unsigned char * haddr;
127 	int rc = -1;
128 
129 	nif = GetOutputInterface(daddr);
130 	if (nif < 0)
131 		return NULL;
132 
133 	haddr = GetDestinationHWaddr(daddr);
134 	if (!haddr) {
135 #ifdef RUN_ARP
136 		/* ARP requests will not be created if it's a standalone middlebox */
137 		/* tcp will retry sending the packet later */
138 		if (!pctx->forward)
139 			RequestARP(mtcp, daddr, nif, mtcp->cur_ts);
140 #else
141 		uint8_t *da = (uint8_t *)&daddr;
142 		TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u "
143 			"is not in ARP table!\n",
144 			da[0], da[1], da[2], da[3]);
145 #endif
146 		return NULL;
147 	}
148 
149 	iph = (struct iphdr *)EthernetOutput(mtcp, pctx,
150 			ETH_P_IP, nif, haddr, tcplen + IP_HEADER_LEN, cur_ts);
151 	if (!iph) {
152 		return NULL;
153 	}
154 
155 	iph->ihl = IP_HEADER_LEN >> 2;
156 	iph->version = 4;
157 	iph->tos = 0;
158 	iph->tot_len = htons(IP_HEADER_LEN + tcplen);
159 	iph->id = htons(ip_id);
160 	iph->frag_off = htons(0x4000);	// no fragmentation
161 	iph->ttl = 64;
162 	iph->protocol = IPPROTO_TCP;
163 	iph->saddr = saddr;
164 	iph->daddr = daddr;
165 	iph->check = 0;
166 
167 	/* offload IP checkum if possible */
168 	if (likely(mtcp->iom->dev_ioctl != NULL))
169 		rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_IP_CSUM, iph);
170 	/* otherwise calculate IP checksum in S/W */
171 	if (rc == -1)
172 		iph->check = ip_fast_csum(iph, iph->ihl);
173 
174 	FillOutPacketIPContext(pctx, iph, tcplen + IP_HEADER_LEN);
175 
176 	return (uint8_t *)(iph + 1);
177 }
178 /*----------------------------------------------------------------------------*/
179 uint8_t *
180 IPOutput(struct mtcp_manager *mtcp, tcp_stream *stream, uint16_t tcplen,
181 			struct pkt_ctx *pctx, uint32_t cur_ts)
182 {
183 	struct iphdr *iph;
184 	int nif;
185 	unsigned char *haddr;
186 	int rc = -1;
187 
188 	if (stream->sndvar->nif_out >= 0) {
189 		nif = stream->sndvar->nif_out;
190 	} else {
191 		nif = GetOutputInterface(stream->daddr);
192 		stream->sndvar->nif_out = nif;
193 	}
194 
195 	haddr = GetDestinationHWaddr(stream->daddr);
196 	if (!haddr) {
197 #ifdef RUN_ARP
198 		/* if not found in the arp table, send arp request and return NULL */
199 		/* ARP requests will not be created if it's a standalone middlebox */
200 		/* tcp will retry sending the packet later */
201 		if (!pctx->forward)
202 			RequestARP(mtcp, stream->daddr, stream->sndvar->nif_out, mtcp->cur_ts);
203 #else
204 		uint8_t *da = (uint8_t *)&stream->daddr;
205 		TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u "
206 			  "is not in ARP table!\n",
207 			  da[0], da[1], da[2], da[3]);
208 #endif
209 		return NULL;
210 	}
211 	iph = (struct iphdr *)EthernetOutput(mtcp, pctx, ETH_P_IP,
212 			stream->sndvar->nif_out, haddr, tcplen + IP_HEADER_LEN, cur_ts);
213 	if (!iph) {
214 		return NULL;
215 	}
216 
217 	iph->ihl = IP_HEADER_LEN >> 2;
218 	iph->version = 4;
219 	iph->tos = 0;
220 	iph->tot_len = htons(IP_HEADER_LEN + tcplen);
221 	iph->id = htons(stream->sndvar->ip_id++);
222 	iph->frag_off = htons(0x4000);	// no fragmentation
223 	iph->ttl = 64;
224 	iph->protocol = IPPROTO_TCP;
225 	iph->saddr = stream->saddr;
226 	iph->daddr = stream->daddr;
227 	iph->check = 0;
228 
229 	/* offload IP checkum if possible */
230 	if (likely(mtcp->iom->dev_ioctl != NULL))
231 		rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_IP_CSUM, iph);
232 	/* otherwise calculate IP checksum in S/W */
233 	if (rc == -1)
234 		iph->check = ip_fast_csum(iph, iph->ihl);
235 
236 	FillOutPacketIPContext(pctx, iph, tcplen + IP_HEADER_LEN);
237 
238 	return (uint8_t *)(iph + 1);
239 }
240