/* Executes set nw dst action. */ static void set_nw_dst(struct packet *pkt, struct ofl_action_nw_addr *act) { packet_handle_std_validate(pkt->handle_std); if (pkt->handle_std->proto->ipv4 != NULL) { struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; // update TCP/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, act->nw_addr); } 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, act->nw_addr); } ipv4->ip_csum = recalc_csum32(ipv4->ip_csum, ipv4->ip_dst, act->nw_addr); ipv4->ip_dst = act->nw_addr; pkt->handle_std->match->nw_dst = act->nw_addr; } else { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute SET_NW_DST action on packet with no nw."); } }
static void packet_set_ipv4_addr(struct ofpbuf *packet, ovs_be32 *addr, ovs_be32 new_addr) { struct ip_header *nh = packet->l3; if (nh->ip_proto == IPPROTO_TCP && packet->l7) { struct tcp_header *th = packet->l4; th->tcp_csum = recalc_csum32(th->tcp_csum, *addr, new_addr); } else if (nh->ip_proto == IPPROTO_UDP && packet->l7) { struct udp_header *uh = packet->l4; if (uh->udp_csum) { uh->udp_csum = recalc_csum32(uh->udp_csum, *addr, new_addr); if (!uh->udp_csum) { uh->udp_csum = htons(0xffff); } } } nh->ip_csum = recalc_csum32(nh->ip_csum, *addr, new_addr); *addr = new_addr; }
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; }
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."); } }