int ofp_term_global(void) { int rc = 0; uint16_t i; struct ofp_ifnet *ifnet; ofp_stop(); /* Terminate CLI thread*/ CHECK_ERROR(ofp_stop_cli_thread(), rc); #ifdef SP /* Terminate Netlink thread*/ if (shm->nl_thread_is_running) { odph_linux_pthread_join(&shm->nl_thread, 1); shm->nl_thread_is_running = 0; } #endif /* SP */ /* Cleanup interfaces: queues and pktios*/ for (i = 0; i < VXLAN_PORTS; i++) { ifnet = ofp_get_ifnet((uint16_t)i, 0); if (!ifnet) { OFP_ERR("Failed to locate interface for port %d", i); rc = -1; continue; } if (ifnet->if_state == OFP_IFT_STATE_FREE) continue; if (ifnet->pktio == ODP_PKTIO_INVALID) continue; OFP_INFO("Cleaning device '%s' addr %s", ifnet->if_name, ofp_print_mac((uint8_t *)ifnet->mac)); CHECK_ERROR(odp_pktio_stop(ifnet->pktio), rc); #ifdef SP close(ifnet->fd); odph_linux_pthread_join(ifnet->rx_tbl, 1); odph_linux_pthread_join(ifnet->tx_tbl, 1); ifnet->fd = -1; #endif /*SP*/ /* Multicasting. */ ofp_igmp_domifdetach(ifnet); ifnet->ii_inet.ii_igmp = NULL; if (ifnet->loopq_def != ODP_QUEUE_INVALID) { if (odp_queue_destroy(ifnet->loopq_def) < 0) { OFP_ERR("Failed to destroy loop queue for %s", ifnet->if_name); rc = -1; } ifnet->loopq_def = ODP_QUEUE_INVALID; } #ifdef SP if (ifnet->spq_def != ODP_QUEUE_INVALID) { cleanup_pkt_queue(ifnet->spq_def); if (odp_queue_destroy(ifnet->spq_def) < 0) { OFP_ERR("Failed to destroy slow path " "queue for %s", ifnet->if_name); rc = -1; } ifnet->spq_def = ODP_QUEUE_INVALID; } #endif /*SP*/ ifnet->outq_def = ODP_QUEUE_INVALID; if (ifnet->pktio != ODP_PKTIO_INVALID) { if (odp_pktio_close(ifnet->pktio) < 0) { OFP_ERR("Failed to destroy pktio for %s", ifnet->if_name); rc = -1; } ifnet->pktio = ODP_PKTIO_INVALID; } if (ifnet->inq_def != ODP_QUEUE_INVALID) { cleanup_pkt_queue(ifnet->inq_def); if (odp_queue_destroy(ifnet->inq_def) < 0) { OFP_ERR("Failed to destroy default input " "queue for %s", ifnet->if_name); rc = -1; } ifnet->inq_def = ODP_QUEUE_INVALID; } } CHECK_ERROR(ofp_clean_vxlan_interface_queue(), rc); if (ofp_term_post_global(SHM_PACKET_POOL_NAME)) { OFP_ERR("Failed to cleanup resources\n"); rc = -1; } return rc; }
/* for local debug */ void ofp_print_packet_buffer(const char *comment, uint8_t *p) { static int first = 1; FILE *f; struct ofp_ip *ip; uint16_t proto; char *g; /* * Filter "noise" */ #if 0 if (p[12] == 0x00 && p[13] == 0x27) return; if (p[12] == 0x01 && p[13] == 0x98) return; #endif if (first) { f = fopen(DEFAULT_DEBUG_TXT_FILE_NAME, "w"); fclose(f); first = 0; } f = fopen(DEFAULT_DEBUG_TXT_FILE_NAME, "a"); if (!f) return; static struct timeval tv0; struct timeval tv; gettimeofday(&tv, NULL); if (tv0.tv_sec == 0) tv0 = tv; int ms = (tv.tv_sec*1000+tv.tv_usec/1000) - (tv0.tv_sec*1000+tv0.tv_usec/1000); ofp_printf(f, "\n*************\n"); ofp_printf(f, "[%d] %s: %d.%03d\n", odp_cpu_id(), comment, ms/1000, ms%1000); ofp_printf(f, "%s ->%s\n ", ofp_print_mac(p+6), ofp_print_mac(p)); if (p[12] == 0x81 && p[13] == 0x00) { ofp_printf(f, "VLAN %d ", (p[14]<<8)|p[15]); p += 4; } if (p[12] == 0x88 && p[13] == 0x47) { uint8_t *label = p+14; int i; ofp_printf(f, "MPLS "); while (1) { ofp_printf(f, "[label=%d ttl=%d] ", label[0]*16*256 + label[1]*16 + label[2]/16, label[3]); if (label[2] & 1) break; label += 4; } if ((label[4] & 0xf0) == 0x40) { label[2] = 0x08; /* ipv4 */ label[3] = 0x00; } else { label[2] = 0x86; /* ipv6 */ label[3] = 0xdd; } label++; for (i = 0; i < 12; i++) *label-- = p[11 - i]; p = label+1; } if (p[12] == 0x08 && p[13] == 0x06) { print_arp(f, (char *)(p + L2_HEADER_NO_VLAN_SIZE)); } else if (p[12] == 0x86 && p[13] == 0xdd) { print_ipv6(f, (char *)(p + L2_HEADER_NO_VLAN_SIZE)); } else if (p[12] == 0x08 && p[13] == 0x00) { ip = (struct ofp_ip *)(p + L2_HEADER_NO_VLAN_SIZE); if (ip->ip_p == 47) { /* GRE */ g = ((char *)ip) + (ip->ip_hl << 2); g += print_gre(f, g, &proto); if (proto == 0x0800) print_ipv4(f, g); else if (proto == 0x86dd) print_ipv6(f, g); } else print_ipv4(f, (char *)(p + L2_HEADER_NO_VLAN_SIZE)); } else { ofp_printf(f, "UNKNOWN ETH PACKET TYPE 0x%02x%02x ", p[12], p[13]); } ofp_printf(f, "\n"); fclose(f); fflush(stdout); }
enum ofp_return_code ofp_arp_processing(odp_packet_t *pkt) { struct ofp_arphdr *arp; struct ofp_ifnet *dev = odp_packet_user_ptr(*pkt); struct ofp_ifnet *outdev = dev; uint16_t vlan = dev->vlan; uint8_t inner_from_mac[OFP_ETHER_ADDR_LEN]; uint32_t is_ours; arp = (struct ofp_arphdr *)odp_packet_l3_ptr(*pkt, NULL); if (odp_unlikely(arp == NULL)) { OFP_DBG("arp is NULL"); return OFP_PKT_DROP; } /* save the received arp info */ if (odp_be_to_cpu_16(arp->op) == OFP_ARPOP_REPLY) ofp_add_mac(dev, arp->ip_src, arp->eth_src); OFP_DBG("Device IP: %s, Packet Dest IP: %s", ofp_print_ip_addr(dev->ip_addr), ofp_print_ip_addr(arp->ip_dst)); /* Check for VXLAN interface */ if (odp_unlikely(ofp_if_type(dev) == OFP_IFT_VXLAN)) { ofp_vxlan_update_devices(*pkt, arp, &vlan, &dev, &outdev, inner_from_mac); } is_ours = dev->ip_addr && dev->ip_addr == (ofp_in_addr_t)(arp->ip_dst); if (!is_ours && !global_param->arp.check_interface) { /* This may be for some other local interface. */ uint32_t flags; struct ofp_nh_entry *nh; nh = ofp_get_next_hop(dev->vrf, arp->ip_dst, &flags); if (nh) is_ours = nh->flags & OFP_RTF_LOCAL; } /* on our interface an ARP request */ if (is_ours && odp_be_to_cpu_16(arp->op) == OFP_ARPOP_REQUEST) { struct ofp_arphdr tmp; struct ofp_ether_header tmp_eth; struct ofp_ether_vlan_header tmp_eth_vlan; void *l2_addr = odp_packet_l2_ptr(*pkt, NULL); struct ofp_ether_header *eth = (struct ofp_ether_header *)l2_addr; struct ofp_ether_vlan_header *eth_vlan = (struct ofp_ether_vlan_header *)l2_addr; ofp_add_mac(dev, arp->ip_src, arp->eth_src); if (vlan) tmp_eth_vlan = *eth_vlan; else tmp_eth = *eth; OFP_DBG("Reply to ARPOP_REQ from ip %s" #ifdef SP "on IF %d" #endif " mac %s ip %s", ofp_print_ip_addr(arp->ip_src), #ifdef SP dev->linux_index, #endif ofp_print_mac(dev->mac), ofp_print_ip_addr(arp->ip_dst)); tmp = *arp; tmp.ip_dst = arp->ip_src; tmp.ip_src = arp->ip_dst; memcpy(&tmp.eth_dst, &arp->eth_src, OFP_ETHER_ADDR_LEN); memcpy(&tmp.eth_src, dev->mac, OFP_ETHER_ADDR_LEN); tmp.op = odp_cpu_to_be_16(OFP_ARPOP_REPLY); *arp = tmp; if (vlan) { memcpy(tmp_eth_vlan.evl_dhost, &arp->eth_dst, OFP_ETHER_ADDR_LEN); memcpy(tmp_eth_vlan.evl_shost, &arp->eth_src, OFP_ETHER_ADDR_LEN); *eth_vlan = tmp_eth_vlan; } else { memcpy(tmp_eth.ether_dhost, &arp->eth_dst, OFP_ETHER_ADDR_LEN); memcpy(tmp_eth.ether_shost, &arp->eth_src, OFP_ETHER_ADDR_LEN); *eth = tmp_eth; } if (odp_unlikely(ofp_if_type(dev) == OFP_IFT_VXLAN)) { /* Restore the original vxlan header and update the addresses */ ofp_vxlan_restore_and_update_header (*pkt, outdev, inner_from_mac); } return send_pkt_out(outdev, *pkt); } return OFP_PKT_CONTINUE; }
enum ofp_return_code ofp_arp_processing(odp_packet_t pkt) { struct ofp_arphdr *arp; struct ofp_ifnet *dev = odp_packet_user_ptr(pkt); struct ofp_ifnet *outdev = dev; uint16_t vlan = dev->vlan; uint8_t inner_from_mac[OFP_ETHER_ADDR_LEN]; arp = (struct ofp_arphdr *)odp_packet_l3_ptr(pkt, NULL); if (odp_unlikely(arp == NULL)) { OFP_DBG("arp is NULL"); return OFP_PKT_DROP; } /* save the received arp info */ if (odp_be_to_cpu_16(arp->op) == OFP_ARPOP_REPLY) ofp_add_mac(dev, arp->ip_src, arp->eth_src); OFP_DBG("Device IP: %s, Packet Dest IP: %s", ofp_print_ip_addr(dev->ip_addr), ofp_print_ip_addr(arp->ip_dst)); /* Check for VXLAN interface */ if (odp_unlikely(!PHYS_PORT(dev->port))) { switch (dev->port) { case GRE_PORTS: /* Never happens. */ break; case VXLAN_PORTS: { ofp_vxlan_update_devices(arp, &vlan, &dev, &outdev, inner_from_mac); break; } } /* switch */ } /* on our interface an ARP request */ if ((dev->ip_addr) && dev->ip_addr == (ofp_in_addr_t)(arp->ip_dst) && odp_be_to_cpu_16(arp->op) == OFP_ARPOP_REQUEST) { struct ofp_arphdr tmp; struct ofp_ether_header tmp_eth; struct ofp_ether_vlan_header tmp_eth_vlan; void *l2_addr = odp_packet_l2_ptr(pkt, NULL); struct ofp_ether_header *eth = (struct ofp_ether_header *)l2_addr; struct ofp_ether_vlan_header *eth_vlan = (struct ofp_ether_vlan_header *)l2_addr; ofp_add_mac(dev, arp->ip_src, arp->eth_src); if (vlan) tmp_eth_vlan = *eth_vlan; else tmp_eth = *eth; OFP_DBG("Reply to ARPOP_REQ from ip %s" #ifdef SP "on IF %d" #endif " mac %s ip %s", ofp_print_ip_addr(arp->ip_src), #ifdef SP dev->linux_index, #endif ofp_print_mac(dev->mac), ofp_print_ip_addr(arp->ip_dst)); tmp = *arp; tmp.ip_dst = arp->ip_src; tmp.ip_src = arp->ip_dst; memcpy(&tmp.eth_dst, &arp->eth_src, OFP_ETHER_ADDR_LEN); memcpy(&tmp.eth_src, dev->mac, OFP_ETHER_ADDR_LEN); tmp.op = odp_cpu_to_be_16(OFP_ARPOP_REPLY); *arp = tmp; if (vlan) { memcpy(tmp_eth_vlan.evl_dhost, &arp->eth_dst, OFP_ETHER_ADDR_LEN); memcpy(tmp_eth_vlan.evl_shost, &arp->eth_src, OFP_ETHER_ADDR_LEN); *eth_vlan = tmp_eth_vlan; } else { memcpy(tmp_eth.ether_dhost, &arp->eth_dst, OFP_ETHER_ADDR_LEN); memcpy(tmp_eth.ether_shost, &arp->eth_src, OFP_ETHER_ADDR_LEN); *eth = tmp_eth; } if (odp_unlikely(!PHYS_PORT(dev->port))) { switch (dev->port) { case GRE_PORTS: /* Never happens. */ break; case VXLAN_PORTS: { /* Restore the original vxlan header and update the addresses */ ofp_vxlan_restore_and_update_header (pkt, outdev, inner_from_mac); break; } } /* switch */ } /* not phys port */ return send_pkt_out(outdev, pkt); } return OFP_PKT_CONTINUE; }