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); }
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); }