/* \brief 简单协议栈ARP/RARP协议处理模块 * * 处理ARP/RARP协议报文数据 * * \author Lu Qiuwen * \date 2016-10-21 */ #include #include #include #include #include #include #include #include static struct ether_addr broadcast_hwaddr = { { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF } }; static inline int __local_frame_filter(struct vdev * vdev, struct ether_addr * ether_addr) { if (is_broadcast_ether_addr(ether_addr)) return 1; if (is_same_ether_addr(&vdev->ether_addr, ether_addr)) return 1; return 0; } static inline int __local_inaddr_filter(struct vdev * vdev, struct in_addr * in_addr) { return (vdev->in_addr.s_addr == in_addr->s_addr); } static void arp_reply_entry(struct neighbour_manager * neigh_manager, struct vdev_instance* vdi, queue_id_t qid, struct rte_mbuf * mbuf, struct arp_hdr * arp_header) { struct in_addr * s_in_addr = (struct in_addr *)&arp_header->arp_data.arp_sip; struct in_addr * d_in_addr = (struct in_addr *)&arp_header->arp_data.arp_tip; struct ether_addr * s_eth_addr = (struct ether_addr *)&arp_header->arp_data.arp_sha; struct ether_addr * d_eth_addr = (struct ether_addr *)&arp_header->arp_data.arp_tha; // 检测目的IP地址、MAC地址是否是本机的 if (!__local_frame_filter(vdi->vdev, d_eth_addr)) goto invalid_frame; if (!__local_inaddr_filter(vdi->vdev, d_in_addr)) goto invalid_frame; // TODO: 错误处理 neigh_create_or_update(neigh_manager, *s_in_addr, s_eth_addr, vdi, 0); invalid_frame: return; } static void arp_request_entry(struct neighbour_manager * neigh_manager, struct vdev_instance * vdi, queue_id_t qid, struct rte_mbuf * mbuf, struct arp_hdr * arp_header) { struct in_addr * s_in_addr = (struct in_addr *)&arp_header->arp_data.arp_sip; struct in_addr * d_in_addr = (struct in_addr *)&arp_header->arp_data.arp_tip; struct ether_addr * s_eth_addr = (struct ether_addr *)&arp_header->arp_data.arp_sha; struct ether_addr * d_eth_addr = (struct ether_addr *)&arp_header->arp_data.arp_tha; // 过滤非广播报文和非目的MAC是本机的报文 if (!(is_zero_ether_addr(d_eth_addr) || __local_frame_filter(vdi->vdev, d_eth_addr))) goto done; // 根据广播的ARP报文,更新邻居表 neigh_create_or_update(neigh_manager, *s_in_addr, s_eth_addr, vdi, 0); // 对请求是本机的,进行响应 if (!__local_inaddr_filter(vdi->vdev, d_in_addr)) goto done; struct rte_mbuf * reply_mbuf = rte_pktmbuf_alloc(vdi->direct_pool); if (unlikely(reply_mbuf == NULL)) goto done; // 构造以太网头 struct ether_hdr * ether_hdr = (struct ether_hdr *)rte_pktmbuf_append( reply_mbuf, sizeof(struct ether_hdr)); ether_addr_copy(&vdi->vdev->ether_addr, ðer_hdr->s_addr); ether_addr_copy(&arp_header->arp_data.arp_sha, ðer_hdr->d_addr); ether_hdr->ether_type = ntohs(ETHER_TYPE_ARP); // 构造ARP应答 struct arp_hdr * reply_arp_hdr = (struct arp_hdr *)rte_pktmbuf_append( reply_mbuf, sizeof(struct arp_hdr)); rte_memcpy(reply_arp_hdr, arp_header, sizeof(struct arp_hdr)); reply_arp_hdr->arp_op = ntohs(ARP_OP_REPLY); ether_addr_copy(ðer_hdr->s_addr, &reply_arp_hdr->arp_data.arp_sha); ether_addr_copy(ðer_hdr->d_addr, &reply_arp_hdr->arp_data.arp_tha); reply_arp_hdr->arp_data.arp_sip = vdi->vdev->in_addr.s_addr; reply_arp_hdr->arp_data.arp_tip = s_in_addr->s_addr; // 写应答包到线路 mrapp_packet_fast_send_burst(vdi, qid, &reply_mbuf, 1); done: return; } int arp_entry(struct mr_instance * instance, struct vdev_instance* vdi, queue_id_t qid, struct rte_mbuf* mbufs_in[], int nr_mbufs_in) { int handled_packets = 0; for (int i = 0; i < nr_mbufs_in; i++) { struct rte_mbuf * mbuf = mbufs_in[i]; if (unlikely(mbuf == NULL)) continue; struct ether_hdr * eth_hdr = rte_pktmbuf_mtod(mbuf, struct ether_hdr *); if (eth_hdr->ether_type != ntohs(ETHER_TYPE_ARP)) continue; struct arp_hdr * arp_hdr = rte_pktmbuf_mtod_offset( mbuf, struct arp_hdr *, sizeof(struct ether_hdr)); if (arp_hdr->arp_op == ntohs(ARP_OP_REQUEST)) arp_request_entry(instance->neigh, vdi, qid, mbuf, arp_hdr); else if (arp_hdr->arp_op == ntohs(ARP_OP_REPLY)) arp_reply_entry(instance->neigh, vdi, qid, mbuf, arp_hdr); handled_packets++; } return handled_packets; } int arp_request_send(struct vdev_instance* vdi, queue_id_t qid, struct in_addr in_addr) { struct vdev * dev_info = vdi->vdev; if (unlikely(dev_info->enable == 0)) { MR_DEBUG("Send ARP request on disable device %s, failed.", dev_info->symbol); return -EINVAL; } if (unlikely(vdi->nr_txstream == 0)) { MR_DEBUG("Send ARP request on recieve only device %s, failed.", dev_info->symbol); return -EINVAL; } struct ether_addr * src_hwaddr = &dev_info->ether_addr; struct ether_addr * dst_hwaddr = &broadcast_hwaddr; struct in_addr in_addr_src = dev_info->in_addr; struct rte_mbuf * req_mbuf = rte_pktmbuf_alloc(vdi->direct_pool); if (unlikely(req_mbuf == NULL)) return -ENOBUFS; // 构造以太网头 struct ether_hdr * ether_hdr = (struct ether_hdr *)rte_pktmbuf_append( req_mbuf, sizeof(struct ether_hdr)); ether_addr_copy(src_hwaddr, ðer_hdr->s_addr); ether_addr_copy(dst_hwaddr, ðer_hdr->d_addr); ether_hdr->ether_type = htons(ETHER_TYPE_ARP); // 构造ARP请求报文 struct arp_hdr * arp_hdr = (struct arp_hdr *)rte_pktmbuf_append( req_mbuf, sizeof(struct arp_hdr)); arp_hdr->arp_hrd = htons(ARP_HRD_ETHER); arp_hdr->arp_pro = htons(ETHER_TYPE_IPv4); arp_hdr->arp_hln = 6; arp_hdr->arp_pln = 4; arp_hdr->arp_op = htons(ARP_OP_REQUEST); arp_hdr->arp_data.arp_sip = in_addr_src.s_addr; arp_hdr->arp_data.arp_tip = in_addr.s_addr; ether_addr_copy(src_hwaddr, &arp_hdr->arp_data.arp_sha); memset(&arp_hdr->arp_data.arp_tha, 0, sizeof(arp_hdr->arp_data.arp_tha)); // 写数据包到线路 mrapp_packet_fast_send_burst(vdi, qid, &req_mbuf, 1); return 0; }