Example #1
0
/* 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;
    }
}
Example #2
0
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;
    }
}
Example #3
0
/* 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;
}
Example #4
0
/* 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.");
    }
}
Example #5
0
/* 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.");
    }
}
Example #6
0
/* 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('#');
}
Example #7
0
/* 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;
    }

}
Example #9
0
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;
}
Example #10
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.");
    }

}
Example #11
0
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;
}
Example #12
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.");
    }

}