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 {
uint8_t *odp_packet_l2(odp_packet_t pkt) { const size_t offset = odp_packet_l2_offset(pkt); if (odp_unlikely(offset == ODP_PACKET_OFFSET_INVALID)) return NULL; return odp_packet_buf_addr(pkt) + offset; }
static enum ofp_return_code ofp_output_ipv4_to_gre( odp_packet_t pkt, struct ofp_ifnet *dev_gre, uint16_t vrfid, struct ofp_nh_entry **nh_new) { struct ofp_ip *ip; struct ofp_greip *greip; uint32_t flags; uint8_t l2_size = 0; int32_t offset; *nh_new = ofp_get_next_hop(vrfid, dev_gre->ip_remote, &flags); if (*nh_new == NULL) return OFP_PKT_DROP; ip = odp_packet_l3_ptr(pkt, NULL); /* Remove eth header, prepend gre + ip */ if (odp_packet_has_l2(pkt)) l2_size = odp_packet_l3_offset(pkt) - odp_packet_l2_offset(pkt); offset = sizeof(*greip) - l2_size; if (offset >= 0) greip = odp_packet_push_head(pkt, offset); else greip = odp_packet_pull_head(pkt, -offset); odp_packet_has_l2_set(pkt, 0); odp_packet_l3_offset_set(pkt, 0); if (!greip) return OFP_PKT_DROP; greip->gi_flags = 0; greip->gi_ptype = odp_cpu_to_be_16(OFP_GREPROTO_IP); greip->gi_i.ip_hl = 5; greip->gi_i.ip_v = 4; greip->gi_i.ip_tos = ip->ip_tos; greip->gi_i.ip_len = odp_cpu_to_be_16(odp_be_to_cpu_16(ip->ip_len) + sizeof(*greip)); greip->gi_i.ip_id = ip->ip_id; greip->gi_i.ip_off = 0; greip->gi_i.ip_ttl = ip->ip_ttl; greip->gi_i.ip_p = OFP_IPPROTO_GRE; greip->gi_i.ip_sum = 0; greip->gi_i.ip_src.s_addr = dev_gre->ip_local; greip->gi_i.ip_dst.s_addr = dev_gre->ip_remote; return OFP_PKT_CONTINUE; }