ipsec_cache_entry_t *find_ipsec_cache_entry_in(uint32_t src_ip, uint32_t dst_ip, odph_ahhdr_t *ah, odph_esphdr_t *esp) { ipsec_cache_entry_t *entry = ipsec_cache->in_list; /* Look for a hit */ for (; NULL != entry; entry = entry->next) { if ((entry->src_ip != src_ip) || (entry->dst_ip != dst_ip)) if ((entry->tun_src_ip != src_ip) || (entry->tun_dst_ip != dst_ip)) continue; if (ah && ((!entry->ah.alg) || (entry->ah.spi != odp_be_to_cpu_32(ah->spi)))) continue; if (esp && ((!entry->esp.alg) || (entry->esp.spi != odp_be_to_cpu_32(esp->spi)))) continue; break; } return entry; }
static enum ofp_return_code ofp_ip_output_add_eth(odp_packet_t pkt, struct ip_out *odata) { uint8_t l2_size = 0; void *l2_addr; if (!odata->gw) /* link local */ odata->gw = odata->ip->ip_dst.s_addr; if (ETH_WITHOUT_VLAN(odata->vlan, odata->out_port)) l2_size = sizeof(struct ofp_ether_header); else l2_size = sizeof(struct ofp_ether_vlan_header); if (odp_packet_l2_offset(pkt) + l2_size == odp_packet_l3_offset(pkt)) { l2_addr = odp_packet_l2_ptr(pkt, NULL); } else if (odp_packet_l3_offset(pkt) >= l2_size) { odp_packet_l2_offset_set(pkt, odp_packet_l3_offset(pkt) - l2_size); l2_addr = odp_packet_l2_ptr(pkt, NULL); } else { l2_addr = odp_packet_push_head(pkt, l2_size - odp_packet_l3_offset(pkt)); odp_packet_l2_offset_set(pkt, 0); odp_packet_l3_offset_set(pkt, l2_size); odp_packet_l4_offset_set(pkt, l2_size + (odata->ip->ip_hl<<2)); } if (odp_unlikely(l2_addr == NULL)) { OFP_DBG("l2_addr == NULL"); return OFP_PKT_DROP; } if (ETH_WITHOUT_VLAN(odata->vlan, odata->out_port)) { struct ofp_ether_header *eth = (struct ofp_ether_header *)l2_addr; uint32_t addr = odp_be_to_cpu_32(odata->ip->ip_dst.s_addr); if (OFP_IN_MULTICAST(addr)) { eth->ether_dhost[0] = 0x01; eth->ether_dhost[1] = 0x00; eth->ether_dhost[2] = 0x5e; eth->ether_dhost[3] = (addr >> 16) & 0x7f; eth->ether_dhost[4] = (addr >> 8) & 0xff; eth->ether_dhost[5] = addr & 0xff; } else if (odata->dev_out->ip_addr == odata->ip->ip_dst.s_addr) { odata->is_local_address = 1; ofp_copy_mac(eth->ether_dhost, &(odata->dev_out->mac[0])); } else if (ofp_get_mac(odata->dev_out, odata->gw, eth->ether_dhost) < 0) { send_arp_request(odata->dev_out, odata->gw); return ofp_arp_save_ipv4_pkt(pkt, odata->nh, odata->gw, odata->dev_out); } ofp_copy_mac(eth->ether_shost, odata->dev_out->mac); eth->ether_type = odp_cpu_to_be_16(OFP_ETHERTYPE_IP); } else {
void ofp_rt_rule_print(int fd, uint16_t vrf, void (*func)(int fd, uint32_t key, int level, struct ofp_nh_entry *data)) { uint32_t index; for (index = 0; index < ROUTE_LIST_SIZE; index++) if (shm->rules[index].used && shm->rules[index].vrf == vrf) func(fd, odp_be_to_cpu_32(shm->rules[index].addr), shm->rules[index].masklen, &shm->rules[index].data[0]); }
/** * Helper function to print IP address. */ char *ofp_print_ip_addr(uint32_t addr) { static char buf[4][24]; static int sel = 0; uint32_t ip = odp_be_to_cpu_32(addr); sel++; if (sel > 3) sel = 0; sprintf(buf[sel], "%d.%d.%d.%d", ip>>24, (ip>>16)&0xff, (ip>>8)&0xff, ip&0xff); return buf[sel]; }
struct ofp_nh_entry *ofp_rtl_search(struct ofp_rtl_tree *tree, uint32_t addr_be) { struct ofp_nh_entry *nh = NULL; struct ofp_rtl_node *elem, *node = tree->root; uint32_t addr = odp_be_to_cpu_32(addr_be); uint32_t low = 0, high = IPV4_FIRST_LEVEL; for (; high <= IPV4_LENGTH ; low = high, high += IPV4_LEVEL) { elem = find_node(node, addr, low, high); if (elem->masklen == 0) return nh; else if (elem->masklen <= high) nh = &elem->data[0]; if ((node = elem->next) == NULL) return nh; } return nh; }
static enum ofp_return_code ofp_ip_output_add_eth(odp_packet_t pkt, struct ip_out *odata) { uint32_t l2_size; void *l2_addr; struct ofp_ether_header *eth; uint32_t addr; uint32_t is_link_local = 0; trim_tail(pkt, odp_be_to_cpu_16(odata->ip->ip_len)); if (!odata->gw) { /* link local */ odata->gw = odata->ip->ip_dst.s_addr; is_link_local = 1; } if (!ETH_WITH_VLAN(odata->dev_out)) l2_size = sizeof(struct ofp_ether_header); else l2_size = sizeof(struct ofp_ether_vlan_header); l2_addr = trim_for_output(pkt, l2_size, odata->ip->ip_hl * 4); if (odp_unlikely(l2_addr == NULL)) { OFP_DBG("l2_addr == NULL"); return OFP_PKT_DROP; } eth = l2_addr; addr = odp_be_to_cpu_32(odata->ip->ip_dst.s_addr); if (OFP_IN_MULTICAST(addr)) { eth->ether_dhost[0] = 0x01; eth->ether_dhost[1] = 0x00; eth->ether_dhost[2] = 0x5e; eth->ether_dhost[3] = (addr >> 16) & 0x7f; eth->ether_dhost[4] = (addr >> 8) & 0xff; eth->ether_dhost[5] = addr & 0xff; } else if (odata->dev_out->ip_addr == odata->ip->ip_dst.s_addr ||
odp_bool_t verify_ipv4_packet(stream_db_entry_t *stream, odp_packet_t pkt) { ipsec_cache_entry_t *entry = NULL; uint8_t *data; odph_ipv4hdr_t *ip; odph_ahhdr_t *ah = NULL; odph_esphdr_t *esp = NULL; int hdr_len; odph_icmphdr_t *icmp; stream_pkt_hdr_t *test; uint32_t src_ip, dst_ip; if (stream->input.entry) entry = stream->input.entry; else if (stream->output.entry) entry = stream->output.entry; /* Basic IPv4 verify (add checksum verification) */ data = odp_packet_l3_ptr(pkt, NULL); ip = (odph_ipv4hdr_t *)data; data += sizeof(*ip); if (0x45 != ip->ver_ihl) return FALSE; src_ip = odp_be_to_cpu_32(ip->src_addr); dst_ip = odp_be_to_cpu_32(ip->dst_addr); if ((stream->src_ip != src_ip) && stream->output.entry && (stream->output.entry->tun_src_ip != src_ip)) return FALSE; if ((stream->dst_ip != dst_ip) && stream->output.entry && (stream->output.entry->tun_dst_ip != dst_ip)) return FALSE; if ((stream->src_ip != src_ip) && stream->input.entry && (stream->input.entry->tun_src_ip != src_ip)) return FALSE; if ((stream->dst_ip != dst_ip) && stream->input.entry && (stream->input.entry->tun_dst_ip != dst_ip)) return FALSE; /* Find IPsec headers if any and compare against entry */ hdr_len = locate_ipsec_headers(ip, &ah, &esp); /* Cleartext packet */ if (!ah && !esp) goto clear_packet; if (ah) { if (!entry) return FALSE; if (ODP_AUTH_ALG_NULL == entry->ah.alg) return FALSE; if (odp_be_to_cpu_32(ah->spi) != entry->ah.spi) return FALSE; if (ODP_AUTH_ALG_MD5_96 != entry->ah.alg) abort(); } else { if (entry && (ODP_AUTH_ALG_NULL != entry->ah.alg)) return FALSE; } if (esp) { if (!entry) return FALSE; if (ODP_CIPHER_ALG_NULL == entry->esp.alg) return FALSE; if (odp_be_to_cpu_32(esp->spi) != entry->esp.spi) return FALSE; if (ODP_CIPHER_ALG_3DES_CBC != entry->esp.alg) abort(); hdr_len += entry->esp.iv_len; } else { if (entry && (ODP_CIPHER_ALG_NULL != entry->esp.alg)) return FALSE; } data += hdr_len; /* Verify authentication (if present) */ if (ah) { uint8_t ip_tos; uint8_t ip_ttl; uint16_t ip_frag_offset; uint8_t icv[12]; uint8_t hash[EVP_MAX_MD_SIZE]; /* Save/clear mutable fields */ ip_tos = ip->tos; ip_ttl = ip->ttl; ip_frag_offset = odp_be_to_cpu_16(ip->frag_offset); ip->tos = 0; ip->ttl = 0; ip->frag_offset = 0; ip->chksum = 0; memcpy(icv, ah->icv, 12); memset(ah->icv, 0, 12); /* Calculate HMAC and compare */ HMAC(EVP_md5(), entry->ah.key.data, entry->ah.key.length, (uint8_t *)ip, odp_be_to_cpu_16(ip->tot_len), hash, NULL); if (0 != memcmp(icv, hash, sizeof(icv))) return FALSE; ip->proto = ah->next_header; ip->tos = ip_tos; ip->ttl = ip_ttl; ip->frag_offset = odp_cpu_to_be_16(ip_frag_offset); } /* Decipher if present */ if (esp) { odph_esptrl_t *esp_t; DES_key_schedule ks1, ks2, ks3; uint8_t iv[8]; int encrypt_len = ipv4_data_len(ip) - hdr_len; memcpy(iv, esp->iv, sizeof(iv)); DES_set_key((DES_cblock *)&entry->esp.key.data[0], &ks1); DES_set_key((DES_cblock *)&entry->esp.key.data[8], &ks2); DES_set_key((DES_cblock *)&entry->esp.key.data[16], &ks3); DES_ede3_cbc_encrypt((uint8_t *)data, (uint8_t *)data, encrypt_len, &ks1, &ks2, &ks3, (DES_cblock *)iv, 0); esp_t = (odph_esptrl_t *)(data + encrypt_len) - 1; ip->proto = esp_t->next_header; } clear_packet: /* Verify IP/ICMP packet */ if (entry && (entry->mode == IPSEC_SA_MODE_TUNNEL) && (ah || esp)) { if (ODPH_IPV4 != ip->proto) return FALSE; odph_ipv4hdr_t *inner_ip = (odph_ipv4hdr_t *)data; icmp = (odph_icmphdr_t *)(inner_ip + 1); data = (uint8_t *)icmp; } else { if (ODPH_IPPROTO_ICMP != ip->proto) return FALSE; icmp = (odph_icmphdr_t *)data; } /* Verify ICMP header */ data += sizeof(*icmp); if (ICMP_ECHO != icmp->type) return FALSE; if (0x1234 != odp_be_to_cpu_16(icmp->un.echo.id)) return FALSE; /* Now check our packet */ test = (stream_pkt_hdr_t *)data; if (STREAM_MAGIC != odp_be_to_cpu_64(test->magic)) return FALSE; return TRUE; }
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 inline uint32_t to_network_prefix(uint32_t addr_be, uint32_t masklen) { return (odp_be_to_cpu_32(addr_be)) & ((~0) << (32 - masklen)); }
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; }
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)); } }
static void *mcasttest(void *arg) { int fd; struct ofp_sockaddr_in my_addr; struct ofp_ip_mreq mreq; (void)arg; logprint("Multicast thread started\n"); if (odp_init_local(ODP_THREAD_CONTROL)) { OFP_ERR("Error: ODP local init failed.\n"); return NULL; } if (ofp_init_local()) { OFP_ERR("Error: OFP local init failed.\n"); return NULL; } sleep(1); while (myaddr == 0) { myaddr = ofp_port_get_ipv4_addr(0, 0, OFP_PORTCONF_IP_TYPE_IP_ADDR); sleep(1); } if ((fd = ofp_socket(OFP_AF_INET, OFP_SOCK_DGRAM, OFP_IPPROTO_UDP)) < 0) { perror("socket"); logprint("Cannot open socket!\n"); return NULL; } memset(&my_addr, 0, sizeof(my_addr)); my_addr.sin_family = OFP_AF_INET; my_addr.sin_port = odp_cpu_to_be_16(2048); my_addr.sin_addr.s_addr = 0; my_addr.sin_len = sizeof(my_addr); if (ofp_bind(fd, (struct ofp_sockaddr *)&my_addr, sizeof(struct ofp_sockaddr)) < 0) { logprint("Cannot bind socket (%s)!\n", ofp_strerror(ofp_errno)); return NULL; } memset(&mreq, 0, sizeof(mreq)); mreq.imr_multiaddr.s_addr = IP4(234,5,5,5); mreq.imr_interface.s_addr = myaddr; if (ofp_setsockopt(fd, OFP_IPPROTO_IP, OFP_IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) { perror("setsockopt"); } memset(&mreq, 0, sizeof(mreq)); mreq.imr_multiaddr.s_addr = IP4(234,7,7,7); mreq.imr_interface.s_addr = myaddr; if (ofp_setsockopt(fd, OFP_IPPROTO_IP, OFP_IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) { perror("setsockopt"); } for (;;) { char buf[100]; int len = sizeof(buf); struct ofp_sockaddr_in addr = {0}; ofp_socklen_t addr_len = 0; len = ofp_recvfrom(fd, buf, len, 0, (struct ofp_sockaddr *)&addr, &addr_len); if (len == -1) { OFP_ERR("Faild to rcv data(errno = %d)\n", ofp_errno); continue; } buf[len] = 0; OFP_INFO("Data (%s, len = %d) was received.\n", buf, len); if (addr_len != sizeof(addr)) { OFP_ERR("Faild to rcv source address: %d (errno = %d)\n", addr_len, ofp_errno); continue; } if (strstr(buf, "add")) { OFP_INFO("Add membership to 234.7.7.7\n"); memset(&mreq, 0, sizeof(mreq)); mreq.imr_multiaddr.s_addr = IP4(234,7,7,7); mreq.imr_interface.s_addr = myaddr; if (ofp_setsockopt(fd, OFP_IPPROTO_IP, OFP_IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) { perror("setsockopt"); } } else if (strstr(buf, "drop")) { OFP_INFO("Drop membership from 234.7.7.7\n"); memset(&mreq, 0, sizeof(mreq)); mreq.imr_multiaddr.s_addr = IP4(234,7,7,7); mreq.imr_interface.s_addr = myaddr; if (ofp_setsockopt(fd, OFP_IPPROTO_IP, OFP_IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) { perror("setsockopt"); } } else if (strstr(buf, "quit")) { exit(0); } OFP_INFO("Data was received from address 0x%x, port = %d.\n", odp_be_to_cpu_32(addr.sin_addr.s_addr), odp_be_to_cpu_16(addr.sin_port)); sprintf(buf, "%d bytes\n", len); if (ofp_sendto(fd, buf, strlen(buf), 0, (struct ofp_sockaddr *)&addr, sizeof(addr)) == -1) { OFP_ERR("Faild to send data (errno = %d)\n", ofp_errno); } } logprint("mcast exit\n"); return NULL; }
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); }