1630 lines · 43.5 KB · C
RawDownload
/* * Copyright (c) 2007-2013 Nicira, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA */ #include "flow.h"#include "datapath.h"#include <linux/uaccess.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/if_ether.h>#include <linux/if_vlan.h>#include <net/llc_pdu.h>#include <linux/kernel.h>#include <linux/jhash.h>#include <linux/jiffies.h>#include <linux/llc.h>#include <linux/module.h>#include <linux/in.h>#include <linux/rcupdate.h>#include <linux/if_arp.h>#include <linux/ip.h>#include <linux/ipv6.h>#include <linux/sctp.h>#include <linux/tcp.h>#include <linux/udp.h>#include <linux/icmp.h>#include <linux/icmpv6.h>#include <linux/rculist.h>#include <net/ip.h>#include <net/ipv6.h>#include <net/ndisc.h> #include "flow_netlink.h" static void update_range__(struct sw_flow_match *match,			   size_t offset, size_t size, bool is_mask){	struct sw_flow_key_range *range = NULL;	size_t start = rounddown(offset, sizeof(long));	size_t end = roundup(offset + size, sizeof(long)); 	if (!is_mask)		range = &match->range;	else if (match->mask)		range = &match->mask->range; 	if (!range)		return; 	if (range->start == range->end) {		range->start = start;		range->end = end;		return;	} 	if (range->start > start)		range->start = start; 	if (range->end < end)		range->end = end;} #define SW_FLOW_KEY_PUT(match, field, value, is_mask) \	do { \		update_range__(match, offsetof(struct sw_flow_key, field),  \				     sizeof((match)->key->field), is_mask); \		if (is_mask) {						    \			if ((match)->mask)				    \				(match)->mask->key.field = value;	    \		} else {                                                    \			(match)->key->field = value;		            \		}                                                           \	} while (0) #define SW_FLOW_KEY_MEMCPY(match, field, value_p, len, is_mask) \	do { \		update_range__(match, offsetof(struct sw_flow_key, field),  \				len, is_mask);                              \		if (is_mask) {						    \			if ((match)->mask)				    \				memcpy(&(match)->mask->key.field, value_p, len);\		} else {                                                    \			memcpy(&(match)->key->field, value_p, len);         \		}                                                           \	} while (0) static u16 range_n_bytes(const struct sw_flow_key_range *range){	return range->end - range->start;} static bool match_validate(const struct sw_flow_match *match,			   u64 key_attrs, u64 mask_attrs){	u64 key_expected = 1 << OVS_KEY_ATTR_ETHERNET;	u64 mask_allowed = key_attrs;  /* At most allow all key attributes */ 	/* The following mask attributes allowed only if they	 * pass the validation tests. */	mask_allowed &= ~((1 << OVS_KEY_ATTR_IPV4)			| (1 << OVS_KEY_ATTR_IPV6)			| (1 << OVS_KEY_ATTR_TCP)			| (1 << OVS_KEY_ATTR_TCP_FLAGS)			| (1 << OVS_KEY_ATTR_UDP)			| (1 << OVS_KEY_ATTR_SCTP)			| (1 << OVS_KEY_ATTR_ICMP)			| (1 << OVS_KEY_ATTR_ICMPV6)			| (1 << OVS_KEY_ATTR_ARP)			| (1 << OVS_KEY_ATTR_ND)); 	/* Always allowed mask fields. */	mask_allowed |= ((1 << OVS_KEY_ATTR_TUNNEL)		       | (1 << OVS_KEY_ATTR_IN_PORT)		       | (1 << OVS_KEY_ATTR_ETHERTYPE)); 	/* Check key attributes. */	if (match->key->eth.type == htons(ETH_P_ARP)			|| match->key->eth.type == htons(ETH_P_RARP)) {		key_expected |= 1 << OVS_KEY_ATTR_ARP;		if (match->mask && (match->mask->key.eth.type == htons(0xffff)))			mask_allowed |= 1 << OVS_KEY_ATTR_ARP;	} 	if (match->key->eth.type == htons(ETH_P_IP)) {		key_expected |= 1 << OVS_KEY_ATTR_IPV4;		if (match->mask && (match->mask->key.eth.type == htons(0xffff)))			mask_allowed |= 1 << OVS_KEY_ATTR_IPV4; 		if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) {			if (match->key->ip.proto == IPPROTO_UDP) {				key_expected |= 1 << OVS_KEY_ATTR_UDP;				if (match->mask && (match->mask->key.ip.proto == 0xff))					mask_allowed |= 1 << OVS_KEY_ATTR_UDP;			} 			if (match->key->ip.proto == IPPROTO_SCTP) {				key_expected |= 1 << OVS_KEY_ATTR_SCTP;				if (match->mask && (match->mask->key.ip.proto == 0xff))					mask_allowed |= 1 << OVS_KEY_ATTR_SCTP;			} 			if (match->key->ip.proto == IPPROTO_TCP) {				key_expected |= 1 << OVS_KEY_ATTR_TCP;				key_expected |= 1 << OVS_KEY_ATTR_TCP_FLAGS;				if (match->mask && (match->mask->key.ip.proto == 0xff)) {					mask_allowed |= 1 << OVS_KEY_ATTR_TCP;					mask_allowed |= 1 << OVS_KEY_ATTR_TCP_FLAGS;				}			} 			if (match->key->ip.proto == IPPROTO_ICMP) {				key_expected |= 1 << OVS_KEY_ATTR_ICMP;				if (match->mask && (match->mask->key.ip.proto == 0xff))					mask_allowed |= 1 << OVS_KEY_ATTR_ICMP;			}		}	} 	if (match->key->eth.type == htons(ETH_P_IPV6)) {		key_expected |= 1 << OVS_KEY_ATTR_IPV6;		if (match->mask && (match->mask->key.eth.type == htons(0xffff)))			mask_allowed |= 1 << OVS_KEY_ATTR_IPV6; 		if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) {			if (match->key->ip.proto == IPPROTO_UDP) {				key_expected |= 1 << OVS_KEY_ATTR_UDP;				if (match->mask && (match->mask->key.ip.proto == 0xff))					mask_allowed |= 1 << OVS_KEY_ATTR_UDP;			} 			if (match->key->ip.proto == IPPROTO_SCTP) {				key_expected |= 1 << OVS_KEY_ATTR_SCTP;				if (match->mask && (match->mask->key.ip.proto == 0xff))					mask_allowed |= 1 << OVS_KEY_ATTR_SCTP;			} 			if (match->key->ip.proto == IPPROTO_TCP) {				key_expected |= 1 << OVS_KEY_ATTR_TCP;				key_expected |= 1 << OVS_KEY_ATTR_TCP_FLAGS;				if (match->mask && (match->mask->key.ip.proto == 0xff)) {					mask_allowed |= 1 << OVS_KEY_ATTR_TCP;					mask_allowed |= 1 << OVS_KEY_ATTR_TCP_FLAGS;				}			} 			if (match->key->ip.proto == IPPROTO_ICMPV6) {				key_expected |= 1 << OVS_KEY_ATTR_ICMPV6;				if (match->mask && (match->mask->key.ip.proto == 0xff))					mask_allowed |= 1 << OVS_KEY_ATTR_ICMPV6; 				if (match->key->ipv6.tp.src ==						htons(NDISC_NEIGHBOUR_SOLICITATION) ||				    match->key->ipv6.tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) {					key_expected |= 1 << OVS_KEY_ATTR_ND;					if (match->mask && (match->mask->key.ipv6.tp.src == htons(0xffff)))						mask_allowed |= 1 << OVS_KEY_ATTR_ND;				}			}		}	} 	if ((key_attrs & key_expected) != key_expected) {		/* Key attributes check failed. */		OVS_NLERR("Missing expected key attributes (key_attrs=%llx, expected=%llx).\n",				key_attrs, key_expected);		return false;	} 	if ((mask_attrs & mask_allowed) != mask_attrs) {		/* Mask attributes check failed. */		OVS_NLERR("Contain more than allowed mask fields (mask_attrs=%llx, mask_allowed=%llx).\n",				mask_attrs, mask_allowed);		return false;	} 	return true;} /* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute.  */static const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {	[OVS_KEY_ATTR_ENCAP] = -1,	[OVS_KEY_ATTR_PRIORITY] = sizeof(u32),	[OVS_KEY_ATTR_IN_PORT] = sizeof(u32),	[OVS_KEY_ATTR_SKB_MARK] = sizeof(u32),	[OVS_KEY_ATTR_ETHERNET] = sizeof(struct ovs_key_ethernet),	[OVS_KEY_ATTR_VLAN] = sizeof(__be16),	[OVS_KEY_ATTR_ETHERTYPE] = sizeof(__be16),	[OVS_KEY_ATTR_IPV4] = sizeof(struct ovs_key_ipv4),	[OVS_KEY_ATTR_IPV6] = sizeof(struct ovs_key_ipv6),	[OVS_KEY_ATTR_TCP] = sizeof(struct ovs_key_tcp),	[OVS_KEY_ATTR_TCP_FLAGS] = sizeof(__be16),	[OVS_KEY_ATTR_UDP] = sizeof(struct ovs_key_udp),	[OVS_KEY_ATTR_SCTP] = sizeof(struct ovs_key_sctp),	[OVS_KEY_ATTR_ICMP] = sizeof(struct ovs_key_icmp),	[OVS_KEY_ATTR_ICMPV6] = sizeof(struct ovs_key_icmpv6),	[OVS_KEY_ATTR_ARP] = sizeof(struct ovs_key_arp),	[OVS_KEY_ATTR_ND] = sizeof(struct ovs_key_nd),	[OVS_KEY_ATTR_TUNNEL] = -1,}; static bool is_all_zero(const u8 *fp, size_t size){	int i; 	if (!fp)		return false; 	for (i = 0; i < size; i++)		if (fp[i])			return false; 	return true;} static int __parse_flow_nlattrs(const struct nlattr *attr,				const struct nlattr *a[],				u64 *attrsp, bool nz){	const struct nlattr *nla;	u64 attrs;	int rem; 	attrs = *attrsp;	nla_for_each_nested(nla, attr, rem) {		u16 type = nla_type(nla);		int expected_len; 		if (type > OVS_KEY_ATTR_MAX) {			OVS_NLERR("Unknown key attribute (type=%d, max=%d).\n",				  type, OVS_KEY_ATTR_MAX);			return -EINVAL;		} 		if (attrs & (1 << type)) {			OVS_NLERR("Duplicate key attribute (type %d).\n", type);			return -EINVAL;		} 		expected_len = ovs_key_lens[type];		if (nla_len(nla) != expected_len && expected_len != -1) {			OVS_NLERR("Key attribute has unexpected length (type=%d"				  ", length=%d, expected=%d).\n", type,				  nla_len(nla), expected_len);			return -EINVAL;		} 		if (!nz || !is_all_zero(nla_data(nla), expected_len)) {			attrs |= 1 << type;			a[type] = nla;		}	}	if (rem) {		OVS_NLERR("Message has %d unknown bytes.\n", rem);		return -EINVAL;	} 	*attrsp = attrs;	return 0;} static int parse_flow_mask_nlattrs(const struct nlattr *attr,				   const struct nlattr *a[], u64 *attrsp){	return __parse_flow_nlattrs(attr, a, attrsp, true);} static int parse_flow_nlattrs(const struct nlattr *attr,			      const struct nlattr *a[], u64 *attrsp){	return __parse_flow_nlattrs(attr, a, attrsp, false);} static int ipv4_tun_from_nlattr(const struct nlattr *attr,				struct sw_flow_match *match, bool is_mask){	struct nlattr *a;	int rem;	bool ttl = false;	__be16 tun_flags = 0; 	nla_for_each_nested(a, attr, rem) {		int type = nla_type(a);		static const u32 ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {			[OVS_TUNNEL_KEY_ATTR_ID] = sizeof(u64),			[OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = sizeof(u32),			[OVS_TUNNEL_KEY_ATTR_IPV4_DST] = sizeof(u32),			[OVS_TUNNEL_KEY_ATTR_TOS] = 1,			[OVS_TUNNEL_KEY_ATTR_TTL] = 1,			[OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = 0,			[OVS_TUNNEL_KEY_ATTR_CSUM] = 0,		}; 		if (type > OVS_TUNNEL_KEY_ATTR_MAX) {			OVS_NLERR("Unknown IPv4 tunnel attribute (type=%d, max=%d).\n",			type, OVS_TUNNEL_KEY_ATTR_MAX);			return -EINVAL;		} 		if (ovs_tunnel_key_lens[type] != nla_len(a)) {			OVS_NLERR("IPv4 tunnel attribute type has unexpected "				  " length (type=%d, length=%d, expected=%d).\n",				  type, nla_len(a), ovs_tunnel_key_lens[type]);			return -EINVAL;		} 		switch (type) {		case OVS_TUNNEL_KEY_ATTR_ID:			SW_FLOW_KEY_PUT(match, tun_key.tun_id,					nla_get_be64(a), is_mask);			tun_flags |= TUNNEL_KEY;			break;		case OVS_TUNNEL_KEY_ATTR_IPV4_SRC:			SW_FLOW_KEY_PUT(match, tun_key.ipv4_src,					nla_get_be32(a), is_mask);			break;		case OVS_TUNNEL_KEY_ATTR_IPV4_DST:			SW_FLOW_KEY_PUT(match, tun_key.ipv4_dst,					nla_get_be32(a), is_mask);			break;		case OVS_TUNNEL_KEY_ATTR_TOS:			SW_FLOW_KEY_PUT(match, tun_key.ipv4_tos,					nla_get_u8(a), is_mask);			break;		case OVS_TUNNEL_KEY_ATTR_TTL:			SW_FLOW_KEY_PUT(match, tun_key.ipv4_ttl,					nla_get_u8(a), is_mask);			ttl = true;			break;		case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT:			tun_flags |= TUNNEL_DONT_FRAGMENT;			break;		case OVS_TUNNEL_KEY_ATTR_CSUM:			tun_flags |= TUNNEL_CSUM;			break;		default:			return -EINVAL;		}	} 	SW_FLOW_KEY_PUT(match, tun_key.tun_flags, tun_flags, is_mask); 	if (rem > 0) {		OVS_NLERR("IPv4 tunnel attribute has %d unknown bytes.\n", rem);		return -EINVAL;	} 	if (!is_mask) {		if (!match->key->tun_key.ipv4_dst) {			OVS_NLERR("IPv4 tunnel destination address is zero.\n");			return -EINVAL;		} 		if (!ttl) {			OVS_NLERR("IPv4 tunnel TTL not specified.\n");			return -EINVAL;		}	} 	return 0;} static int ipv4_tun_to_nlattr(struct sk_buff *skb,			      const struct ovs_key_ipv4_tunnel *tun_key,			      const struct ovs_key_ipv4_tunnel *output){	struct nlattr *nla; 	nla = nla_nest_start(skb, OVS_KEY_ATTR_TUNNEL);	if (!nla)		return -EMSGSIZE; 	if (output->tun_flags & TUNNEL_KEY &&	    nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id))		return -EMSGSIZE;	if (output->ipv4_src &&		nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, output->ipv4_src))		return -EMSGSIZE;	if (output->ipv4_dst &&		nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST, output->ipv4_dst))		return -EMSGSIZE;	if (output->ipv4_tos &&		nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->ipv4_tos))		return -EMSGSIZE;	if (nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TTL, output->ipv4_ttl))		return -EMSGSIZE;	if ((output->tun_flags & TUNNEL_DONT_FRAGMENT) &&		nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT))		return -EMSGSIZE;	if ((output->tun_flags & TUNNEL_CSUM) &&		nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM))		return -EMSGSIZE; 	nla_nest_end(skb, nla);	return 0;}  static int metadata_from_nlattrs(struct sw_flow_match *match,  u64 *attrs,				 const struct nlattr **a, bool is_mask){	if (*attrs & (1 << OVS_KEY_ATTR_PRIORITY)) {		SW_FLOW_KEY_PUT(match, phy.priority,			  nla_get_u32(a[OVS_KEY_ATTR_PRIORITY]), is_mask);		*attrs &= ~(1 << OVS_KEY_ATTR_PRIORITY);	} 	if (*attrs & (1 << OVS_KEY_ATTR_IN_PORT)) {		u32 in_port = nla_get_u32(a[OVS_KEY_ATTR_IN_PORT]); 		if (is_mask)			in_port = 0xffffffff; /* Always exact match in_port. */		else if (in_port >= DP_MAX_PORTS)			return -EINVAL; 		SW_FLOW_KEY_PUT(match, phy.in_port, in_port, is_mask);		*attrs &= ~(1 << OVS_KEY_ATTR_IN_PORT);	} else if (!is_mask) {		SW_FLOW_KEY_PUT(match, phy.in_port, DP_MAX_PORTS, is_mask);	} 	if (*attrs & (1 << OVS_KEY_ATTR_SKB_MARK)) {		uint32_t mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_MARK]); 		SW_FLOW_KEY_PUT(match, phy.skb_mark, mark, is_mask);		*attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK);	}	if (*attrs & (1 << OVS_KEY_ATTR_TUNNEL)) {		if (ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match,					 is_mask))			return -EINVAL;		*attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL);	}	return 0;} static int ovs_key_from_nlattrs(struct sw_flow_match *match,  u64 attrs,				const struct nlattr **a, bool is_mask){	int err;	u64 orig_attrs = attrs; 	err = metadata_from_nlattrs(match, &attrs, a, is_mask);	if (err)		return err; 	if (attrs & (1 << OVS_KEY_ATTR_ETHERNET)) {

Lines 1–500 of 1630.