xref: /mOS-networking-stack/core/src/arp.c (revision d8823779)
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
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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