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