/* Modifies the IPv4 header fields of 'packet' to be consistent with 'src', * 'dst', 'tos', and 'ttl'. Updates 'packet''s L4 checksums as appropriate. * 'packet' must contain a valid IPv4 packet with correctly populated l[347] * markers. */ void packet_set_ipv4(struct ofpbuf *packet, ovs_be32 src, ovs_be32 dst, uint8_t tos, uint8_t ttl) { struct ip_header *nh = packet->l3; if (nh->ip_src != src) { packet_set_ipv4_addr(packet, &nh->ip_src, src); } if (nh->ip_dst != dst) { packet_set_ipv4_addr(packet, &nh->ip_dst, dst); } if (nh->ip_tos != tos) { uint8_t *field = &nh->ip_tos; nh->ip_csum = recalc_csum16(nh->ip_csum, htons((uint16_t) *field), htons((uint16_t) tos)); *field = tos; } if (nh->ip_ttl != ttl) { uint8_t *field = &nh->ip_ttl; nh->ip_csum = recalc_csum16(nh->ip_csum, htons(*field << 8), htons(ttl << 8)); *field = ttl; } }
static void packet_set_port(ovs_be16 *port, ovs_be16 new_port, ovs_be16 *csum) { if (*port != new_port) { *csum = recalc_csum16(*csum, *port, new_port); *port = new_port; } }
/* Called on a sorted complete list of v4 fragments to reassemble them into * a single packet that can be processed, such as passing through conntrack. */ static struct dp_packet * ipf_reassemble_v4_frags(struct ipf_list *ipf_list) /* OVS_REQUIRES(ipf_lock) */ { struct ipf_frag *frag_list = ipf_list->frag_list; struct dp_packet *pkt = dp_packet_clone(frag_list[0].pkt); dp_packet_set_size(pkt, dp_packet_size(pkt) - dp_packet_l2_pad_size(pkt)); struct ip_header *l3 = dp_packet_l3(pkt); int len = ntohs(l3->ip_tot_len); int rest_len = frag_list[ipf_list->last_inuse_idx].end_data_byte - frag_list[1].start_data_byte + 1; if (len + rest_len > IPV4_PACKET_MAX_SIZE) { ipf_print_reass_packet( "Unsupported big reassembled v4 packet; v4 hdr:", l3); dp_packet_delete(pkt); return NULL; } dp_packet_prealloc_tailroom(pkt, rest_len); for (int i = 1; i <= ipf_list->last_inuse_idx; i++) { size_t add_len = frag_list[i].end_data_byte - frag_list[i].start_data_byte + 1; const char *l4 = dp_packet_l4(frag_list[i].pkt); dp_packet_put(pkt, l4, add_len); } len += rest_len; l3 = dp_packet_l3(pkt); ovs_be16 new_ip_frag_off = l3->ip_frag_off & ~htons(IP_MORE_FRAGMENTS); l3->ip_csum = recalc_csum16(l3->ip_csum, l3->ip_frag_off, new_ip_frag_off); l3->ip_csum = recalc_csum16(l3->ip_csum, l3->ip_tot_len, htons(len)); l3->ip_tot_len = htons(len); l3->ip_frag_off = new_ip_frag_off; dp_packet_set_l2_pad_size(pkt, 0); return pkt; }
/* Executes set tp src action. */ static void set_tp_src(struct packet *pkt, struct ofl_action_tp_port *act) { packet_handle_std_validate(pkt->handle_std); if (pkt->handle_std->proto->tcp != NULL) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_src, htons(act->tp_port)); tcp->tcp_src = htons(act->tp_port); pkt->handle_std->match->tp_src = act->tp_port; } else if (pkt->handle_std->proto->udp != NULL) { struct udp_header *udp = pkt->handle_std->proto->udp; udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_src, htons(act->tp_port)); udp->udp_src = htons(act->tp_port); pkt->handle_std->match->tp_src = act->tp_port; } else { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute SET_TP_SRC action on packet with no tp."); } }
/* Executes set tp dst action. */ static void set_tp_dst(struct packet *pkt, struct ofl_action_tp_port *act) { packet_handle_std_validate(pkt->handle_std); if (pkt->handle_std->proto->tcp != NULL) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_dst, htons(act->tp_port)); tcp->tcp_dst = htons(act->tp_port); pkt->handle_std->match->tp_dst = act->tp_port; } else if (pkt->handle_std->proto->udp != NULL) { struct udp_header *udp = pkt->handle_std->proto->udp; udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, htons(act->tp_port)); udp->udp_dst = htons(act->tp_port); // update packet match (assuming it is of type ofl_match_standard) pkt->handle_std->match->tp_dst = act->tp_port; } else { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute SET_TP_DST action on packet with no tp."); } }
/* Make sure we get the calculation in RFC 1624 section 4 correct. */ static void test_rfc1624(void) { /* "...an IP packet header in which a 16-bit field m = 0x5555..." */ uint8_t data[32] = { 0xfe, 0x8f, 0xc1, 0x14, 0x4b, 0x6f, 0x70, 0x2a, 0x80, 0x29, 0x78, 0xc0, 0x58, 0x81, 0x77, 0xaa, 0x66, 0x64, 0xfc, 0x96, 0x63, 0x97, 0x64, 0xee, 0x12, 0x53, 0x1d, 0xa9, 0x2d, 0xa9, 0x55, 0x55 }; /* "...the one's complement sum of all other header octets is 0xCD7A." */ assert(ntohs(csum(data, sizeof data - 2)) == 0xffff - 0xcd7a); /* "...the header checksum would be: HC = ~(0xCD7A + 0x5555) = ~0x22D0 = 0xDD2F" */ assert(ntohs(csum(data, sizeof data)) == 0xdd2f); /* "a 16-bit field m = 0x5555 changes to m' = 0x3285..." */ data[30] = 0x32; data[31] = 0x85; /* "The new checksum via recomputation is: HC' = ~(0xCD7A + 0x3285) = ~0xFFFF = 0x0000" */ assert(ntohs(csum(data, sizeof data)) == 0x0000); /* "Applying [Eqn. 3] to the example above, we get the correct result: HC' = ~(C + (-m) + m') = ~(0x22D0 + ~0x5555 + 0x3285) = ~0xFFFF = 0x0000" */ assert(recalc_csum16(htons(0xdd2f), htons(0x5555), htons(0x3285)) == htons(0x0000)); mark('#'); }
/* Make sure we get the calculation in RFC 1624 section 4 correct. */ static void test_rfc1624(void) { /* "...an IP packet header in which a 16-bit field m = 0x5555..." */ uint8_t data[32] = "\xfe\x8f\xc1\x14\x4b\x6f\x70\x2a\x80\x29\x78\xc0\x58\x81\x77\xaa" "\x66\x64\xfc\x96\x63\x97\x64\xee\x12\x53\x1d\xa9\x2d\xa9\x55\x55"; /* "...the one's complement sum of all other header octets is 0xCD7A." */ assert(ntohs(csum(data, sizeof data - 2)) == 0xffff - 0xcd7a); /* "...the header checksum would be: HC = ~(0xCD7A + 0x5555) = ~0x22D0 = 0xDD2F" */ assert(ntohs(csum(data, sizeof data)) == 0xdd2f); /* "a 16-bit field m = 0x5555 changes to m' = 0x3285..." */ data[30] = 0x32; data[31] = 0x85; /* "The new checksum via recomputation is: HC' = ~(0xCD7A + 0x3285) = ~0xFFFF = 0x0000" */ assert(ntohs(csum(data, sizeof data)) == 0x0000); /* "Applying [Eqn. 3] to the example above, we get the correct result: HC' = ~(C + (-m) + m') = ~(0x22D0 + ~0x5555 + 0x3285) = ~0xFFFF = 0x0000" */ assert(recalc_csum16(htons(0xdd2f), htons(0x5555), htons(0x3285)) == htons(0x0000)); mark('#'); }
static void set_field(struct packet *pkt, struct ofl_action_set_field *act ) { packet_handle_std_validate(pkt->handle_std); if (pkt->handle_std->valid) { /*Field existence is guaranteed by the field pre-requisite on matching */ switch(act->field->header) { case OXM_OF_ETH_DST: { memcpy(pkt->handle_std->proto->eth->eth_dst, act->field->value, OXM_LENGTH(act->field->header)); break; } case OXM_OF_ETH_SRC: { memcpy(pkt->handle_std->proto->eth->eth_src, act->field->value, OXM_LENGTH(act->field->header)); break; } case OXM_OF_ETH_TYPE: { uint16_t *v = (uint16_t*) act->field->value; *v = htons(*v); memcpy(&pkt->handle_std->proto->eth->eth_type, v, OXM_LENGTH(act->field->header)); break; } case OXM_OF_VLAN_VID: { struct vlan_header *vlan = pkt->handle_std->proto->vlan; /* VLAN existence is no guaranteed by match prerquisite*/ if(vlan != NULL) { uint16_t v = (*(uint16_t*)act->field->value); vlan->vlan_tci = htons((ntohs(vlan->vlan_tci) & ~VLAN_VID_MASK) | (v & VLAN_VID_MASK)); } break; } case OXM_OF_VLAN_PCP: { struct vlan_header *vlan = pkt->handle_std->proto->vlan; /* VLAN existence is no guaranteed by match prerquisite*/ if(vlan != NULL) { vlan->vlan_tci = (vlan->vlan_tci & ~htons(VLAN_PCP_MASK)) | htons(*act->field->value << VLAN_PCP_SHIFT); break; } } case OXM_OF_IP_DSCP: { struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; uint8_t tos = (ipv4->ip_tos & ~IP_DSCP_MASK) | (*act->field->value << 2); ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, (uint16_t) (ipv4->ip_tos), (uint16_t)tos); ipv4->ip_tos = tos; break; } case OXM_OF_IP_ECN: { struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; uint8_t tos = (ipv4->ip_tos & ~IP_ECN_MASK) | (*act->field->value & IP_ECN_MASK); ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, (uint16_t) (ipv4->ip_tos), (uint16_t)tos); ipv4->ip_tos = tos; break; } case OXM_OF_IP_PROTO: { pkt->handle_std->proto->ipv4->ip_proto = *act->field->value; break; } case OXM_OF_IPV4_SRC: { struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; /*Reconstruct TCP or UDP checksum*/ if (pkt->handle_std->proto->tcp != NULL) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; tcp->tcp_csum = recalc_csum32(tcp->tcp_csum, ipv4->ip_src, *((uint32_t*) act->field->value)); } else if (pkt->handle_std->proto->udp != NULL) { struct udp_header *udp = pkt->handle_std->proto->udp; udp->udp_csum = recalc_csum32(udp->udp_csum, ipv4->ip_src, *((uint32_t*) act->field->value)); } ipv4->ip_csum = recalc_csum32(ipv4->ip_csum, ipv4->ip_src, *((uint32_t*) act->field->value)); ipv4->ip_src = *((uint32_t*) act->field->value); break; } case OXM_OF_IPV4_DST: { struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; /*Reconstruct TCP or UDP checksum*/ if (pkt->handle_std->proto->tcp != NULL) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; tcp->tcp_csum = recalc_csum32(tcp->tcp_csum, ipv4->ip_dst, *((uint32_t*) act->field->value)); } else if (pkt->handle_std->proto->udp != NULL) { struct udp_header *udp = pkt->handle_std->proto->udp; udp->udp_csum = recalc_csum32(udp->udp_csum, ipv4->ip_dst, *((uint32_t*) act->field->value)); } ipv4->ip_csum = recalc_csum32(ipv4->ip_csum, ipv4->ip_dst, *((uint32_t*) act->field->value)); ipv4->ip_dst = *((uint32_t*) act->field->value); break; } case OXM_OF_TCP_SRC: { struct tcp_header *tcp = pkt->handle_std->proto->tcp; uint16_t *v = (uint16_t*) act->field->value; *v = htons(*v); tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_src,*v); memcpy(&tcp->tcp_src, v, OXM_LENGTH(act->field->header)); break; } case OXM_OF_TCP_DST: { struct tcp_header *tcp = pkt->handle_std->proto->tcp; uint16_t *v = (uint16_t*) act->field->value; *v = htons(*v); tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_dst,*v); memcpy(&tcp->tcp_dst, v, OXM_LENGTH(act->field->header)); break; } case OXM_OF_UDP_SRC: { struct udp_header *udp = pkt->handle_std->proto->udp; uint16_t *v = (uint16_t*) act->field->value; *v = htons(*v); udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, *v); memcpy(&udp->udp_src, v, OXM_LENGTH(act->field->header)); break; } case OXM_OF_UDP_DST: { struct udp_header *udp = pkt->handle_std->proto->udp; uint16_t *v = (uint16_t*) act->field->value; *v = htons(*v); udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, *v); memcpy(&udp->udp_dst, v, OXM_LENGTH(act->field->header)); break; } /*TODO recalculate SCTP checksum*/ case OXM_OF_SCTP_SRC: { uint16_t *v = (uint16_t*) act->field->value; *v = htons(*v); memcpy(&pkt->handle_std->proto->sctp->sctp_src, v, OXM_LENGTH(act->field->header)); break; } case OXM_OF_SCTP_DST: { uint16_t *v = (uint16_t*) act->field->value; *v = htons(*v); memcpy(&pkt->handle_std->proto->sctp->sctp_dst, v, OXM_LENGTH(act->field->header)); break; } case OXM_OF_ICMPV4_TYPE: case OXM_OF_ICMPV6_TYPE: { pkt->handle_std->proto->icmp->icmp_type = *act->field->value; break; } case OXM_OF_ICMPV4_CODE: case OXM_OF_ICMPV6_CODE: { pkt->handle_std->proto->icmp->icmp_code = *act->field->value; break; } case OXM_OF_ARP_OP: { pkt->handle_std->proto->arp->ar_op = htons(*((uint16_t*) act->field->value)); break; } case OXM_OF_ARP_SPA: { pkt->handle_std->proto->arp->ar_spa = *((uint32_t*) act->field->value); break; } case OXM_OF_ARP_TPA: { pkt->handle_std->proto->arp->ar_tpa = *((uint32_t*) act->field->value); break; } case OXM_OF_ARP_SHA: { memcpy(pkt->handle_std->proto->arp->ar_sha, act->field->value, OXM_LENGTH(act->field->header)); break; } case OXM_OF_ARP_THA: { memcpy(pkt->handle_std->proto->arp->ar_tha, act->field->value, OXM_LENGTH(act->field->header)); break; } case OXM_OF_IPV6_SRC: { memcpy(&pkt->handle_std->proto->ipv6->ipv6_src, act->field->value, OXM_LENGTH(act->field->header)); break; } case OXM_OF_IPV6_DST: { memcpy(&pkt->handle_std->proto->ipv6->ipv6_dst, act->field->value, OXM_LENGTH(act->field->header)); break; } case OXM_OF_IPV6_FLABEL: { struct ipv6_header *ipv6 = (struct ipv6_header*) pkt->handle_std->proto->ipv6; uint32_t v = *((uint32_t*) act->field->value); ipv6->ipv6_ver_tc_fl = (ipv6->ipv6_ver_tc_fl & ~ntohl(IPV6_FLABEL_MASK)) | ntohl(v & IPV6_FLABEL_MASK); break; } /*IPV6 Neighbor Discovery */ case OXM_OF_IPV6_ND_TARGET: { struct icmp_header *icmp = pkt->handle_std->proto->icmp; uint8_t offset; uint8_t *data = (uint8_t*)icmp; /*ICMP header + neighbor discovery header reserverd bytes*/ offset = sizeof(struct icmp_header) + 4; memcpy(data + offset, act->field->value, OXM_LENGTH(act->field->header)); break; } case OXM_OF_IPV6_ND_SLL: { struct icmp_header *icmp = pkt->handle_std->proto->icmp; uint8_t offset; struct ipv6_nd_options_hd *opt = (struct ipv6_nd_options_hd*) icmp + sizeof(struct icmp_header); uint8_t *data = (uint8_t*) opt; /*ICMP header + neighbor discovery header reserverd bytes*/ offset = sizeof(struct ipv6_nd_header); if(opt->type == ND_OPT_SLL) { memcpy(data + offset, act->field->value, OXM_LENGTH(act->field->header)); } break; } case OXM_OF_IPV6_ND_TLL: { struct icmp_header *icmp = pkt->handle_std->proto->icmp; uint8_t offset; struct ipv6_nd_options_hd *opt = (struct ipv6_nd_options_hd*) icmp + sizeof(struct icmp_header); uint8_t *data = (uint8_t*) opt; /*ICMP header + neighbor discovery header reserverd bytes*/ offset = sizeof(struct ipv6_nd_header); if(opt->type == ND_OPT_TLL) { memcpy(data + offset, act->field->value, OXM_LENGTH(act->field->header)); } break; } case OXM_OF_MPLS_LABEL: { struct mpls_header *mpls = pkt->handle_std->proto->mpls; uint32_t v = *((uint32_t*) act->field->value); mpls->fields = (mpls->fields & ~ntohl(MPLS_LABEL_MASK)) | ntohl((v << MPLS_LABEL_SHIFT) & MPLS_LABEL_MASK); break; } case OXM_OF_MPLS_TC: { struct mpls_header *mpls = pkt->handle_std->proto->mpls; mpls->fields = (mpls->fields & ~ntohl(MPLS_TC_MASK)) | ntohl((*act->field->value << MPLS_TC_SHIFT) & MPLS_TC_MASK); break; } case OXM_OF_MPLS_BOS: { struct mpls_header *mpls = pkt->handle_std->proto->mpls; mpls->fields = (mpls->fields & ~ntohl(MPLS_S_MASK)) | ntohl((*act->field->value << MPLS_S_SHIFT) & MPLS_S_MASK); break; } case OXM_OF_PBB_ISID : { struct pbb_header *pbb = pkt->handle_std->proto->pbb; uint32_t v = *((uint32_t*) act->field->value); pbb->id = (pbb->id & ~ntohl(PBB_ISID_MASK)) | ntohl(v & PBB_ISID_MASK); break; } default: VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to set unknow field."); break; } pkt->handle_std->valid = false; return; } }
int main(void) { const struct test_case *tc; int i; for (tc = test_cases; tc < &test_cases[ARRAY_SIZE(test_cases)]; tc++) { const uint16_t *data16 = (const uint16_t *) tc->data; const uint32_t *data32 = (const uint32_t *) tc->data; uint32_t partial; size_t i; /* Test csum(). */ assert(ntohs(csum(tc->data, tc->size)) == tc->csum); mark('.'); /* Test csum_add16(). */ partial = 0; for (i = 0; i < tc->size / 2; i++) { partial = csum_add16(partial, data16[i]); } assert(ntohs(csum_finish(partial)) == tc->csum); mark('.'); /* Test csum_add32(). */ partial = 0; for (i = 0; i < tc->size / 4; i++) { partial = csum_add32(partial, data32[i]); } assert(ntohs(csum_finish(partial)) == tc->csum); mark('.'); /* Test alternating csum_add16() and csum_add32(). */ partial = 0; for (i = 0; i < tc->size / 4; i++) { if (i % 2) { partial = csum_add32(partial, data32[i]); } else { partial = csum_add16(partial, data16[i * 2]); partial = csum_add16(partial, data16[i * 2 + 1]); } } assert(ntohs(csum_finish(partial)) == tc->csum); mark('.'); /* Test csum_continue(). */ partial = 0; for (i = 0; i < tc->size / 4; i++) { if (i) { partial = csum_continue(partial, &data32[i], 4); } else { partial = csum_continue(partial, &data16[i * 2], 2); partial = csum_continue(partial, &data16[i * 2 + 1], 2); } } assert(ntohs(csum_finish(partial)) == tc->csum); mark('#'); } test_rfc1624(); /* Test recalc_csum16(). */ for (i = 0; i < 32; i++) { uint16_t old_u16, new_u16; uint16_t old_csum; uint16_t data[16]; int j, index; for (j = 0; j < ARRAY_SIZE(data); j++) { data[j] = random_uint32(); } old_csum = csum(data, sizeof data); index = random_range(ARRAY_SIZE(data)); old_u16 = data[index]; new_u16 = data[index] = random_uint32(); assert(csum(data, sizeof data) == recalc_csum16(old_csum, old_u16, new_u16)); mark('.'); } mark('#'); /* Test recalc_csum32(). */ for (i = 0; i < 32; i++) { uint32_t old_u32, new_u32; uint16_t old_csum; uint32_t data[16]; int j, index; for (j = 0; j < ARRAY_SIZE(data); j++) { data[j] = random_uint32(); } old_csum = csum(data, sizeof data); index = random_range(ARRAY_SIZE(data)); old_u32 = data[index]; new_u32 = data[index] = random_uint32(); assert(csum(data, sizeof data) == recalc_csum32(old_csum, old_u32, new_u32)); mark('.'); } mark('#'); putchar('\n'); return 0; }
static void set_field(struct packet *pkt, struct ofl_action_set_field *act ) { packet_handle_std_validate(pkt->handle_std); if (pkt->handle_std->valid) { struct packet_fields *iter; /* Search field on the description of the packet. */ HMAP_FOR_EACH_WITH_HASH(iter,struct packet_fields, hmap_node, hash_int(act->field->header,0), &pkt->handle_std->match.match_fields) { /* TODO: Checksum for SCTP and ICMP */ if (iter->header == OXM_OF_IPV4_SRC || iter->header == OXM_OF_IPV4_DST || iter->header == OXM_OF_IP_DSCP || iter->header == OXM_OF_IP_ECN) { uint16_t *aux_old ; aux_old = (uint16_t *)malloc(sizeof(uint16_t)); memcpy(aux_old, ((uint8_t*)pkt->buffer->data + iter->pos - 1) , (2 * OXM_LENGTH(iter->header))); if (iter->header == OXM_OF_IP_DSCP) { uint8_t* aux; aux = (uint8_t *)malloc(OXM_LENGTH(iter->header)); memcpy(aux,((uint8_t*)pkt->buffer->data + iter->pos) , OXM_LENGTH(iter->header)); *aux = *aux ^ ((*act->field->value) << 2 ); memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , aux , OXM_LENGTH(iter->header)); free(aux); } else if (iter->header == OXM_OF_IP_ECN) { memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , act->field->value , OXM_LENGTH(iter->header)); } else { memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , act->field->value , OXM_LENGTH(iter->header)); } // update TCP/UDP checksum struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; if (pkt->handle_std->proto->tcp != NULL) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; if (iter->header == OXM_OF_IPV4_SRC) { tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, ipv4->ip_src,htonl(*((uint32_t*) act->field->value))); } else if (iter->header == OXM_OF_IPV4_DST) { tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, ipv4->ip_dst,htonl(*((uint32_t*) act->field->value))); } } else if (pkt->handle_std->proto->udp != NULL) { struct udp_header *udp = pkt->handle_std->proto->udp; if (iter->header == OXM_OF_IPV4_SRC) { udp->udp_csum = recalc_csum32(udp->udp_csum, ipv4->ip_src, htonl(*((uint32_t*) act->field->value))); } else if (iter->header == OXM_OF_IPV4_DST) { udp->udp_csum = recalc_csum32(udp->udp_csum, ipv4->ip_dst, htonl(*((uint32_t*) act->field->value))); } } if (iter->header == OXM_OF_IP_DSCP || iter->header == OXM_OF_IP_ECN) { uint16_t *aux ; aux = (uint16_t *)malloc(sizeof(uint16_t)); memcpy(aux, ((uint8_t*)pkt->buffer->data + iter->pos - 1) , (2 * OXM_LENGTH(iter->header))); ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, *aux_old, *aux); free(aux); } else if (iter->header == OXM_OF_IPV4_SRC) { ipv4->ip_csum = recalc_csum32(ipv4->ip_csum, ipv4->ip_src, htonl(*((uint32_t*) act->field->value))); } else { ipv4->ip_csum = recalc_csum32(ipv4->ip_csum, ipv4->ip_dst, htonl(*((uint32_t*) act->field->value))); } pkt->handle_std->valid = false; packet_handle_std_validate(pkt->handle_std); free(aux_old); return; } if (iter->header == OXM_OF_TCP_SRC) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_src, htons(*((uint16_t*) act->field->value))); } else if (iter->header == OXM_OF_TCP_DST) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_dst, htons(*((uint16_t*) act->field->value))); } else if (iter->header == OXM_OF_UDP_SRC) { struct udp_header *udp = pkt->handle_std->proto->udp; udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_src, htons(*((uint16_t*) act->field->value))); } else if (iter->header == OXM_OF_UDP_DST) { struct udp_header *udp = pkt->handle_std->proto->udp; udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, htons(*((uint16_t*) act->field->value))); } if (iter->header == OXM_OF_IPV6_SRC || iter->header == OXM_OF_IPV6_DST || iter->header == OXM_OF_ETH_SRC || iter->header == OXM_OF_ETH_DST || iter->header == OXM_OF_ARP_SPA || iter->header == OXM_OF_ARP_TPA || iter->header == OXM_OF_ARP_SHA || iter->header == OXM_OF_ARP_THA) { memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , act->field->value , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } /* Found the field, lets re-write it!! */ uint8_t* tmp = (uint8_t*) malloc(OXM_LENGTH(iter->header)); uint8_t i; for (i=0;i<OXM_LENGTH(iter->header);i++) { memcpy(((uint8_t*)tmp + i) , (act->field->value + OXM_LENGTH(iter->header) - i -1 ), 1); } memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , tmp , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute SET_FIELD action on packet with no corresponding field."); } }
int main(void) { const struct test_case *tc; int i; for (tc = test_cases; tc < &test_cases[ARRAY_SIZE(test_cases)]; tc++) { const void *data = tc->data; const ovs_be16 *data16 = (OVS_FORCE const ovs_be16 *) data; const ovs_be32 *data32 = (OVS_FORCE const ovs_be32 *) data; uint32_t partial; /* Test csum(). */ assert(ntohs(csum(tc->data, tc->size)) == tc->csum); mark('.'); /* Test csum_add16(). */ partial = 0; for (i = 0; i < tc->size / 2; i++) { partial = csum_add16(partial, get_unaligned_be16(&data16[i])); } assert(ntohs(csum_finish(partial)) == tc->csum); mark('.'); /* Test csum_add32(). */ partial = 0; for (i = 0; i < tc->size / 4; i++) { partial = csum_add32(partial, get_unaligned_be32(&data32[i])); } assert(ntohs(csum_finish(partial)) == tc->csum); mark('.'); /* Test alternating csum_add16() and csum_add32(). */ partial = 0; for (i = 0; i < tc->size / 4; i++) { if (i % 2) { partial = csum_add32(partial, get_unaligned_be32(&data32[i])); } else { ovs_be16 u0 = get_unaligned_be16(&data16[i * 2]); ovs_be16 u1 = get_unaligned_be16(&data16[i * 2 + 1]); partial = csum_add16(partial, u0); partial = csum_add16(partial, u1); } } assert(ntohs(csum_finish(partial)) == tc->csum); mark('.'); /* Test csum_continue(). */ partial = 0; for (i = 0; i < tc->size / 4; i++) { if (i) { partial = csum_continue(partial, &data32[i], 4); } else { partial = csum_continue(partial, &data16[i * 2], 2); partial = csum_continue(partial, &data16[i * 2 + 1], 2); } } assert(ntohs(csum_finish(partial)) == tc->csum); mark('#'); } test_rfc1624(); /* Test recalc_csum16(). */ for (i = 0; i < 32; i++) { ovs_be16 old_u16, new_u16; ovs_be16 old_csum; ovs_be16 data[16]; int j, index; for (j = 0; j < ARRAY_SIZE(data); j++) { data[j] = (OVS_FORCE ovs_be16) random_uint32(); } old_csum = csum(data, sizeof data); index = random_range(ARRAY_SIZE(data)); old_u16 = data[index]; new_u16 = data[index] = (OVS_FORCE ovs_be16) random_uint32(); assert(csum(data, sizeof data) == recalc_csum16(old_csum, old_u16, new_u16)); mark('.'); } mark('#'); /* Test recalc_csum32(). */ for (i = 0; i < 32; i++) { ovs_be32 old_u32, new_u32; ovs_be16 old_csum; ovs_be32 data[16]; int j, index; for (j = 0; j < ARRAY_SIZE(data); j++) { data[j] = (OVS_FORCE ovs_be32) random_uint32(); } old_csum = csum(data, sizeof data); index = random_range(ARRAY_SIZE(data)); old_u32 = data[index]; new_u32 = data[index] = (OVS_FORCE ovs_be32) random_uint32(); assert(csum(data, sizeof data) == recalc_csum32(old_csum, old_u32, new_u32)); mark('.'); } mark('#'); putchar('\n'); return 0; }
void meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ size_t b; bool drop = false; entry->stats->packet_in_count++; entry->stats->byte_in_count += (*pkt)->buffer->size; b = choose_band(entry, *pkt); if(b != -1){ struct ofl_meter_band_header *band_header = (struct ofl_meter_band_header*) entry->config->bands[b]; switch(band_header->type){ case OFPMBT_DROP:{ drop = true; break; } case OFPMBT_DSCP_REMARK:{ packet_handle_std_validate((*pkt)->handle_std); if ((*pkt)->handle_std->valid) { struct ofl_meter_band_dscp_remark *band_header = (struct ofl_meter_band_dscp_remark *) entry->config->bands[b]; /* Nothing prevent this band to be used for non-IP packets, so filter them out. Jean II */ if ((*pkt)->handle_std->proto->ipv4 != NULL) { // Fetch dscp in ipv4 header struct ip_header *ipv4 = (*pkt)->handle_std->proto->ipv4; uint8_t old_drop = ipv4->ip_tos & 0x1C; /* The spec says that we need to increase the drop precedence of the packet. We need a valid DSCP out of the process, so we can only modify dscp if the drop precedence is low (tos 0x***010**) or medium (tos 0x***100**). Jean II */ if (((old_drop == 0x8) && (band_header->prec_level <= 2)) || ((old_drop == 0x10) && (band_header->prec_level <= 1))) { uint8_t new_drop = old_drop + (band_header->prec_level << 3); uint8_t new_tos = new_drop | (ipv4->ip_tos & 0xE3); uint16_t old_val = htons((ipv4->ip_ihl_ver << 8) + ipv4->ip_tos); uint16_t new_val = htons((ipv4->ip_ihl_ver << 8) + new_tos); ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); ipv4->ip_tos = new_tos; } } else if ((*pkt)->handle_std->proto->ipv6 != NULL){ struct ipv6_header *ipv6 = (*pkt)->handle_std->proto->ipv6; uint32_t ipv6_ver_tc_fl = ntohl(ipv6->ipv6_ver_tc_fl); uint32_t old_drop = ipv6_ver_tc_fl & 0x1C00000; if (((old_drop == 0x800000) && (band_header->prec_level <= 2)) || ((old_drop == 0x1000000) && (band_header->prec_level <= 1))){ uint32_t prec_level = band_header->prec_level << 23; uint32_t new_drop = old_drop + prec_level; ipv6->ipv6_ver_tc_fl = htonl(new_drop | (ipv6_ver_tc_fl & 0xFE3FFFFF)); } } (*pkt)->handle_std->valid = false; } break; } case OFPMBT_EXPERIMENTER:{ break; } } entry->stats->band_stats[b]->byte_band_count += (*pkt)->buffer->size; entry->stats->band_stats[b]->packet_band_count++; if (drop){ VLOG_DBG_RL(LOG_MODULE, &rl, "Dropping packet: rate %d", band_header->rate); packet_destroy(*pkt); *pkt = NULL; } } }
static void set_field(struct packet *pkt, struct ofl_action_set_field *act ) { packet_handle_std_validate(pkt->handle_std); if (pkt->handle_std->valid) { struct packet_fields *iter; /* Search field on the description of the packet. */ HMAP_FOR_EACH_WITH_HASH(iter,struct packet_fields, hmap_node, hash_int(act->field->header,0), &pkt->handle_std->match.match_fields) { struct ip_header *ipv4; struct mpls_header *mpls; struct vlan_header *vlan; uint8_t* tmp; size_t i; /* TODO: Checksum for SCTP and ICMP */ if (iter->header == OXM_OF_IPV4_SRC || iter->header == OXM_OF_IPV4_DST || iter->header == OXM_OF_IP_DSCP || iter->header == OXM_OF_IP_ECN) { uint16_t *aux_old ; aux_old = (uint16_t *)malloc(sizeof(uint16_t)); memcpy(aux_old, ((uint8_t*)pkt->buffer->data + iter->pos - 1) , (2 * OXM_LENGTH(iter->header))); if (iter->header == OXM_OF_IP_DSCP) { uint8_t* aux; aux = (uint8_t *)malloc(OXM_LENGTH(iter->header)); memcpy(aux,((uint8_t*)pkt->buffer->data + iter->pos) , OXM_LENGTH(iter->header)); *aux = *aux ^ ((*act->field->value) << 2 ); memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , aux , OXM_LENGTH(iter->header)); free(aux); } else if (iter->header == OXM_OF_IP_ECN) { memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , act->field->value , OXM_LENGTH(iter->header)); } else { memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , act->field->value , OXM_LENGTH(iter->header)); } // update TCP/UDP checksum ipv4 = pkt->handle_std->proto->ipv4; if (pkt->handle_std->proto->tcp != NULL) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; if (iter->header == OXM_OF_IPV4_SRC) { tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, ipv4->ip_src,htonl(*((uint32_t*) act->field->value))); } else if (iter->header == OXM_OF_IPV4_DST) { tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, ipv4->ip_dst,htonl(*((uint32_t*) act->field->value))); } } else if (pkt->handle_std->proto->udp != NULL) { struct udp_header *udp = pkt->handle_std->proto->udp; if (iter->header == OXM_OF_IPV4_SRC) { udp->udp_csum = recalc_csum32(udp->udp_csum, ipv4->ip_src, htonl(*((uint32_t*) act->field->value))); } else if (iter->header == OXM_OF_IPV4_DST) { udp->udp_csum = recalc_csum32(udp->udp_csum, ipv4->ip_dst, htonl(*((uint32_t*) act->field->value))); } } if (iter->header == OXM_OF_IP_DSCP || iter->header == OXM_OF_IP_ECN) { uint16_t *aux ; aux = (uint16_t *)malloc(sizeof(uint16_t)); memcpy(aux, ((uint8_t*)pkt->buffer->data + iter->pos - 1) , (2 * OXM_LENGTH(iter->header))); ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, *aux_old, *aux); free(aux); } else if (iter->header == OXM_OF_IPV4_SRC) { ipv4->ip_csum = recalc_csum32(ipv4->ip_csum, ipv4->ip_src, htonl(*((uint32_t*) act->field->value))); } else { ipv4->ip_csum = recalc_csum32(ipv4->ip_csum, ipv4->ip_dst, htonl(*((uint32_t*) act->field->value))); } pkt->handle_std->valid = false; packet_handle_std_validate(pkt->handle_std); free(aux_old); return; } if (iter->header == OXM_OF_TCP_SRC) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_src, htons(*((uint16_t*) act->field->value))); } else if (iter->header == OXM_OF_TCP_DST) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_dst, htons(*((uint16_t*) act->field->value))); } else if (iter->header == OXM_OF_UDP_SRC) { struct udp_header *udp = pkt->handle_std->proto->udp; udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_src, htons(*((uint16_t*) act->field->value))); } else if (iter->header == OXM_OF_UDP_DST) { struct udp_header *udp = pkt->handle_std->proto->udp; udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, htons(*((uint16_t*) act->field->value))); } if (iter->header == OXM_OF_IPV6_SRC || iter->header == OXM_OF_IPV6_DST || iter->header == OXM_OF_ETH_SRC || iter->header == OXM_OF_ETH_DST || iter->header == OXM_OF_ARP_SPA || iter->header == OXM_OF_ARP_TPA || iter->header == OXM_OF_ARP_SHA || iter->header == OXM_OF_ARP_THA) { memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , act->field->value , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } if (iter->header == OXM_OF_VLAN_VID){ uint16_t vlan_id = *((uint16_t*) act->field->value); vlan = pkt->handle_std->proto->vlan; vlan->vlan_tci = htons((ntohs(vlan->vlan_tci) & ~VLAN_VID_MASK) | (vlan_id & VLAN_VID_MASK)); memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , &vlan->vlan_tci , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } if (iter->header == OXM_OF_VLAN_PCP){ uint8_t vlan_pcp = *((uint8_t*) act->field->value); vlan = pkt->handle_std->proto->vlan; vlan->vlan_tci = htons((ntohs(vlan->vlan_tci) & ~VLAN_PCP_MASK) | ((vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK)); memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , &vlan->vlan_tci , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } if (iter->header == OXM_OF_MPLS_LABEL){ uint32_t mpls_label = *((uint32_t*) act->field->value); mpls = pkt->handle_std->proto->mpls; mpls->fields = (mpls->fields & ~ntohl(MPLS_LABEL_MASK)) | ntohl((mpls_label << MPLS_LABEL_SHIFT) & MPLS_LABEL_MASK); memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , &mpls->fields , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } if (iter->header == OXM_OF_MPLS_TC){ mpls = pkt->handle_std->proto->mpls; mpls->fields = (mpls->fields & ~ntohl(MPLS_TC_MASK)) | ntohl((*act->field->value << MPLS_TC_SHIFT) & MPLS_TC_MASK); memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , &mpls->fields , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } if (iter->header == OXM_OF_MPLS_BOS){ mpls = pkt->handle_std->proto->mpls; mpls->fields = (mpls->fields & ~ntohl(MPLS_S_MASK)) | ntohl((*act->field->value << MPLS_S_SHIFT) & MPLS_S_MASK); memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , &mpls->fields , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } tmp = (uint8_t*) malloc(OXM_LENGTH(iter->header)); for (i=0;i<OXM_LENGTH(iter->header);i++) { memcpy(((uint8_t*)tmp + i) , (act->field->value + OXM_LENGTH(iter->header) - i -1 ), 1); } memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , tmp , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute SET_FIELD action on packet with no corresponding field."); } }