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
GetOutputInterface(uint32_t daddr)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
ForwardIPPacket(mtcp_manager_t mtcp,struct pkt_ctx * pctx)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
FillOutPacketIPContext(struct pkt_ctx * pctx,struct iphdr * iph,int ip_len)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 *
IPOutputStandalone(struct mtcp_manager * mtcp,uint16_t ip_id,uint32_t saddr,uint32_t daddr,uint16_t tcplen,struct pkt_ctx * pctx,uint32_t cur_ts)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 *
IPOutput(struct mtcp_manager * mtcp,tcp_stream * stream,uint16_t tcplen,struct pkt_ctx * pctx,uint32_t cur_ts)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