static void test_sinlge_port_basic(void) { int port = 0; uint16_t vlan = 0; uint16_t vrf = 1; uint32_t ifaddr = 0x650AA8C0; /* C0.A8.0A.65 = 192.168.10.101 */ int masklen = 24; uint32_t bcast = ifaddr | odp_cpu_to_be_32(0xFF); struct ofp_ifnet *dev; struct ofp_nh_entry *nh; const char *res; res = ofp_config_interface_up_v4(port, vlan, vrf, ifaddr, masklen); CU_ASSERT_PTR_NULL_FATAL(res); dev = ofp_get_ifnet(port, vlan); assert_dev(dev, port, vlan, vrf, ifaddr, ifmtu, masklen, bcast, link_local); nh = ofp_get_next_hop(vrf, ifaddr, NULL); assert_next_hop(nh, 0, port, vlan); res = ofp_config_interface_down(port, vlan); CU_ASSERT_PTR_NULL_FATAL(res); dev = ofp_get_ifnet(port, vlan); assert_dev(dev, port, vlan, vrf, 0, ifmtu, masklen, bcast, link_local); nh = ofp_get_next_hop(vrf, ifaddr, NULL); CU_ASSERT_PTR_NULL(nh); }
/* * INIT */ static void init_ifnet(void) { char str[256]; ofp_config_interface_up_v4(port, vlan, vrf, dev_ip, 24); /* port 0 */ dev = ofp_get_ifnet(port, vlan); memcpy(dev->mac, dev_mac, OFP_ETHER_ADDR_LEN); dev->if_mtu = def_mtu; #ifdef SP dev->linux_index = port + 3; /* an if index of Linux != port val */ ofp_update_ifindex_lookup_tab(dev); #endif /* SP */ dev->pkt_pool = odp_pool_lookup(pool_name); sprintf(str, "out default queue:%d", port); dev->outq_def = odp_queue_create(str, NULL); if (dev->outq_def == ODP_QUEUE_INVALID) { fail_with_odp("Out default queue create failed.\n"); return; } dev->out_queue_num = 1; dev->out_queue_type = OFP_OUT_QUEUE_TYPE_QUEUE; /* port 0 vlan 1 */ ofp_config_interface_up_v4(port, vlan + 1, vrf, dev_ip + 1, 24); dev_vlan = ofp_get_ifnet(port, vlan + 1); memcpy(dev_vlan->mac, dev_vlan_mac, OFP_ETHER_ADDR_LEN); dev_vlan->if_mtu = def_mtu; #ifdef SP dev_vlan->linux_index = port + 4; /* an if index of Linux != port val */ ofp_update_ifindex_lookup_tab(dev_vlan); #endif /* SP */ dev_vlan->pkt_pool = odp_pool_lookup(pool_name); sprintf(str, "out default queue:%d", port); dev_vlan->outq_def = odp_queue_create(str, NULL); if (dev_vlan->outq_def == ODP_QUEUE_INVALID) { fail_with_odp("Out default queue create failed.\n"); return; } /* Tunnels */ ofp_config_interface_up_tun(GRE_PORTS, 100, 0, dev_ip, tun_rem_ip, tun_p2p, tun_addr, tun_mask); /* No nexthop for tunnel remote address */ ofp_config_interface_up_tun(GRE_PORTS, 200, 0, dev_ip, 0x08070605, tun_p2p + 1, tun_addr + 1, tun_mask); }
static void test_gre_port(void) { int port = 0; uint16_t vlan = 10; uint16_t vrf = 1; uint32_t ifaddr = 0x650AA8C0; /* C0.A8.0A.65 = 192.168.10.101 */ int masklen = 24, gre_ml = 32; uint16_t greid = 100; uint32_t greaddr = 0x010A0A0A; uint32_t grep2p = 0x020A0A0A; struct ofp_ifnet *dev; struct ofp_nh_entry *nh; const char *res; res = ofp_config_interface_up_v4(port, vlan, vrf, ifaddr, masklen); CU_ASSERT_PTR_NULL_FATAL(res); /* Non-existent endpoint in vrf */ res = ofp_config_interface_up_tun(GRE_PORTS, greid, vrf + 1, ifaddr, ifaddr + 1, greaddr, grep2p, gre_ml); CU_ASSERT_PTR_NOT_NULL_FATAL(res); dev = ofp_get_ifnet(GRE_PORTS, greid); CU_ASSERT_PTR_NULL_FATAL(dev); /* Successful test */ res = ofp_config_interface_up_tun(GRE_PORTS, greid, vrf, ifaddr, ifaddr + 1, grep2p, greaddr, gre_ml); CU_ASSERT_PTR_NULL_FATAL(res); dev = ofp_get_ifnet(GRE_PORTS, greid); CU_ASSERT_PTR_NOT_NULL_FATAL(dev); CU_ASSERT_EQUAL(dev->ip_local, ifaddr); CU_ASSERT_EQUAL(dev->ip_remote, ifaddr + 1); CU_ASSERT_EQUAL(dev->ip_addr, greaddr); CU_ASSERT_EQUAL(dev->ip_p2p, grep2p); CU_ASSERT_EQUAL(dev->masklen, gre_ml); CU_ASSERT_EQUAL(dev->if_mtu, ifmtu - 24); nh = ofp_get_next_hop(vrf, grep2p, NULL); assert_next_hop(nh, 0, GRE_PORTS, greid); res = ofp_config_interface_down(port, vlan); CU_ASSERT_PTR_NULL_FATAL(res); res = ofp_config_interface_down(GRE_PORTS, greid); CU_ASSERT_PTR_NULL_FATAL(res); dev = ofp_get_ifnet(GRE_PORTS, greid); CU_ASSERT_PTR_NULL_FATAL(dev); }
static void test_two_ports_vlan(void) { int port = 0; uint16_t vlan = 0, vlan1 = 100; uint16_t vrf = 1, vrf1 = 2; uint32_t ifaddr = 0x650AA8C0; /* C0.A8.0A.65 = 192.168.10.101 */ uint32_t ifaddr1 = 0x650AA8C1; int masklen = 24, masklen1 = 20; uint32_t bcast = ifaddr | odp_cpu_to_be_32(0xFF); uint32_t bcast1 = ifaddr1 | odp_cpu_to_be_32(0xFFF); struct ofp_ifnet *dev; struct ofp_nh_entry *nh; const char *res; res = ofp_config_interface_up_v4(port, vlan, vrf, ifaddr, masklen); CU_ASSERT_PTR_NULL_FATAL(res); res = ofp_config_interface_up_v4(port, vlan1, vrf1, ifaddr1, masklen1); CU_ASSERT_PTR_NULL_FATAL(res); dev = ofp_get_ifnet(port, vlan); CU_ASSERT_PTR_NOT_NULL_FATAL(dev); assert_dev(dev, port, vlan, vrf, ifaddr, ifmtu, masklen, bcast, link_local); nh = ofp_get_next_hop(vrf, ifaddr, NULL); assert_next_hop(nh, 0, port, vlan); dev = ofp_get_ifnet(port, vlan1); assert_dev(dev, port, vlan1, vrf1, ifaddr1, ifmtu, masklen1, bcast1, link_local); nh = ofp_get_next_hop(vrf1, ifaddr1, NULL); assert_next_hop(nh, 0, port, vlan1); res = ofp_config_interface_down(port, vlan); CU_ASSERT_PTR_NULL_FATAL(res); res = ofp_config_interface_down(port, vlan1); CU_ASSERT_PTR_NULL_FATAL(res); dev = ofp_get_ifnet(port, vlan); assert_dev(dev, port, vlan, vrf, 0, ifmtu, masklen, bcast, link_local); nh = ofp_get_next_hop(vrf, ifaddr, NULL); CU_ASSERT_PTR_NULL(nh); dev = ofp_get_ifnet(port, vlan1); CU_ASSERT_PTR_NULL_FATAL(dev); nh = ofp_get_next_hop(vrf1, ifaddr1, NULL); CU_ASSERT_PTR_NULL(nh); }
static void init_ifnet(void) { char str[256]; ofp_config_interface_up_v4(port, vlan, vrf, dev_ip, 24); dev = ofp_get_ifnet(port, vlan); memcpy(dev->mac, dev_mac, OFP_ETHER_ADDR_LEN); dev->if_mtu = def_mtu; #ifdef SP dev->linux_index = port + 3; /* an if index of Linux != port val */ ofp_update_ifindex_lookup_tab(dev); #endif /* SP */ dev->pkt_pool = odp_pool_lookup("packet_pool"); sprintf(str, "out default queue:%d", port); dev->outq_def = odp_queue_create(str, NULL); if (dev->outq_def == ODP_QUEUE_INVALID) { fail_with_odp("Out default queue create failed.\n"); return; } dev->out_queue_num = 1; dev->out_queue_type = OFP_OUT_QUEUE_TYPE_QUEUE; }
enum ofp_return_code send_pkt_loop(struct ofp_ifnet *dev, odp_packet_t pkt) { if (odp_queue_enq(ofp_get_ifnet(dev->port, 0)->loopq_def, odp_packet_to_event(pkt))) return OFP_PKT_DROP; return OFP_PKT_PROCESSED; }
enum ofp_return_code ofp_eth_vlan_processing(odp_packet_t *pkt) { uint16_t vlan = 0, ethtype; struct ofp_ether_header *eth; struct ofp_ifnet *ifnet = odp_packet_user_ptr(*pkt); eth = (struct ofp_ether_header *)odp_packet_l2_ptr(*pkt, NULL); if (odp_unlikely(eth == NULL)) { OFP_DBG("eth is NULL"); return OFP_PKT_DROP; } ethtype = odp_be_to_cpu_16(eth->ether_type); if (ethtype == OFP_ETHERTYPE_VLAN) { struct ofp_ether_vlan_header *vlan_hdr; vlan_hdr = (struct ofp_ether_vlan_header *)eth; vlan = OFP_EVL_VLANOFTAG(odp_be_to_cpu_16(vlan_hdr->evl_tag)); ethtype = odp_be_to_cpu_16(vlan_hdr->evl_proto); ifnet = ofp_get_ifnet(ifnet->port, vlan); if (!ifnet) return OFP_PKT_DROP; if (odp_likely(ofp_if_type(ifnet) != OFP_IFT_VXLAN)) odp_packet_user_ptr_set(*pkt, ifnet); } OFP_DBG("ETH TYPE = %04x", ethtype); /* network layer classifier */ switch (ethtype) { /* STUB: except for ARP, just terminate all traffic to slowpath. * FIXME: test/implement other cases */ #ifdef INET case OFP_ETHERTYPE_IP: return ofp_ipv4_processing(pkt); #endif /* INET */ #ifdef INET6 case OFP_ETHERTYPE_IPV6: return ofp_ipv6_processing(pkt); #endif /* INET6 */ #if 0 case OFP_ETHERTYPE_MPLS: return OFP_PKT_DROP; #endif case OFP_ETHERTYPE_ARP: return ofp_arp_processing(pkt); default: return OFP_PKT_CONTINUE; } }
/* * INIT */ static void test_init_ifnet(void) { char str[256]; ofp_config_interface_up_v4(port, vlan, vrf, local_ip, 24); ifnet = ofp_get_ifnet(port, vlan); ifnet->pkt_pool = odp_pool_lookup("packet_pool"); #ifdef SP ifnet->linux_index = port + 3; /* an if index of Linux != port val */ ofp_update_ifindex_lookup_tab(ifnet); sprintf(str, "slow path stack port:%d", port); ifnet->spq_def = odp_queue_create(str, ODP_QUEUE_TYPE_POLL, NULL); if (ifnet->spq_def == ODP_QUEUE_INVALID) { fail_with_odp("Slow path queue create failed.\n"); return; } #endif sprintf(str, "out default queue:%d", port); ifnet->outq_def = odp_queue_create(str, ODP_QUEUE_TYPE_POLL, NULL); if (ifnet->outq_def == ODP_QUEUE_INVALID) { fail_with_odp("Out default queue create failed.\n"); return; } sprintf(str, "interface queue:%d", port); interface_queue[port] = odp_queue_create(str, ODP_QUEUE_TYPE_POLL, NULL); if (interface_queue[port] == ODP_QUEUE_INVALID) { OFP_ERR("Poll queue create failed.\n"); return; } ofp_queue_context_set(interface_queue[port], ifnet); ofp_config_interface_up_tun(GRE_PORTS, 100 + port, vrf, local_ip, tun_rem_ip, tun_p2p, tun_addr, tun_mask); }
enum ofp_return_code send_pkt_out(struct ofp_ifnet *dev, odp_packet_t pkt) { OFP_DBG("Sent packet out %s", dev->if_name); if (odp_queue_enq(ofp_get_ifnet(dev->port, 0)->outq_def, odp_packet_to_event(pkt))) { OFP_DBG("odp_queue_enq failed"); return OFP_PKT_DROP; } OFP_DEBUG_PACKET(OFP_DEBUG_PKT_SEND_NIC, pkt, dev->port); OFP_UPDATE_PACKET_STAT(tx_fp, 1); return OFP_PKT_PROCESSED; }
static enum ofp_return_code ofp_gre_update_target(odp_packet_t pkt, struct ip_out *odata) { struct ofp_nh_entry *nh_new = NULL; if (ofp_output_ipv4_to_gre(pkt, odata->dev_out, odata->vrf, &nh_new) == OFP_PKT_DROP) return OFP_PKT_DROP; odata->nh = nh_new; odata->gw = odata->nh->gw; odata->vlan = odata->nh->vlan; odata->out_port = odata->nh->port; odata->ip = odp_packet_l3_ptr(pkt, NULL); odata->dev_out = ofp_get_ifnet(odata->out_port, odata->vlan); if (!odata->dev_out) return OFP_PKT_DROP; return OFP_PKT_CONTINUE; }
/* * INIT */ static int init_suite(void) { odp_pool_param_t pool_params; ofp_pkt_hook pkt_hook[OFP_HOOK_MAX]; struct ofp_ifnet *dev; odp_pool_t pool; /* Init ODP before calling anything else */ if (odp_init_global(NULL, NULL)) { OFP_ERR("Error: ODP global init failed.\n"); return -1; } /* Init this thread */ if (odp_init_local(ODP_THREAD_CONTROL)) { OFP_ERR("Error: ODP local init failed.\n"); return -1; } memset(pkt_hook, 0, sizeof(pkt_hook)); pool_params.pkt.seg_len = SHM_PKT_POOL_BUFFER_SIZE; pool_params.pkt.len = SHM_PKT_POOL_BUFFER_SIZE; pool_params.pkt.num = SHM_PKT_POOL_SIZE / SHM_PKT_POOL_BUFFER_SIZE; pool_params.type = ODP_POOL_PACKET; (void) ofp_init_pre_global("packet_pool", &pool_params, pkt_hook, &pool, ARP_AGE_INTERVAL, ARP_ENTRY_TIMEOUT); ofp_arp_init_local(); dev = ofp_get_ifnet(0, 0); dev->if_mtu = ifmtu; memcpy(dev->mac, ifmac, OFP_ETHER_ADDR_LEN); ofp_mac_to_link_local(ifmac, link_local); return 0; }
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; }
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); }
int ofp_ioctl(int sockfd, int request, ...) { va_list ap; void *data; struct ofp_ifnet *iface = NULL; struct socket *so = ofp_get_sock_by_fd(sockfd); if (!so) { ofp_errno = OFP_EBADF; return -1; } va_start(ap, request); data = va_arg(ap, void *); va_end(ap); if (request == (int)(OFP_SIOCGIFCONF)) { ofp_errno = ((*so->so_proto->pr_usrreqs->pru_control) (so, request, data, NULL, NULL)); } else if (OFP_IOCGROUP(request) == 'i') { /* All the interface requests start with interface name */ int port, vlan = 0; char *name = data; if (get_port_vlan_by_name(name, &port, &vlan) < 0) { ofp_errno = OFP_EBADF; return -1; } if (request == (int)(OFP_SIOCSIFTUN)) { struct ofp_in_tunreq *treq = data; const char *retstr = ofp_config_interface_up_tun (port, vlan, treq->iftun_vrf, treq->iftun_local_addr.sin_addr.s_addr, treq->iftun_remote_addr.sin_addr.s_addr, treq->iftun_p2p_addr.sin_addr.s_addr, treq->iftun_addr.sin_addr.s_addr, 30); if (!retstr) ofp_errno = 0; else ofp_errno = OFP_EBADMSG; } else { iface = ofp_get_ifnet(port, vlan); if (so->so_proto->pr_usrreqs->pru_control) ofp_errno = ((*so->so_proto->pr_usrreqs->pru_control) (so, request, data, iface, NULL)); else ofp_errno = OFP_EOPNOTSUPP; } } else if (OFP_IOCGROUP(request) == 'r') { int port = 0, vlan = 0; struct ofp_rtentry *rt = data; uint32_t dst = ((struct ofp_sockaddr_in *)&rt->rt_dst)->sin_addr.s_addr; uint32_t mask = ((struct ofp_sockaddr_in *)&rt->rt_genmask)->sin_addr.s_addr; uint32_t gw = ((struct ofp_sockaddr_in *)&rt->rt_gateway)->sin_addr.s_addr; uint32_t maskcpu = odp_be_to_cpu_32(mask); uint32_t mlen = 0; if (request != (int)OFP_SIOCADDRT && request != (int)OFP_SIOCDELRT) { ofp_errno = OFP_EBADF; return -1; } if (request == (int)OFP_SIOCADDRT) { if (rt->rt_dev) { if (get_port_vlan_by_name(rt->rt_dev, &port, &vlan) < 0) { ofp_errno = OFP_EBADF; return -1; } } else { uint32_t flags; struct ofp_nh_entry *nh = ofp_get_next_hop(rt->rt_vrf, gw, &flags); if (!nh) { ofp_errno = OFP_EBADF; return -1; } port = nh->port; vlan = nh->vlan; } } while (maskcpu) { mlen++; maskcpu <<= 1; } ofp_set_route_params((request == (int) OFP_SIOCADDRT) ? OFP_ROUTE_ADD : OFP_ROUTE_DEL, rt->rt_vrf, vlan, port, dst, mlen, gw, (request == (int) OFP_SIOCADDRT) ? (gw ? OFP_RTF_GATEWAY : OFP_RTF_NET) : 0); } else { ofp_errno = ofp_soo_ioctl(so, request, data, NULL, NULL); } if (ofp_errno) return -1; return 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); }