1 #include <stdint.h>
2 #include <string.h>
3 #include <sys/types.h>
4
5 #include "mtcp.h"
6 #include "arp.h"
7 #include "eth_out.h"
8 #include "debug.h"
9 #include "config.h"
10
11 #define ARP_PAD_LEN 18
12 #define ARP_HEAD_LEN 8
13 #define TS_GEQ(a, b) ((int32_t)((a)-(b)) >= 0)
14 #define SEC_TO_TS(a) (a * 1000)
15
16 /*----------------------------------------------------------------------------*/
17 enum arp_hrd_format
18 {
19 arp_hrd_ethernet = 1
20 };
21 /*----------------------------------------------------------------------------*/
22 enum arp_opcode
23 {
24 arp_op_request = 1,
25 arp_op_reply = 2,
26 };
27 /*----------------------------------------------------------------------------*/
28 struct arphdr
29 {
30 uint16_t ar_hrd; /* hardware address format */
31 uint16_t ar_pro; /* protocol address format */
32 uint8_t ar_hln; /* hardware address length */
33 uint8_t ar_pln; /* protocol address length */
34 uint16_t ar_op; /* arp opcode */
35
36 uint8_t ar_sha[ETH_ALEN]; /* sender hardware address */
37 uint32_t ar_sip; /* sender ip address */
38 uint8_t ar_tha[ETH_ALEN]; /* targe hardware address */
39 uint32_t ar_tip; /* target ip address */
40
41 uint8_t pad[ARP_PAD_LEN];
42 } __attribute__ ((packed));
43 /*----------------------------------------------------------------------------*/
44 struct arp_queue_entry
45 {
46 uint32_t ip;
47 int nif_out;
48 uint32_t ts_out;
49
50 TAILQ_ENTRY(arp_queue_entry) arp_link;
51 };
52 /*----------------------------------------------------------------------------*/
53 struct arp_manager
54 {
55 TAILQ_HEAD (, arp_queue_entry) list;
56 pthread_mutex_t lock;
57 };
58 /*----------------------------------------------------------------------------*/
59 struct arp_manager g_arpm;
60 /*----------------------------------------------------------------------------*/
61 void
62 DumpARPPacket(struct arphdr *arph);
63 /*----------------------------------------------------------------------------*/
64 int
InitARPTable()65 InitARPTable()
66 {
67 TAILQ_INIT(&g_arpm.list);
68 pthread_mutex_init(&g_arpm.lock, NULL);
69
70 return 0;
71 }
72 /*----------------------------------------------------------------------------*/
73 unsigned char *
GetHWaddr(uint32_t ip)74 GetHWaddr(uint32_t ip)
75 {
76 int i;
77 unsigned char *haddr = NULL;
78 for (i = 0; i < g_config.mos->netdev_table->num; i++) {
79 if (ip == g_config.mos->netdev_table->ent[i]->ip_addr) {
80 haddr = g_config.mos->netdev_table->ent[i]->haddr;
81 break;
82 }
83 }
84
85 return haddr;
86 }
87 /*----------------------------------------------------------------------------*/
88 unsigned char *
GetDestinationHWaddr(uint32_t dip)89 GetDestinationHWaddr(uint32_t dip)
90 {
91 unsigned char *d_haddr = NULL;
92 int prefix = 0;
93 int i;
94
95 #ifdef L3_TRANSPARENT
96 static unsigned char none_haddr[ETH_ALEN] = {0,};
97 return none_haddr;
98 #endif
99
100 /* Longest prefix matching */
101 for (i = 0; i < g_config.mos->arp_table->num; i++) {
102 if (g_config.mos->arp_table->ent[i]->prefix == 1) {
103 if (g_config.mos->arp_table->ent[i]->ip == dip) {
104 d_haddr = g_config.mos->arp_table->ent[i]->haddr;
105 break;
106 }
107 } else {
108 if ((dip & g_config.mos->arp_table->ent[i]->mask) ==
109 g_config.mos->arp_table->ent[i]->masked_ip) {
110
111 if (g_config.mos->arp_table->ent[i]->prefix > prefix) {
112 d_haddr = g_config.mos->arp_table->ent[i]->haddr;
113 prefix = g_config.mos->arp_table->ent[i]->prefix;
114 }
115 }
116 }
117 }
118
119 return d_haddr;
120 }
121 /*----------------------------------------------------------------------------*/
122 static int
ARPOutput(struct mtcp_manager * mtcp,int nif,int opcode,uint32_t dst_ip,unsigned char * dst_haddr,unsigned char * target_haddr)123 ARPOutput(struct mtcp_manager *mtcp, int nif, int opcode,
124 uint32_t dst_ip, unsigned char *dst_haddr,
125 unsigned char *target_haddr)
126 {
127 if (!dst_haddr)
128 return -1;
129
130 /* Allocate a buffer */
131 struct arphdr *arph = (struct arphdr *)EthernetOutput(mtcp, NULL,
132 ETH_P_ARP, nif, dst_haddr, sizeof(struct arphdr), 0);
133 if (!arph) {
134 return -1;
135 }
136
137 /* Fill arp header */
138 arph->ar_hrd = htons(arp_hrd_ethernet);
139 arph->ar_pro = htons(ETH_P_IP);
140 arph->ar_hln = ETH_ALEN;
141 arph->ar_pln = 4;
142 arph->ar_op = htons(opcode);
143
144 /* Fill arp body */
145 arph->ar_sip = g_config.mos->netdev_table->ent[nif]->ip_addr;
146 arph->ar_tip = dst_ip;
147
148 memcpy(arph->ar_sha, g_config.mos->netdev_table->ent[nif]->haddr, arph->ar_hln);
149 if (target_haddr) {
150 memcpy(arph->ar_tha, target_haddr, arph->ar_hln);
151 } else {
152 memcpy(arph->ar_tha, dst_haddr, arph->ar_hln);
153 }
154 memset(arph->pad, 0, ARP_PAD_LEN);
155
156 #if DBGMSG
157 DumpARPPacket(arph);
158 #endif
159
160 return 0;
161 }
162 /*----------------------------------------------------------------------------*/
163 int
RegisterARPEntry(uint32_t ip,const unsigned char * haddr)164 RegisterARPEntry(uint32_t ip, const unsigned char *haddr)
165 {
166 int idx = g_config.mos->arp_table->num;
167 g_config.mos->arp_table->ent[idx] = calloc(1, sizeof(struct _arp_entry));
168 if (!g_config.mos->arp_table->ent[idx])
169 exit(0);
170 g_config.mos->arp_table->ent[idx]->prefix = 32;
171 g_config.mos->arp_table->ent[idx]->ip = ip;
172 memcpy(g_config.mos->arp_table->ent[idx]->haddr, haddr, ETH_ALEN);
173 g_config.mos->arp_table->ent[idx]->mask = -1;
174 g_config.mos->arp_table->ent[idx]->masked_ip = ip;
175
176 g_config.mos->arp_table->num = idx + 1;
177
178 TRACE_CONFIG("Learned new arp entry.\n");
179 PrintARPTable();
180
181 return 0;
182 }
183 /*----------------------------------------------------------------------------*/
184 void
RequestARP(mtcp_manager_t mtcp,uint32_t ip,int nif,uint32_t cur_ts)185 RequestARP(mtcp_manager_t mtcp, uint32_t ip, int nif, uint32_t cur_ts)
186 {
187 struct arp_queue_entry *ent;
188 unsigned char haddr[ETH_ALEN];
189 unsigned char taddr[ETH_ALEN];
190
191 pthread_mutex_lock(&g_arpm.lock);
192 /* if the arp request is in progress, return */
193 TAILQ_FOREACH(ent, &g_arpm.list, arp_link) {
194 if (ent->ip == ip) {
195 pthread_mutex_unlock(&g_arpm.lock);
196 return;
197 }
198 }
199
200 ent = (struct arp_queue_entry *)calloc(1, sizeof(struct arp_queue_entry));
201 if (ent == NULL) {
202 TRACE_ERROR("Unable to allocate memory for ARP entry!\n");
203 exit(EXIT_FAILURE);
204 }
205 ent->ip = ip;
206 ent->nif_out = nif;
207 ent->ts_out = cur_ts;
208 TAILQ_INSERT_TAIL(&g_arpm.list, ent, arp_link);
209 pthread_mutex_unlock(&g_arpm.lock);
210
211 /* else, broadcast arp request */
212 memset(haddr, 0xFF, ETH_ALEN);
213 memset(taddr, 0x00, ETH_ALEN);
214 ARPOutput(mtcp, nif, arp_op_request, ip, haddr, taddr);
215 }
216 /*----------------------------------------------------------------------------*/
217 static int
ProcessARPRequest(mtcp_manager_t mtcp,struct arphdr * arph,int nif,uint32_t cur_ts)218 ProcessARPRequest(mtcp_manager_t mtcp,
219 struct arphdr *arph, int nif, uint32_t cur_ts)
220 {
221 unsigned char *temp;
222
223 /* register the arp entry if not exist */
224 temp = GetDestinationHWaddr(arph->ar_sip);
225 if (!temp) {
226 RegisterARPEntry(arph->ar_sip, arph->ar_sha);
227 }
228
229 /* send arp reply */
230 ARPOutput(mtcp, nif, arp_op_reply, arph->ar_sip, arph->ar_sha, NULL);
231
232 return 0;
233 }
234 /*----------------------------------------------------------------------------*/
235 static int
ProcessARPReply(mtcp_manager_t mtcp,struct arphdr * arph,uint32_t cur_ts)236 ProcessARPReply(mtcp_manager_t mtcp, struct arphdr *arph, uint32_t cur_ts)
237 {
238 unsigned char *temp;
239 struct arp_queue_entry *ent;
240
241 /* register the arp entry if not exist */
242 temp = GetDestinationHWaddr(arph->ar_sip);
243 if (!temp) {
244 RegisterARPEntry(arph->ar_sip, arph->ar_sha);
245 }
246
247 /* remove from the arp request queue */
248 pthread_mutex_lock(&g_arpm.lock);
249 TAILQ_FOREACH(ent, &g_arpm.list, arp_link) {
250 if (ent->ip == arph->ar_sip) {
251 TAILQ_REMOVE(&g_arpm.list, ent, arp_link);
252 free(ent);
253 break;
254 }
255 }
256 pthread_mutex_unlock(&g_arpm.lock);
257
258 return 0;
259 }
260 /*----------------------------------------------------------------------------*/
261 int
ProcessARPPacket(mtcp_manager_t mtcp,uint32_t cur_ts,const int ifidx,unsigned char * pkt_data,int len)262 ProcessARPPacket(mtcp_manager_t mtcp, uint32_t cur_ts,
263 const int ifidx, unsigned char *pkt_data, int len)
264 {
265 struct arphdr *arph = (struct arphdr *)(pkt_data + sizeof(struct ethhdr));
266 int i;
267 int to_me = FALSE;
268
269 /* process the arp messages destined to me */
270 for (i = 0; i < g_config.mos->netdev_table->num; i++) {
271 if (arph->ar_tip == g_config.mos->netdev_table->ent[i]->ip_addr) {
272 to_me = TRUE;
273 }
274 }
275
276 if (!to_me)
277 return TRUE;
278
279 #if DBGMSG
280 DumpARPPacket(arph);
281 #endif
282
283 switch (ntohs(arph->ar_op)) {
284 case arp_op_request:
285 ProcessARPRequest(mtcp, arph, ifidx, cur_ts);
286 break;
287
288 case arp_op_reply:
289 ProcessARPReply(mtcp, arph, cur_ts);
290 break;
291
292 default:
293 break;
294 }
295
296 return TRUE;
297 }
298 /*----------------------------------------------------------------------------*/
299 // Publish my address
300 void
PublishARP(mtcp_manager_t mtcp)301 PublishARP(mtcp_manager_t mtcp)
302 {
303 int i;
304 for (i = 0; i < g_config.mos->netdev_table->num; i++) {
305 ARPOutput(mtcp, g_config.mos->netdev_table->ent[i]->ifindex, arp_op_request, 0, NULL, NULL);
306 }
307 }
308 /*----------------------------------------------------------------------------*/
309 /* ARPTimer: wakes up every milisecond and check the ARP timeout */
310 /* timeout is set to 1 second */
311 /*----------------------------------------------------------------------------*/
312 void
ARPTimer(mtcp_manager_t mtcp,uint32_t cur_ts)313 ARPTimer(mtcp_manager_t mtcp, uint32_t cur_ts)
314 {
315 struct arp_queue_entry *ent, *ent_tmp;
316
317 /* if the arp requet is timed out, retransmit */
318 pthread_mutex_lock(&g_arpm.lock);
319 TAILQ_FOREACH_SAFE(ent, &g_arpm.list, arp_link, ent_tmp) {
320 if (TS_GEQ(cur_ts, ent->ts_out + SEC_TO_TS(ARP_TIMEOUT_SEC))) {
321 TRACE_INFO("[CPU%2d] ARP request timed out.\n",
322 mtcp->ctx->cpu);
323 TAILQ_REMOVE(&g_arpm.list, ent, arp_link);
324 free(ent);
325 }
326 }
327 pthread_mutex_unlock(&g_arpm.lock);
328 }
329 /*----------------------------------------------------------------------------*/
330 void
PrintARPTable()331 PrintARPTable()
332 {
333 int i;
334
335 /* print out process start information */
336 TRACE_CONFIG("ARP Table:\n");
337 for (i = 0; i < g_config.mos->arp_table->num; i++) {
338
339 uint8_t *da = (uint8_t *)&g_config.mos->arp_table->ent[i]->ip;
340
341 TRACE_CONFIG("IP addr: %u.%u.%u.%u, "
342 "dst_hwaddr: %02X:%02X:%02X:%02X:%02X:%02X\n",
343 da[0], da[1], da[2], da[3],
344 g_config.mos->arp_table->ent[i]->haddr[0],
345 g_config.mos->arp_table->ent[i]->haddr[1],
346 g_config.mos->arp_table->ent[i]->haddr[2],
347 g_config.mos->arp_table->ent[i]->haddr[3],
348 g_config.mos->arp_table->ent[i]->haddr[4],
349 g_config.mos->arp_table->ent[i]->haddr[5]);
350 }
351 if (g_config.mos->arp_table->num == 0)
352 TRACE_CONFIG("(blank)\n");
353
354 TRACE_CONFIG("----------------------------------------------------------"
355 "-----------------------\n");
356 }
357 /*----------------------------------------------------------------------------*/
358 void
DumpARPPacket(struct arphdr * arph)359 DumpARPPacket(struct arphdr *arph)
360 {
361 uint8_t *t;
362
363 fprintf(stderr, "ARP header: \n");
364 fprintf(stderr, "Hareware type: %d (len: %d), "
365 "protocol type: %d (len: %d), opcode: %d\n",
366 ntohs(arph->ar_hrd), arph->ar_hln,
367 ntohs(arph->ar_pro), arph->ar_pln, ntohs(arph->ar_op));
368 t = (uint8_t *)&arph->ar_sip;
369 fprintf(stderr, "Sender IP: %u.%u.%u.%u, "
370 "haddr: %02X:%02X:%02X:%02X:%02X:%02X\n",
371 t[0], t[1], t[2], t[3],
372 arph->ar_sha[0], arph->ar_sha[1], arph->ar_sha[2],
373 arph->ar_sha[3], arph->ar_sha[4], arph->ar_sha[5]);
374 t = (uint8_t *)&arph->ar_tip;
375 fprintf(stderr, "Target IP: %u.%u.%u.%u, "
376 "haddr: %02X:%02X:%02X:%02X:%02X:%02X\n",
377 t[0], t[1], t[2], t[3],
378 arph->ar_tha[0], arph->ar_tha[1], arph->ar_tha[2],
379 arph->ar_tha[3], arph->ar_tha[4], arph->ar_tha[5]);
380 }
381 /*----------------------------------------------------------------------------*/
382 void
ForwardARPPacket(struct mtcp_manager * mtcp,struct pkt_ctx * pctx)383 ForwardARPPacket(struct mtcp_manager *mtcp, struct pkt_ctx *pctx)
384 {
385 unsigned char *haddr;
386
387 if (g_config.mos->nic_forward_table != NULL) {
388 pctx->out_ifidx =
389 g_config.mos->nic_forward_table->nic_fwd_table[pctx->p.in_ifidx];
390 if (pctx->out_ifidx != -1) {
391 haddr = pctx->p.ethh->h_dest;
392 struct arphdr *arph = (struct arphdr *)
393 EthernetOutput(mtcp, NULL, ETH_P_ARP,
394 pctx->out_ifidx, haddr,
395 sizeof(struct arphdr), 0);
396 if (!arph)
397 return;
398 memcpy(arph, (pctx->p.ethh + 1), sizeof(struct arphdr));
399 }
400 }
401 }
402 /*----------------------------------------------------------------------------*/
403