Example #1
0
/* Initializes 'flow' members from 'packet', 'skb_priority', 'tnl', and
 * 'ofp_in_port'.
 *
 * Initializes 'packet' header pointers as follows:
 *
 *    - packet->l2 to the start of the Ethernet header.
 *
 *    - packet->l2_5 to the start of the MPLS shim header.
 *
 *    - packet->l3 to just past the Ethernet header, or just past the
 *      vlan_header if one is present, to the first byte of the payload of the
 *      Ethernet frame.
 *
 *    - packet->l4 to just past the IPv4 header, if one is present and has a
 *      correct length, and otherwise NULL.
 *
 *    - packet->l7 to just past the TCP or UDP or ICMP header, if one is
 *      present and has a correct length, and otherwise NULL.
 */
void
flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t skb_mark,
             const struct flow_tnl *tnl, uint16_t ofp_in_port,
             struct flow *flow)
{
    struct ofpbuf b = *packet;
    struct eth_header *eth;

    COVERAGE_INC(flow_extract);

    memset(flow, 0, sizeof *flow);

    if (tnl) {
        ovs_assert(tnl != &flow->tunnel);
        flow->tunnel = *tnl;
    }
    flow->in_port = ofp_in_port;
    flow->skb_priority = skb_priority;
    flow->skb_mark = skb_mark;

    packet->l2   = b.data;
    packet->l2_5 = NULL;
    packet->l3   = NULL;
    packet->l4   = NULL;
    packet->l7   = NULL;

    if (b.size < sizeof *eth) {
        return;
    }

    /* Link layer. */
    eth = b.data;
    memcpy(flow->dl_src, eth->eth_src, ETH_ADDR_LEN);
    memcpy(flow->dl_dst, eth->eth_dst, ETH_ADDR_LEN);

    /* dl_type, vlan_tci. */
    ofpbuf_pull(&b, ETH_ADDR_LEN * 2);
    if (eth->eth_type == htons(ETH_TYPE_VLAN)) {
        parse_vlan(&b, flow);
    }
    flow->dl_type = parse_ethertype(&b);

    /* Parse mpls, copy l3 ttl. */
    if (eth_type_mpls(flow->dl_type)) {
        packet->l2_5 = b.data;
        parse_mpls(&b, flow);
    }

    packet->l3 = b.data;
    flow_extract_l3_onwards(packet, flow, flow->dl_type);
}
Example #2
0
/* Puts into 'b' a packet that flow_extract() would parse as having the given
 * 'flow'.
 *
 * (This is useful only for testing, obviously, and the packet isn't really
 * valid. It hasn't got some checksums filled in, for one, and lots of fields
 * are just zeroed.) */
void
flow_compose(struct ofpbuf *b, const struct flow *flow)
{
    eth_compose(b, flow->dl_dst, flow->dl_src, ntohs(flow->dl_type), 0);
    if (flow->dl_type == htons(FLOW_DL_TYPE_NONE)) {
        struct eth_header *eth = b->l2;
        eth->eth_type = htons(b->size);
        return;
    }

    if (flow->vlan_tci & htons(VLAN_CFI)) {
        eth_push_vlan(b, flow->vlan_tci);
    }

    if (flow->dl_type == htons(ETH_TYPE_IP)) {
        struct ip_header *ip;

        b->l3 = ip = ofpbuf_put_zeros(b, sizeof *ip);
        ip->ip_ihl_ver = IP_IHL_VER(5, 4);
        ip->ip_tos = flow->nw_tos;
        ip->ip_ttl = flow->nw_ttl;
        ip->ip_proto = flow->nw_proto;
        put_16aligned_be32(&ip->ip_src, flow->nw_src);
        put_16aligned_be32(&ip->ip_dst, flow->nw_dst);

        if (flow->nw_frag & FLOW_NW_FRAG_ANY) {
            ip->ip_frag_off |= htons(IP_MORE_FRAGMENTS);
            if (flow->nw_frag & FLOW_NW_FRAG_LATER) {
                ip->ip_frag_off |= htons(100);
            }
        }
        if (!(flow->nw_frag & FLOW_NW_FRAG_ANY)
            || !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
            if (flow->nw_proto == IPPROTO_TCP) {
                struct tcp_header *tcp;

                b->l4 = tcp = ofpbuf_put_zeros(b, sizeof *tcp);
                tcp->tcp_src = flow->tp_src;
                tcp->tcp_dst = flow->tp_dst;
                tcp->tcp_ctl = TCP_CTL(0, 5);
            } else if (flow->nw_proto == IPPROTO_UDP) {
                struct udp_header *udp;

                b->l4 = udp = ofpbuf_put_zeros(b, sizeof *udp);
                udp->udp_src = flow->tp_src;
                udp->udp_dst = flow->tp_dst;
            } else if (flow->nw_proto == IPPROTO_SCTP) {
                struct sctp_header *sctp;

                b->l4 = sctp = ofpbuf_put_zeros(b, sizeof *sctp);
                sctp->sctp_src = flow->tp_src;
                sctp->sctp_dst = flow->tp_dst;
            } else if (flow->nw_proto == IPPROTO_ICMP) {
                struct icmp_header *icmp;

                b->l4 = icmp = ofpbuf_put_zeros(b, sizeof *icmp);
                icmp->icmp_type = ntohs(flow->tp_src);
                icmp->icmp_code = ntohs(flow->tp_dst);
                icmp->icmp_csum = csum(icmp, ICMP_HEADER_LEN);
            }
        }

        ip = b->l3;
        ip->ip_tot_len = htons((uint8_t *) b->data + b->size
                               - (uint8_t *) b->l3);
        ip->ip_csum = csum(ip, sizeof *ip);
    } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
        /* XXX */
    } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
               flow->dl_type == htons(ETH_TYPE_RARP)) {
        struct arp_eth_header *arp;

        b->l3 = arp = ofpbuf_put_zeros(b, sizeof *arp);
        arp->ar_hrd = htons(1);
        arp->ar_pro = htons(ETH_TYPE_IP);
        arp->ar_hln = ETH_ADDR_LEN;
        arp->ar_pln = 4;
        arp->ar_op = htons(flow->nw_proto);

        if (flow->nw_proto == ARP_OP_REQUEST ||
            flow->nw_proto == ARP_OP_REPLY) {
            put_16aligned_be32(&arp->ar_spa, flow->nw_src);
            put_16aligned_be32(&arp->ar_tpa, flow->nw_dst);
            memcpy(arp->ar_sha, flow->arp_sha, ETH_ADDR_LEN);
            memcpy(arp->ar_tha, flow->arp_tha, ETH_ADDR_LEN);
        }
    }

    if (eth_type_mpls(flow->dl_type)) {
        b->l2_5 = b->l3;
        push_mpls(b, flow->dl_type, flow->mpls_lse);
    }
}
Example #3
0
/* Initializes 'flow' members from 'packet', 'skb_priority', 'tnl', and
 * 'in_port'.
 *
 * Initializes 'packet' header pointers as follows:
 *
 *    - packet->l2 to the start of the Ethernet header.
 *
 *    - packet->l2_5 to the start of the MPLS shim header.
 *
 *    - packet->l3 to just past the Ethernet header, or just past the
 *      vlan_header if one is present, to the first byte of the payload of the
 *      Ethernet frame.
 *
 *    - packet->l4 to just past the IPv4 header, if one is present and has a
 *      correct length, and otherwise NULL.
 *
 *    - packet->l7 to just past the TCP/UDP/SCTP/ICMP header, if one is
 *      present and has a correct length, and otherwise NULL.
 */
void
flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t pkt_mark,
             const struct flow_tnl *tnl, const union flow_in_port *in_port,
             struct flow *flow)
{
    struct ofpbuf b = *packet;
    struct eth_header *eth;

    COVERAGE_INC(flow_extract);

    memset(flow, 0, sizeof *flow);

    if (tnl) {
        ovs_assert(tnl != &flow->tunnel);
        flow->tunnel = *tnl;
    }
    if (in_port) {
        flow->in_port = *in_port;
    }
    flow->skb_priority = skb_priority;
    flow->pkt_mark = pkt_mark;

    packet->l2   = b.data;
    packet->l2_5 = NULL;
    packet->l3   = NULL;
    packet->l4   = NULL;
    packet->l7   = NULL;

    if (b.size < sizeof *eth) {
        return;
    }

    /* Link layer. */
    eth = b.data;
    memcpy(flow->dl_src, eth->eth_src, ETH_ADDR_LEN);
    memcpy(flow->dl_dst, eth->eth_dst, ETH_ADDR_LEN);

    /* dl_type, vlan_tci. */
    ofpbuf_pull(&b, ETH_ADDR_LEN * 2);
    if (eth->eth_type == htons(ETH_TYPE_VLAN)) {
        parse_vlan(&b, flow);
    }
    flow->dl_type = parse_ethertype(&b);

    /* Parse mpls, copy l3 ttl. */
    if (eth_type_mpls(flow->dl_type)) {
        packet->l2_5 = b.data;
        parse_mpls(&b, flow);
    }

    /* Network layer. */
    packet->l3 = b.data;
    if (flow->dl_type == htons(ETH_TYPE_IP)) {
        const struct ip_header *nh = pull_ip(&b);
        if (nh) {
            packet->l4 = b.data;

            flow->nw_src = get_16aligned_be32(&nh->ip_src);
            flow->nw_dst = get_16aligned_be32(&nh->ip_dst);
            flow->nw_proto = nh->ip_proto;

            flow->nw_tos = nh->ip_tos;
            if (IP_IS_FRAGMENT(nh->ip_frag_off)) {
                flow->nw_frag = FLOW_NW_FRAG_ANY;
                if (nh->ip_frag_off & htons(IP_FRAG_OFF_MASK)) {
                    flow->nw_frag |= FLOW_NW_FRAG_LATER;
                }
            }
            flow->nw_ttl = nh->ip_ttl;

            if (!(nh->ip_frag_off & htons(IP_FRAG_OFF_MASK))) {
                if (flow->nw_proto == IPPROTO_TCP) {
                    parse_tcp(packet, &b, flow);
                } else if (flow->nw_proto == IPPROTO_UDP) {
                    parse_udp(packet, &b, flow);
                } else if (flow->nw_proto == IPPROTO_SCTP) {
                    parse_sctp(packet, &b, flow);
                } else if (flow->nw_proto == IPPROTO_ICMP) {
                    const struct icmp_header *icmp = pull_icmp(&b);
                    if (icmp) {
                        flow->tp_src = htons(icmp->icmp_type);
                        flow->tp_dst = htons(icmp->icmp_code);
                        packet->l7 = b.data;
                    }
                }
            }
        }
    } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
        if (parse_ipv6(&b, flow)) {
            return;
        }

        packet->l4 = b.data;
        if (flow->nw_proto == IPPROTO_TCP) {
            parse_tcp(packet, &b, flow);
        } else if (flow->nw_proto == IPPROTO_UDP) {
            parse_udp(packet, &b, flow);
        } else if (flow->nw_proto == IPPROTO_SCTP) {
            parse_sctp(packet, &b, flow);
        } else if (flow->nw_proto == IPPROTO_ICMPV6) {
            if (parse_icmpv6(&b, flow)) {
                packet->l7 = b.data;
            }
        }
    } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
               flow->dl_type == htons(ETH_TYPE_RARP)) {
        const struct arp_eth_header *arp = pull_arp(&b);
        if (arp && arp->ar_hrd == htons(1)
            && arp->ar_pro == htons(ETH_TYPE_IP)
            && arp->ar_hln == ETH_ADDR_LEN
            && arp->ar_pln == 4) {
            /* We only match on the lower 8 bits of the opcode. */
            if (ntohs(arp->ar_op) <= 0xff) {
                flow->nw_proto = ntohs(arp->ar_op);
            }

            flow->nw_src = get_16aligned_be32(&arp->ar_spa);
            flow->nw_dst = get_16aligned_be32(&arp->ar_tpa);
            memcpy(flow->arp_sha, arp->ar_sha, ETH_ADDR_LEN);
            memcpy(flow->arp_tha, arp->ar_tha, ETH_ADDR_LEN);
        }
    }
}
Example #4
0
/* Converts a flow into a match.  It sets the wildcard masks based on
 * the packet contents.  It will not set the mask for fields that do not
 * make sense for the packet type. */
void
match_wc_init(struct match *match, const struct flow *flow)
{
    struct flow_wildcards *wc;
    int i;

    match->flow = *flow;
    wc = &match->wc;
    memset(&wc->masks, 0x0, sizeof wc->masks);

    memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);

    if (flow->nw_proto) {
        memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
    }

    if (flow->skb_priority) {
        memset(&wc->masks.skb_priority, 0xff, sizeof wc->masks.skb_priority);
    }

    if (flow->pkt_mark) {
        memset(&wc->masks.pkt_mark, 0xff, sizeof wc->masks.pkt_mark);
    }

    for (i = 0; i < FLOW_N_REGS; i++) {
        if (flow->regs[i]) {
            memset(&wc->masks.regs[i], 0xff, sizeof wc->masks.regs[i]);
        }
    }

    if (flow->tunnel.ip_dst) {
        if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
            memset(&wc->masks.tunnel.tun_id, 0xff, sizeof wc->masks.tunnel.tun_id);
        }
        memset(&wc->masks.tunnel.ip_src, 0xff, sizeof wc->masks.tunnel.ip_src);
        memset(&wc->masks.tunnel.ip_dst, 0xff, sizeof wc->masks.tunnel.ip_dst);
        memset(&wc->masks.tunnel.flags, 0xff, sizeof wc->masks.tunnel.flags);
        memset(&wc->masks.tunnel.ip_tos, 0xff, sizeof wc->masks.tunnel.ip_tos);
        memset(&wc->masks.tunnel.ip_ttl, 0xff, sizeof wc->masks.tunnel.ip_ttl);
    } else if (flow->tunnel.tun_id) {
        memset(&wc->masks.tunnel.tun_id, 0xff, sizeof wc->masks.tunnel.tun_id);
    }

    memset(&wc->masks.metadata, 0xff, sizeof wc->masks.metadata);
    memset(&wc->masks.in_port, 0xff, sizeof wc->masks.in_port);
    memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
    memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
    memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);

    if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
        memset(&wc->masks.ipv6_src, 0xff, sizeof wc->masks.ipv6_src);
        memset(&wc->masks.ipv6_dst, 0xff, sizeof wc->masks.ipv6_dst);
        memset(&wc->masks.ipv6_label, 0xff, sizeof wc->masks.ipv6_label);
    } else if (flow->dl_type == htons(ETH_TYPE_IP) ||
               (flow->dl_type == htons(ETH_TYPE_ARP)) ||
               (flow->dl_type == htons(ETH_TYPE_RARP))) {
        memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
        memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
    } else if (eth_type_mpls(flow->dl_type)) {
        int i;

        for (i = 0; i < FLOW_MAX_MPLS_LABELS; i++) {
            wc->masks.mpls_lse[i] = OVS_BE32_MAX;
            if (flow->mpls_lse[i] & htonl(MPLS_BOS_MASK)) {
                break;
            }
        }
    }

    if (flow->dl_type == htons(ETH_TYPE_ARP) ||
        flow->dl_type == htons(ETH_TYPE_RARP)) {
        memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha);
        memset(&wc->masks.arp_tha, 0xff, sizeof wc->masks.arp_tha);
    }

    if (is_ip_any(flow)) {
        memset(&wc->masks.nw_tos, 0xff, sizeof wc->masks.nw_tos);
        memset(&wc->masks.nw_ttl, 0xff, sizeof wc->masks.nw_ttl);

        if (flow->nw_frag) {
            memset(&wc->masks.nw_frag, 0xff, sizeof wc->masks.nw_frag);
            if (flow->nw_frag & FLOW_NW_FRAG_LATER) {
                /* No transport layer header in later fragments. */
                return;
            }
        }

        if (flow->nw_proto == IPPROTO_ICMP ||
            flow->nw_proto == IPPROTO_ICMPV6 ||
            (flow->tp_src || flow->tp_dst)) {
            memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
            memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
        }
        if (flow->nw_proto == IPPROTO_TCP) {
            memset(&wc->masks.tcp_flags, 0xff, sizeof wc->masks.tcp_flags);
        }

        if (flow->nw_proto == IPPROTO_ICMPV6) {
            memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha);
            memset(&wc->masks.arp_tha, 0xff, sizeof wc->masks.arp_tha);
            memset(&wc->masks.nd_target, 0xff, sizeof wc->masks.nd_target);
        }
    }

    return;
}
Example #5
0
/* Converts a flow into a match.  It sets the wildcard masks based on
 * the packet contents.  It will not set the mask for fields that do not
 * make sense for the packet type. */
void
match_wc_init(struct match *match, const struct flow *flow)
{
    struct flow_wildcards *wc;
    int i;

    match->flow = *flow;
    wc = &match->wc;
    memset(&wc->masks, 0x0, sizeof wc->masks);

    memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);

    if (flow->nw_proto) {
        memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
    }

    if (flow->skb_priority) {
        memset(&wc->masks.skb_priority, 0xff, sizeof wc->masks.skb_priority);
    }

    if (flow->pkt_mark) {
        memset(&wc->masks.pkt_mark, 0xff, sizeof wc->masks.pkt_mark);
    }

    for (i = 0; i < FLOW_N_REGS; i++) {
        if (flow->regs[i]) {
            memset(&wc->masks.regs[i], 0xff, sizeof wc->masks.regs[i]);
        }
    }

    if (flow->tunnel.ip_dst) {
        if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
            memset(&wc->masks.tunnel.tun_id, 0xff, sizeof wc->masks.tunnel.tun_id);
        }
        memset(&wc->masks.tunnel.ip_src, 0xff, sizeof wc->masks.tunnel.ip_src);
        memset(&wc->masks.tunnel.ip_dst, 0xff, sizeof wc->masks.tunnel.ip_dst);
        memset(&wc->masks.tunnel.flags, 0xff, sizeof wc->masks.tunnel.flags);
        memset(&wc->masks.tunnel.ip_tos, 0xff, sizeof wc->masks.tunnel.ip_tos);
        memset(&wc->masks.tunnel.ip_ttl, 0xff, sizeof wc->masks.tunnel.ip_ttl);
    } else if (flow->tunnel.tun_id) {
        memset(&wc->masks.tunnel.tun_id, 0xff, sizeof wc->masks.tunnel.tun_id);
    }

    memset(&wc->masks.metadata, 0xff, sizeof wc->masks.metadata);
    memset(&wc->masks.in_port, 0xff, sizeof wc->masks.in_port);
    memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
    memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
    memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);

    if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
        memset(&wc->masks.ipv6_src, 0xff, sizeof wc->masks.ipv6_src);
        memset(&wc->masks.ipv6_dst, 0xff, sizeof wc->masks.ipv6_dst);
        memset(&wc->masks.ipv6_label, 0xff, sizeof wc->masks.ipv6_label);
    } else if (flow->dl_type == htons(ETH_TYPE_IP) ||
               (flow->dl_type == htons(ETH_TYPE_ARP)) ||
               (flow->dl_type == htons(ETH_TYPE_RARP))) {
        memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
        memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
    } else if (eth_type_mpls(flow->dl_type)) {
        memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse);
    }

    if (flow->dl_type == htons(ETH_TYPE_ARP) ||
        flow->dl_type == htons(ETH_TYPE_RARP)) {
        memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha);
        memset(&wc->masks.arp_tha, 0xff, sizeof wc->masks.arp_tha);
    }

    if (is_ip_any(flow)) {
        memset(&wc->masks.nw_tos, 0xff, sizeof wc->masks.nw_tos);
        memset(&wc->masks.nw_ttl, 0xff, sizeof wc->masks.nw_ttl);

        if (flow->nw_frag) {
            memset(&wc->masks.nw_frag, 0xff, sizeof wc->masks.nw_frag);
        }

        if (flow->nw_proto == IPPROTO_ICMP ||
            flow->nw_proto == IPPROTO_ICMPV6 ||
            (flow->tp_src || flow->tp_dst)) {
            memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
            memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
        }
        if (flow->nw_proto == IPPROTO_TCP &&
            flow->tcp_flags != 0) { /* XXX: How about matching zero flags? */
            memset(&wc->masks.tcp_flags, 0xff, sizeof wc->masks.tcp_flags);
        }

        if (flow->nw_proto == IPPROTO_ICMPV6) {
            memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha);
            memset(&wc->masks.arp_tha, 0xff, sizeof wc->masks.arp_tha);
        }
    }

    return;
}