void ovs_flow_stats_update(struct sw_flow *flow, __be16 tcp_flags, conststruct sk_buff *skb)
{ struct sw_flow_stats *stats; unsignedint cpu = smp_processor_id(); int len = skb->len + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
stats = rcu_dereference(flow->stats[cpu]);
/* Check if already have CPU-specific stats. */ if (likely(stats)) {
spin_lock(&stats->lock); /* Mark if we write on the pre-allocated stats. */ if (cpu == 0 && unlikely(flow->stats_last_writer != cpu))
flow->stats_last_writer = cpu;
} else {
stats = rcu_dereference(flow->stats[0]); /* Pre-allocated. */
spin_lock(&stats->lock);
/* If the current CPU is the only writer on the * pre-allocated stats keep using them.
*/ if (unlikely(flow->stats_last_writer != cpu)) { /* A previous locker may have already allocated the * stats, so we need to check again. If CPU-specific * stats were already allocated, we update the pre- * allocated stats as we have already locked them.
*/ if (likely(flow->stats_last_writer != -1) &&
likely(!rcu_access_pointer(flow->stats[cpu]))) { /* Try to allocate CPU-specific stats. */ struct sw_flow_stats *new_stats;
/* Must be called with rcu_read_lock or ovs_mutex. */ void ovs_flow_stats_get(conststruct sw_flow *flow, struct ovs_flow_stats *ovs_stats, unsignedlong *used, __be16 *tcp_flags)
{ int cpu;
/* We open code this to make sure cpu 0 is always considered */ for (cpu = 0; cpu < nr_cpu_ids;
cpu = cpumask_next(cpu, flow->cpu_used_mask)) { struct sw_flow_stats *stats = rcu_dereference_ovsl(flow->stats[cpu]);
if (stats) { /* Local CPU may write on non-local stats, so we must * block bottom-halves here.
*/
spin_lock_bh(&stats->lock); if (!*used || time_after(stats->used, *used))
*used = stats->used;
*tcp_flags |= stats->tcp_flags;
ovs_stats->n_packets += stats->packet_count;
ovs_stats->n_bytes += stats->byte_count;
spin_unlock_bh(&stats->lock);
}
}
}
/* Called with ovs_mutex. */ void ovs_flow_stats_clear(struct sw_flow *flow)
{ int cpu;
/* We open code this to make sure cpu 0 is always considered */ for (cpu = 0; cpu < nr_cpu_ids;
cpu = cpumask_next(cpu, flow->cpu_used_mask)) { struct sw_flow_stats *stats = ovsl_dereference(flow->stats[cpu]);
/** * get_ipv6_ext_hdrs() - Parses packet and sets IPv6 extension header flags. * * @skb: buffer where extension header data starts in packet * @nh: ipv6 header * @ext_hdrs: flags are stored here * * OFPIEH12_UNREP is set if more than one of a given IPv6 extension header * is unexpectedly encountered. (Two destination options headers may be * expected and would not cause this bit to be set.) * * OFPIEH12_UNSEQ is set if IPv6 extension headers were not in the order * preferred (but not required) by RFC 2460: * * When more than one extension header is used in the same packet, it is * recommended that those headers appear in the following order: * IPv6 header * Hop-by-Hop Options header * Destination Options header * Routing header * Fragment header * Authentication header * Encapsulating Security Payload header * Destination Options header * upper-layer header
*/ staticvoid get_ipv6_ext_hdrs(struct sk_buff *skb, struct ipv6hdr *nh,
u16 *ext_hdrs)
{
u8 next_type = nh->nexthdr; unsignedint start = skb_network_offset(skb) + sizeof(struct ipv6hdr); int dest_options_header_count = 0;
*ext_hdrs = 0;
while (ipv6_ext_hdr(next_type)) { struct ipv6_opt_hdr _hdr, *hp;
case IPPROTO_ROUTING: if (*ext_hdrs & OFPIEH12_ROUTER)
*ext_hdrs |= OFPIEH12_UNREP; if ((*ext_hdrs & ~(OFPIEH12_HOP |
OFPIEH12_DEST |
OFPIEH12_UNREP)) ||
dest_options_header_count >= 2) {
*ext_hdrs |= OFPIEH12_UNSEQ;
}
*ext_hdrs |= OFPIEH12_ROUTER; break;
case IPPROTO_HOPOPTS: if (*ext_hdrs & OFPIEH12_HOP)
*ext_hdrs |= OFPIEH12_UNREP; /* OFPIEH12_HOP is set to 1 if a hop-by-hop IPv6 * extension header is present as the first * extension header in the packet.
*/ if (*ext_hdrs == 0)
*ext_hdrs |= OFPIEH12_HOP; else
*ext_hdrs |= OFPIEH12_UNSEQ; break;
default: return;
}
hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); if (!hp) break;
next_type = hp->nexthdr;
start += ipv6_optlen(hp);
}
}
/* Delayed handling of error in ipv6_find_hdr() as it * always sets flags and frag_off to a valid value which may be * used to set key->ip.frag above.
*/ if (unlikely(nexthdr < 0)) return -EPROTO;
/** * parse_vlan_tag - Parse vlan tag from vlan header. * @skb: skb containing frame to parse * @key_vh: pointer to parsed vlan tag * @untag_vlan: should the vlan header be removed from the frame * * Return: ERROR on memory error. * %0 if it encounters a non-vlan or incomplete packet. * %1 after successfully parsing vlan tag.
*/ staticint parse_vlan_tag(struct sk_buff *skb, struct vlan_head *key_vh, bool untag_vlan)
{ struct vlan_head *vh = (struct vlan_head *)skb->data;
if (likely(!eth_type_vlan(vh->tpid))) return 0;
if (unlikely(skb->len < sizeof(struct vlan_head) + sizeof(__be16))) return 0;
if (unlikely(!pskb_may_pull(skb, sizeof(struct vlan_head) + sizeof(__be16)))) return -ENOMEM;
/* The ICMPv6 type and code fields use the 16-bit transport port * fields, so we need to store them in 16-bit network byte order.
*/
key->tp.src = htons(icmp->icmp6_type);
key->tp.dst = htons(icmp->icmp6_code);
if (icmp->icmp6_code == 0 &&
(icmp->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION ||
icmp->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT)) { int icmp_len = skb->len - skb_transport_offset(skb); struct nd_msg *nd; int offset;
memset(&key->ipv6.nd, 0, sizeof(key->ipv6.nd));
/* In order to process neighbor discovery options, we need the * entire packet.
*/ if (unlikely(icmp_len < sizeof(*nd))) return 0;
if (unlikely(!opt_len || opt_len > icmp_len)) return 0;
/* Store the link layer address if the appropriate * option is provided. It is considered an error if * the same link layer option is specified twice.
*/ if (nd_opt->nd_opt_type == ND_OPT_SOURCE_LL_ADDR
&& opt_len == 8) { if (unlikely(!is_zero_ether_addr(key->ipv6.nd.sll))) goto invalid;
ether_addr_copy(key->ipv6.nd.sll,
&nd->opt[offset+sizeof(*nd_opt)]);
} elseif (nd_opt->nd_opt_type == ND_OPT_TARGET_LL_ADDR
&& opt_len == 8) { if (unlikely(!is_zero_ether_addr(key->ipv6.nd.tll))) goto invalid;
ether_addr_copy(key->ipv6.nd.tll,
&nd->opt[offset+sizeof(*nd_opt)]);
}
/** * key_extract - extracts a flow key from an Ethernet frame. * @skb: sk_buff that contains the frame, with skb->data pointing to the * Ethernet header * @key: output flow key * * The caller must ensure that skb->len >= ETH_HLEN. * * Initializes @skb header fields as follows: * * - skb->mac_header: the L2 header. * * - skb->network_header: just past the L2 header, or just past the * VLAN header, to the first byte of the L2 payload. * * - skb->transport_header: If key->eth.type is ETH_P_IP or ETH_P_IPV6 * on output, then just past the IP header, if one is present and * of a correct length, otherwise the same as skb->network_header. * For other key->eth.type values it is left untouched. * * - skb->protocol: the type of the data starting at skb->network_header. * Equals to key->eth.type. * * Return: %0 if successful, otherwise a negative errno value.
*/ staticint key_extract(struct sk_buff *skb, struct sw_flow_key *key)
{ struct ethhdr *eth;
/* Flags are always used as part of stats */
key->tp.flags = 0;
skb_reset_mac_header(skb);
/* Link layer. */
clear_vlan(key); if (ovs_key_mac_proto(key) == MAC_PROTO_NONE) { if (unlikely(eth_type_vlan(skb->protocol))) return -EINVAL;
__skb_pull(skb, 2 * ETH_ALEN); /* We are going to push all headers that we pull, so no need to * update skb->csum here.
*/
if (unlikely(parse_vlan(skb, key))) return -ENOMEM;
key->eth.type = parse_ethertype(skb); if (unlikely(key->eth.type == htons(0))) return -ENOMEM;
/* Multiple tagged packets need to retain TPID to satisfy * skb_vlan_pop(), which will later shift the ethertype into * skb->protocol.
*/ if (key->eth.cvlan.tci & htons(VLAN_CFI_MASK))
skb->protocol = key->eth.cvlan.tpid; else
skb->protocol = key->eth.type;
/* Fill out L3/L4 key info, if any */ return key_extract_l3l4(skb, key);
}
/* In the case of conntrack fragment handling it expects L3 headers, * add a helper.
*/ int ovs_flow_key_update_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
{ return key_extract_l3l4(skb, key);
}
int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key)
{ int res;
res = key_extract(skb, key); if (!res)
key->mac_proto &= ~SW_FLOW_KEY_INVALID;
return res;
}
staticint key_extract_mac_proto(struct sk_buff *skb)
{ switch (skb->dev->type) { case ARPHRD_ETHER: return MAC_PROTO_ETHERNET; case ARPHRD_NONE: if (skb->protocol == htons(ETH_P_TEB)) return MAC_PROTO_ETHERNET; return MAC_PROTO_NONE;
}
WARN_ON_ONCE(1); return -EINVAL;
}
err = key_extract(skb, key); if (!err) {
ovs_ct_fill_key(skb, key, post_ct); /* Must be after key_extract(). */ if (post_ct) { if (!skb_get_nfct(skb)) {
key->ct_zone = zone;
} else { if (!post_ct_dnat)
key->ct_state &= ~OVS_CS_F_DST_NAT; if (!post_ct_snat)
key->ct_state &= ~OVS_CS_F_SRC_NAT;
}
}
} return err;
}
int ovs_flow_key_extract_userspace(struct net *net, conststruct nlattr *attr, struct sk_buff *skb, struct sw_flow_key *key, bool log)
{ conststruct nlattr *a[OVS_KEY_ATTR_MAX + 1];
u64 attrs = 0; int err;
err = parse_flow_nlattrs(attr, a, &attrs, log); if (err) return -EINVAL;
/* Extract metadata from netlink attributes. */
err = ovs_nla_get_flow_metadata(net, a, attrs, key, log); if (err) return err;
/* key_extract assumes that skb->protocol is set-up for * layer 3 packets which is the case for other callers, * in particular packets received from the network stack. * Here the correct value can be set from the metadata * extracted above. * For L2 packet key eth type would be zero. skb protocol * would be set to correct value later during key-extact.
*/
/* Check that we have conntrack original direction tuple metadata only * for packets for which it makes sense. Otherwise the key may be * corrupted due to overlapping key fields.
*/ if (attrs & (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4) &&
key->eth.type != htons(ETH_P_IP)) return -EINVAL; if (attrs & (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6) &&
(key->eth.type != htons(ETH_P_IPV6) ||
sw_flow_key_is_nd(key))) return -EINVAL;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.