static void print_arp(FILE *f, char *p) { ofp_printf(f, "ARP %d %s -> %s ", p[7], /* opcode */ ofp_print_ip_addr(*((uint32_t *)(p+14))), /* sender IP */ ofp_print_ip_addr(*((uint32_t *)(p+24)))); /* target IP */ }
/** * Prinf usage information */ static void usage(char *progname) { printf("\n" "Usage: %s OPTIONS\n" " E.g. %s -i eth1,eth2,eth3\n" "\n" "ODPFastpath application.\n" "\n" "Mandatory OPTIONS:\n" " -i, --interface Eth interfaces (comma-separated, no spaces)\n" "\n" "Optional OPTIONS\n" " -c, --count <number> Core count.\n" " -r, --root <web root folder> Webserver root folder.\n" "\tDefault: "DEFAULT_ROOT_DIRECTORY"\n" " -l, --laddr <IPv4 address> IPv4 address were webserver binds.\n" "\tDefault: %s\n" " -p, --lport <port> Port address were webserver binds.\n" "\tDefault: %d\n" " -h, --help Display help and exit.\n" "\n", NO_PATH(progname), NO_PATH(progname), ofp_print_ip_addr(DEFAULT_BIND_ADDRESS), DEFAULT_BIND_PORT ); }
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_ipv4_processing(odp_packet_t *pkt) { int frag_res = 0, res; int protocol = IS_IPV4; uint32_t flags; struct ofp_ip *ip; struct ofp_nh_entry *nh; struct ofp_ifnet *dev = odp_packet_user_ptr(*pkt); uint32_t is_ours; ip = (struct ofp_ip *)odp_packet_l3_ptr(*pkt, NULL); if (odp_unlikely(ip == NULL)) { OFP_DBG("ip is NULL"); return OFP_PKT_DROP; } if (odp_unlikely(ofp_if_type(dev) == OFP_IFT_VXLAN)) { struct ofp_packet_user_area *ua; /* Look for the correct device. */ ua = ofp_packet_user_area(*pkt); dev = ofp_get_ifnet(VXLAN_PORTS, ua->vxlan.vni); if (!dev) return OFP_PKT_DROP; } if (odp_unlikely(ip->ip_v != OFP_IPVERSION)) return OFP_PKT_DROP; if (ofp_packet_user_area(*pkt)->chksum_flags & OFP_L3_CHKSUM_STATUS_VALID) { switch (odp_packet_l3_chksum_status(*pkt)) { case ODP_PACKET_CHKSUM_OK: break; case ODP_PACKET_CHKSUM_UNKNOWN: /* Checksum was not validated by HW */ if (odp_unlikely(ofp_cksum_iph(ip, ip->ip_hl))) return OFP_PKT_DROP; break; case ODP_PACKET_CHKSUM_BAD: return OFP_PKT_DROP; break; } ofp_packet_user_area(*pkt)->chksum_flags &= ~OFP_L3_CHKSUM_STATUS_VALID; } else if (odp_unlikely(ofp_cksum_iph(ip, ip->ip_hl))) return OFP_PKT_DROP; /* TODO: handle broadcast */ if (dev->bcast_addr == ip->ip_dst.s_addr) return OFP_PKT_DROP; OFP_DBG("Device IP: %s, Packet Dest IP: %s", ofp_print_ip_addr(dev->ip_addr), ofp_print_ip_addr(ip->ip_dst.s_addr)); is_ours = dev->ip_addr == ip->ip_dst.s_addr || OFP_IN_MULTICAST(odp_be_to_cpu_32(ip->ip_dst.s_addr)); if (!is_ours) { /* This may be for some other local interface. */ nh = ofp_get_next_hop(dev->vrf, ip->ip_dst.s_addr, &flags); if (nh) is_ours = nh->flags & OFP_RTF_LOCAL; } if (is_ours) { if (odp_be_to_cpu_16(ip->ip_off) & 0x3fff) { frag_res = pkt_reassembly(pkt); if (frag_res != OFP_PKT_CONTINUE) return frag_res; ip = (struct ofp_ip *)odp_packet_l3_ptr(*pkt, NULL); } OFP_HOOK(OFP_HOOK_LOCAL, *pkt, &protocol, &res); if (res != OFP_PKT_CONTINUE) { OFP_DBG("OFP_HOOK_LOCAL returned %d", res); return res; } OFP_HOOK(OFP_HOOK_LOCAL_IPv4, *pkt, NULL, &res); if (res != OFP_PKT_CONTINUE) { OFP_DBG("OFP_HOOK_LOCAL_IPv4 returned %d", res); return res; } return ipv4_transport_classifier(pkt, ip->ip_p); } OFP_HOOK(OFP_HOOK_FWD_IPv4, *pkt, nh, &res); if (res != OFP_PKT_CONTINUE) { OFP_DBG("OFP_HOOK_FWD_IPv4 returned %d", res); return res; } if (nh == NULL) { OFP_DBG("nh is NULL, vrf=%d dest=%x", dev->vrf, ip->ip_dst.s_addr); return OFP_PKT_CONTINUE; } if (ip->ip_ttl <= 1) { OFP_DBG("OFP_ICMP_TIMXCEED"); ofp_icmp_error(*pkt, OFP_ICMP_TIMXCEED, OFP_ICMP_TIMXCEED_INTRANS, 0, 0); return OFP_PKT_DROP; } /* * Decrement TTL and incrementally change the IP header checksum. */ ip->ip_ttl--; uint16_t a = ~odp_cpu_to_be_16(1 << 8); if (ip->ip_sum >= a) ip->ip_sum -= a; else ip->ip_sum += odp_cpu_to_be_16(1 << 8); #ifdef OFP_SEND_ICMP_REDIRECT /* 1. The interface on which the packet comes into the router is the * same interface on which the packet gets routed out. * 2. The subnet or network of the source IP address is on the same * subnet or network of the next-hop IP address of the routed packet. * 3. Stack configured to send redirects. */ #define INET_SUBNET_PREFIX(addr) \ (odp_be_to_cpu_32(addr) & ((~0) << (32 - dev->masklen))) if (nh->port == dev->port && (INET_SUBNET_PREFIX(ip->ip_src.s_addr) == INET_SUBNET_PREFIX(nh->gw))) { OFP_DBG("send OFP_ICMP_REDIRECT"); ofp_icmp_error(*pkt, OFP_ICMP_REDIRECT, OFP_ICMP_REDIRECT_HOST, nh->gw, 0); } #endif return ofp_ip_output_common_inline(*pkt, nh, 0); }
static void print_ipv4(FILE *f, char *p) { struct ofp_ip *iphdr = (struct ofp_ip *)p; struct ofp_icmp *icmp; struct ofp_udphdr *uh; struct ofp_tcphdr *th; /* if it's a non-first fragment, print only IPv4 information */ if ((odp_be_to_cpu_16(iphdr->ip_off) & 0x1fff) != 0) { ofp_printf(f, "IP fragment PKT len=%d %s -> %s ", odp_be_to_cpu_16(iphdr->ip_len), ofp_print_ip_addr(iphdr->ip_src.s_addr), ofp_print_ip_addr(iphdr->ip_dst.s_addr)); return; } if (iphdr->ip_p == OFP_IPPROTO_UDP) { uh = (struct ofp_udphdr *)(((uint8_t *)iphdr) + (iphdr->ip_hl<<2)); ofp_printf(f, "IP UDP PKT len=%d %s:%d -> %s:%d ", odp_be_to_cpu_16(uh->uh_ulen), ofp_print_ip_addr(iphdr->ip_src.s_addr), odp_be_to_cpu_16(uh->uh_sport), ofp_print_ip_addr(iphdr->ip_dst.s_addr), odp_be_to_cpu_16(uh->uh_dport)); } else if (iphdr->ip_p == OFP_IPPROTO_TCP) { th = (struct ofp_tcphdr *)(((uint8_t *)iphdr) + (iphdr->ip_hl<<2)); ofp_printf(f, "IP len=%d TCP %s:%d -> %s:%d\n" " seq=0x%x ack=0x%x off=%d\n flags=", odp_be_to_cpu_16(iphdr->ip_len), ofp_print_ip_addr(iphdr->ip_src.s_addr), odp_be_to_cpu_16(th->th_sport), ofp_print_ip_addr(iphdr->ip_dst.s_addr), odp_be_to_cpu_16(th->th_dport), odp_be_to_cpu_32(th->th_seq), odp_be_to_cpu_32(th->th_ack), th->th_off); if (th->th_flags & OFP_TH_FIN) ofp_printf(f, "F"); if (th->th_flags & OFP_TH_SYN) ofp_printf(f, "S"); if (th->th_flags & OFP_TH_RST) ofp_printf(f, "R"); if (th->th_flags & OFP_TH_PUSH) ofp_printf(f, "P"); if (th->th_flags & OFP_TH_ACK) ofp_printf(f, "A"); if (th->th_flags & OFP_TH_URG) ofp_printf(f, "U"); if (th->th_flags & OFP_TH_ECE) ofp_printf(f, "E"); if (th->th_flags & OFP_TH_CWR) ofp_printf(f, "C"); ofp_printf(f, " win=%u sum=0x%x urp=%u", odp_be_to_cpu_16(th->th_win), odp_be_to_cpu_16(th->th_sum), odp_be_to_cpu_16(th->th_urp)); int i; int len = odp_be_to_cpu_16(iphdr->ip_len); #if 0 if (odp_be_to_cpu_16(th->th_win) == 0) { /* wrong value */ ofp_printf(f, "\n---- th_win == 0, quit\n"); fflush(NULL); int *a = 0; *a = 8; } #endif if (len > 2000) { ofp_printf(f, "\nToo long data!\n"); int *a = 0, b = 8, c = 9; *a = b + c; } else if (0) { for (i = 0; i < len; i++) { if ((i & 0xf) == 0) ofp_printf(f, "\n"); ofp_printf(f, " %02x", (uint8_t)p[i]); } } } else if (iphdr->ip_p == OFP_IPPROTO_ICMP) { icmp = (struct ofp_icmp *)(((uint8_t *)iphdr) + (iphdr->ip_hl<<2)); switch (icmp->icmp_type) { case OFP_ICMP_ECHOREPLY: ofp_printf(f, "IP ICMP: echo reply %s -> %s id=%d seq=%d", ofp_print_ip_addr(iphdr->ip_src.s_addr), ofp_print_ip_addr(iphdr->ip_dst.s_addr), icmp->ofp_icmp_id, icmp->ofp_icmp_seq); break; case OFP_ICMP_UNREACH: ofp_printf(f, "IP ICMP: dest unreachable %s -> %s ", ofp_print_ip_addr(iphdr->ip_src.s_addr), ofp_print_ip_addr(iphdr->ip_dst.s_addr)); break; case OFP_ICMP_ECHO: ofp_printf(f, "IP ICMP: echo %s -> %s id=%d seq=%d", ofp_print_ip_addr(iphdr->ip_src.s_addr), ofp_print_ip_addr(iphdr->ip_dst.s_addr), icmp->ofp_icmp_id, icmp->ofp_icmp_seq); break; default: ofp_printf(f, "IP ICMP %d: code=%d %s -> %s ", icmp->icmp_type, icmp->icmp_code, ofp_print_ip_addr(iphdr->ip_src.s_addr), ofp_print_ip_addr(iphdr->ip_dst.s_addr)); } } else { ofp_printf(f, "IP PKT len=%d proto=%d %s -> %s ", odp_be_to_cpu_16(iphdr->ip_len), iphdr->ip_p, ofp_print_ip_addr(iphdr->ip_src.s_addr), ofp_print_ip_addr(iphdr->ip_dst.s_addr)); } }
enum ofp_return_code ofp_ipv4_processing(odp_packet_t pkt) { int res; int protocol = IS_IPV4; uint32_t flags; struct ofp_ip *ip; struct ofp_nh_entry *nh; struct ofp_ifnet *dev = odp_packet_user_ptr(pkt); uint32_t is_ours; ip = (struct ofp_ip *)odp_packet_l3_ptr(pkt, NULL); if (odp_unlikely(ip == NULL)) { OFP_DBG("ip is NULL"); return OFP_PKT_DROP; } if (odp_unlikely(!PHYS_PORT(dev->port))) { switch (dev->port) { case GRE_PORTS: /* Doesn't happen. */ break; case VXLAN_PORTS: { /* Look for the correct device. */ struct vxlan_user_data *saved = odp_packet_user_area(pkt); dev = ofp_get_ifnet(VXLAN_PORTS, saved->vni); if (!dev) return OFP_PKT_DROP; break; } } } #ifndef OFP_PERFORMANCE if (odp_unlikely(ip->ip_v != 4)) return OFP_PKT_DROP; if (odp_unlikely(ofp_cksum_buffer((uint16_t *) ip, ip->ip_hl<<2))) return OFP_PKT_DROP; /* TODO: handle broadcast */ if (dev->bcast_addr == ip->ip_dst.s_addr) return OFP_PKT_DROP; #endif OFP_DBG("Device IP: %s, Packet Dest IP: %s", ofp_print_ip_addr(dev->ip_addr), ofp_print_ip_addr(ip->ip_dst.s_addr)); is_ours = dev->ip_addr == ip->ip_dst.s_addr || OFP_IN_MULTICAST(odp_be_to_cpu_32(ip->ip_dst.s_addr)); if (!is_ours) { /* This may be for some other local interface. */ nh = ofp_get_next_hop(dev->vrf, ip->ip_dst.s_addr, &flags); if (nh) is_ours = nh->flags & OFP_RTF_LOCAL; } if (is_ours) { if (odp_be_to_cpu_16(ip->ip_off) & 0x3fff) { OFP_UPDATE_PACKET_STAT(rx_ip_frag, 1); pkt = ofp_ip_reass(pkt); if (pkt == ODP_PACKET_INVALID) return OFP_PKT_ON_HOLD; OFP_UPDATE_PACKET_STAT(rx_ip_reass, 1); ip = (struct ofp_ip *)odp_packet_l3_ptr(pkt, NULL); } OFP_HOOK(OFP_HOOK_LOCAL, pkt, &protocol, &res); if (res != OFP_PKT_CONTINUE) { OFP_DBG("OFP_HOOK_LOCAL returned %d", res); return res; } OFP_HOOK(OFP_HOOK_LOCAL_IPv4, pkt, NULL, &res); if (res != OFP_PKT_CONTINUE) { OFP_DBG("OFP_HOOK_LOCAL_IPv4 returned %d", res); return res; } return ipv4_transport_classifier(pkt, ip->ip_p); } OFP_HOOK(OFP_HOOK_FWD_IPv4, pkt, nh, &res); if (res != OFP_PKT_CONTINUE) { OFP_DBG("OFP_HOOK_FWD_IPv4 returned %d", res); return res; } if (nh == NULL) { OFP_DBG("nh is NULL, vrf=%d dest=%x", dev->vrf, ip->ip_dst.s_addr); return OFP_PKT_CONTINUE; } if (ip->ip_ttl <= 1) { OFP_DBG("OFP_ICMP_TIMXCEED"); ofp_icmp_error(pkt, OFP_ICMP_TIMXCEED, OFP_ICMP_TIMXCEED_INTRANS, 0, 0); return OFP_PKT_DROP; } /* * Decrement TTL and incrementally change the IP header checksum. */ ip->ip_ttl--; uint16_t a = ~odp_cpu_to_be_16(1 << 8); if (ip->ip_sum >= a) ip->ip_sum -= a; else ip->ip_sum += odp_cpu_to_be_16(1 << 8); #ifdef OFP_SEND_ICMP_REDIRECT /* 1. The interface on which the packet comes into the router is the * same interface on which the packet gets routed out. * 2. The subnet or network of the source IP address is on the same * subnet or network of the next-hop IP address of the routed packet. * 3. Stack configured to send redirects. */ #define INET_SUBNET_PREFIX(addr) \ (odp_be_to_cpu_32(addr) & ((~0) << (32 - dev->masklen))) if (nh->port == dev->port && (INET_SUBNET_PREFIX(ip->ip_src.s_addr) == INET_SUBNET_PREFIX(nh->gw))) { OFP_DBG("send OFP_ICMP_REDIRECT"); ofp_icmp_error(pkt, OFP_ICMP_REDIRECT, OFP_ICMP_REDIRECT_HOST, nh->gw, 0); } #endif return ofp_ip_output(pkt, nh); }
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; }