X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fflow.c;h=ab49b80027694cd17da6c543f39ce2a1c6e33c5d;hb=69fc54f47bbc35e81bfe2e38e57f5dcfd9858df4;hp=397bda161835999f70ab464dbc6f41c05642e02b;hpb=67680b012be30d9c26eab999b83b08c6eb32dbd2;p=sliver-openvswitch.git diff --git a/lib/flow.c b/lib/flow.c index 397bda161..ab49b8002 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -81,6 +81,12 @@ pull_udp(struct ofpbuf *packet) return ofpbuf_try_pull(packet, UDP_HEADER_LEN); } +static struct sctp_header * +pull_sctp(struct ofpbuf *packet) +{ + return ofpbuf_try_pull(packet, SCTP_HEADER_LEN); +} + static struct icmp_header * pull_icmp(struct ofpbuf *packet) { @@ -229,9 +235,8 @@ parse_ipv6(struct ofpbuf *packet, struct flow *flow) /* We only process the first fragment. */ if (frag_hdr->ip6f_offlg != htons(0)) { - if ((frag_hdr->ip6f_offlg & IP6F_OFF_MASK) == htons(0)) { - flow->nw_frag = FLOW_NW_FRAG_ANY; - } else { + flow->nw_frag = FLOW_NW_FRAG_ANY; + if ((frag_hdr->ip6f_offlg & IP6F_OFF_MASK) != htons(0)) { flow->nw_frag |= FLOW_NW_FRAG_LATER; nexthdr = IPPROTO_FRAGMENT; break; @@ -266,6 +271,17 @@ parse_udp(struct ofpbuf *packet, struct ofpbuf *b, struct flow *flow) } } +static void +parse_sctp(struct ofpbuf *packet, struct ofpbuf *b, struct flow *flow) +{ + const struct sctp_header *sctp = pull_sctp(b); + if (sctp) { + flow->tp_src = sctp->sctp_src; + flow->tp_dst = sctp->sctp_dst; + packet->l7 = b->data; + } +} + static bool parse_icmpv6(struct ofpbuf *b, struct flow *flow) { @@ -338,7 +354,7 @@ invalid: } /* Initializes 'flow' members from 'packet', 'skb_priority', 'tnl', and - * 'ofp_in_port'. + * 'in_port'. * * Initializes 'packet' header pointers as follows: * @@ -353,12 +369,12 @@ invalid: * - 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 + * - 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 skb_mark, - const struct flow_tnl *tnl, uint16_t ofp_in_port, +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; @@ -372,9 +388,11 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t skb_mark, ovs_assert(tnl != &flow->tunnel); flow->tunnel = *tnl; } - flow->in_port = ofp_in_port; + if (in_port) { + flow->in_port = *in_port; + } flow->skb_priority = skb_priority; - flow->skb_mark = skb_mark; + flow->pkt_mark = pkt_mark; packet->l2 = b.data; packet->l2_5 = NULL; @@ -404,33 +422,9 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t skb_mark, parse_mpls(&b, flow); } - packet->l3 = b.data; - flow_extract_l3_onwards(packet, flow, flow->dl_type); -} - -/* Initializes l3 and higher 'flow' members from 'packet' - * - * This should be called by or after flow_extract() - * - * Initializes 'packet' header pointers as follows: - * - * - 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_l3_onwards(struct ofpbuf *packet, struct flow *flow, - ovs_be16 dl_type) -{ - struct ofpbuf b; - - ofpbuf_use_const(&b, packet->l3, packet->size - - (size_t)((char *)packet->l3 - (char *)packet->l2)); - /* Network layer. */ - if (dl_type == htons(ETH_TYPE_IP)) { + 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; @@ -453,6 +447,8 @@ flow_extract_l3_onwards(struct ofpbuf *packet, struct flow *flow, 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) { @@ -463,7 +459,7 @@ flow_extract_l3_onwards(struct ofpbuf *packet, struct flow *flow, } } } - } else if (dl_type == htons(ETH_TYPE_IPV6)) { + } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { if (parse_ipv6(&b, flow)) { return; } @@ -473,13 +469,15 @@ flow_extract_l3_onwards(struct ofpbuf *packet, struct flow *flow, 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 (dl_type == htons(ETH_TYPE_ARP) || - dl_type == htons(ETH_TYPE_RARP)) { + } 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) @@ -516,12 +514,15 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards) void flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd) { - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20); fmd->tun_id = flow->tunnel.tun_id; + fmd->tun_src = flow->tunnel.ip_src; + fmd->tun_dst = flow->tunnel.ip_dst; fmd->metadata = flow->metadata; memcpy(fmd->regs, flow->regs, sizeof fmd->regs); - fmd->in_port = flow->in_port; + fmd->pkt_mark = flow->pkt_mark; + fmd->in_port = flow->in_port.ofp_port; } char * @@ -627,13 +628,13 @@ flow_wildcards_is_catchall(const struct flow_wildcards *wc) return true; } -/* Initializes 'dst' as the combination of wildcards in 'src1' and 'src2'. - * That is, a bit or a field is wildcarded in 'dst' if it is wildcarded in - * 'src1' or 'src2' or both. */ +/* Sets 'dst' as the bitwise AND of wildcards in 'src1' and 'src2'. + * That is, a bit or a field is wildcarded in 'dst' if it is wildcarded + * in 'src1' or 'src2' or both. */ void -flow_wildcards_combine(struct flow_wildcards *dst, - const struct flow_wildcards *src1, - const struct flow_wildcards *src2) +flow_wildcards_and(struct flow_wildcards *dst, + const struct flow_wildcards *src1, + const struct flow_wildcards *src2) { uint32_t *dst_u32 = (uint32_t *) &dst->masks; const uint32_t *src1_u32 = (const uint32_t *) &src1->masks; @@ -645,6 +646,51 @@ flow_wildcards_combine(struct flow_wildcards *dst, } } +/* Sets 'dst' as the bitwise OR of wildcards in 'src1' and 'src2'. That + * is, a bit or a field is wildcarded in 'dst' if it is neither + * wildcarded in 'src1' nor 'src2'. */ +void +flow_wildcards_or(struct flow_wildcards *dst, + const struct flow_wildcards *src1, + const struct flow_wildcards *src2) +{ + uint32_t *dst_u32 = (uint32_t *) &dst->masks; + const uint32_t *src1_u32 = (const uint32_t *) &src1->masks; + const uint32_t *src2_u32 = (const uint32_t *) &src2->masks; + size_t i; + + for (i = 0; i < FLOW_U32S; i++) { + dst_u32[i] = src1_u32[i] | src2_u32[i]; + } +} + +/* Perform a bitwise OR of miniflow 'src' flow data with the equivalent + * fields in 'dst', storing the result in 'dst'. */ +static void +flow_union_with_miniflow(struct flow *dst, const struct miniflow *src) +{ + uint32_t *dst_u32 = (uint32_t *) dst; + int ofs; + int i; + + ofs = 0; + for (i = 0; i < MINI_N_MAPS; i++) { + uint32_t map; + + for (map = src->map[i]; map; map = zero_rightmost_1bit(map)) { + dst_u32[raw_ctz(map) + i * 32] |= src->values[ofs++]; + } + } +} + +/* Fold minimask 'mask''s wildcard mask into 'wc's wildcard mask. */ +void +flow_wildcards_fold_minimask(struct flow_wildcards *wc, + const struct minimask *mask) +{ + flow_union_with_miniflow(&wc->masks, &mask->masks); +} + /* Returns a hash of the wildcards in 'wc'. */ uint32_t flow_wildcards_hash(const struct flow_wildcards *wc, uint32_t basis) @@ -736,7 +782,7 @@ flow_hash_symmetric_l4(const struct flow *flow, uint32_t basis) if (fields.eth_type == htons(ETH_TYPE_IP)) { fields.ipv4_addr = flow->nw_src ^ flow->nw_dst; fields.ip_proto = flow->nw_proto; - if (fields.ip_proto == IPPROTO_TCP) { + if (fields.ip_proto == IPPROTO_TCP || fields.ip_proto == IPPROTO_SCTP) { fields.tp_port = flow->tp_src ^ flow->tp_dst; } } else if (fields.eth_type == htons(ETH_TYPE_IPV6)) { @@ -748,13 +794,46 @@ flow_hash_symmetric_l4(const struct flow *flow, uint32_t basis) ipv6_addr[i] = a[i] ^ b[i]; } fields.ip_proto = flow->nw_proto; - if (fields.ip_proto == IPPROTO_TCP) { + if (fields.ip_proto == IPPROTO_TCP || fields.ip_proto == IPPROTO_SCTP) { fields.tp_port = flow->tp_src ^ flow->tp_dst; } } return jhash_bytes(&fields, sizeof fields, basis); } +/* Masks the fields in 'wc' that are used by the flow hash 'fields'. */ +void +flow_mask_hash_fields(const struct flow *flow, struct flow_wildcards *wc, + enum nx_hash_fields fields) +{ + switch (fields) { + case NX_HASH_FIELDS_ETH_SRC: + memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src); + break; + + case NX_HASH_FIELDS_SYMMETRIC_L4: + 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_IP)) { + memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src); + memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst); + } else 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); + } + if (is_ip_any(flow)) { + memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); + memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src); + memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst); + } + wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI); + break; + + default: + NOT_REACHED(); + } +} + /* Hashes the portions of 'flow' designated by 'fields'. */ uint32_t flow_hash_fields(const struct flow *flow, enum nx_hash_fields fields, @@ -791,6 +870,24 @@ flow_hash_fields_valid(enum nx_hash_fields fields) || fields == NX_HASH_FIELDS_SYMMETRIC_L4; } +/* Returns a hash value for the bits of 'flow' that are active based on + * 'wc', given 'basis'. */ +uint32_t +flow_hash_in_wildcards(const struct flow *flow, + const struct flow_wildcards *wc, uint32_t basis) +{ + const uint32_t *wc_u32 = (const uint32_t *) &wc->masks; + const uint32_t *flow_u32 = (const uint32_t *) flow; + uint32_t hash; + size_t i; + + hash = basis; + for (i = 0; i < FLOW_U32S; i++) { + hash = mhash_add(hash, flow_u32[i] & wc_u32[i]); + } + return mhash_finish(hash, 4 * FLOW_U32S); +} + /* Sets the VLAN VID that 'flow' matches to 'vid', which is interpreted as an * OpenFlow 1.0 "dl_vlan" value: * @@ -848,6 +945,14 @@ flow_set_mpls_label(struct flow *flow, ovs_be32 label) set_mpls_lse_label(&flow->mpls_lse, label); } +/* Sets the MPLS TTL that 'flow' matches to 'ttl', which should be in the + * range 0...255. */ +void +flow_set_mpls_ttl(struct flow *flow, uint8_t ttl) +{ + set_mpls_lse_ttl(&flow->mpls_lse, ttl); +} + /* Sets the MPLS TC that 'flow' matches to 'tc', which should be in the * range 0...7. */ void @@ -872,9 +977,6 @@ flow_set_mpls_bos(struct flow *flow, uint8_t bos) void flow_compose(struct ofpbuf *b, const struct flow *flow) { - ovs_be16 inner_dl_type; - - inner_dl_type = flow_innermost_dl_type(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; @@ -886,7 +988,7 @@ flow_compose(struct ofpbuf *b, const struct flow *flow) eth_push_vlan(b, flow->vlan_tci); } - if (inner_dl_type == htons(ETH_TYPE_IP)) { + if (flow->dl_type == htons(ETH_TYPE_IP)) { struct ip_header *ip; b->l3 = ip = ofpbuf_put_zeros(b, sizeof *ip); @@ -918,6 +1020,12 @@ flow_compose(struct ofpbuf *b, const struct flow *flow) 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; @@ -932,10 +1040,10 @@ flow_compose(struct ofpbuf *b, const struct flow *flow) ip->ip_tot_len = htons((uint8_t *) b->data + b->size - (uint8_t *) b->l3); ip->ip_csum = csum(ip, sizeof *ip); - } else if (inner_dl_type == htons(ETH_TYPE_IPV6)) { + } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { /* XXX */ - } else if (inner_dl_type == htons(ETH_TYPE_ARP) || - inner_dl_type == htons(ETH_TYPE_RARP)) { + } 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); @@ -1042,20 +1150,8 @@ miniflow_destroy(struct miniflow *flow) void miniflow_expand(const struct miniflow *src, struct flow *dst) { - uint32_t *dst_u32 = (uint32_t *) dst; - int ofs; - int i; - - memset(dst_u32, 0, sizeof *dst); - - ofs = 0; - for (i = 0; i < MINI_N_MAPS; i++) { - uint32_t map; - - for (map = src->map[i]; map; map = zero_rightmost_1bit(map)) { - dst_u32[raw_ctz(map) + i * 32] = src->values[ofs++]; - } - } + memset(dst, 0, sizeof *dst); + flow_union_with_miniflow(dst, src); } static const uint32_t *