Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0a6410fb authored by Jiri Benc's avatar Jiri Benc Committed by David S. Miller
Browse files

openvswitch: netlink: support L3 packets



Extend the ovs flow netlink protocol to support L3 packets. Packets without
OVS_KEY_ATTR_ETHERNET attribute specify L3 packets; for those, the
OVS_KEY_ATTR_ETHERTYPE attribute is mandatory.

Push/pop vlan actions are only supported for Ethernet packets.

Based on previous versions by Lorand Jakab and Simon Horman.

Signed-off-by: default avatarLorand Jakab <lojakab@cisco.com>
Signed-off-by: default avatarSimon Horman <simon.horman@netronome.com>
Signed-off-by: default avatarJiri Benc <jbenc@redhat.com>
Acked-by: default avatarPravin B Shelar <pshelar@ovn.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5108bbad
Loading
Loading
Loading
Loading
+99 −61
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ static void update_range(struct sw_flow_match *match,
static bool match_validate(const struct sw_flow_match *match,
			   u64 key_attrs, u64 mask_attrs, bool log)
{
	u64 key_expected = 1 << OVS_KEY_ATTR_ETHERNET;
	u64 key_expected = 0;
	u64 mask_allowed = key_attrs;  /* At most allow all key attributes */

	/* The following mask attributes allowed only if they
@@ -969,10 +969,33 @@ static int parse_vlan_from_nlattrs(struct sw_flow_match *match,
	return 0;
}

static int parse_eth_type_from_nlattrs(struct sw_flow_match *match,
				       u64 *attrs, const struct nlattr **a,
				       bool is_mask, bool log)
{
	__be16 eth_type;

	eth_type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
	if (is_mask) {
		/* Always exact match EtherType. */
		eth_type = htons(0xffff);
	} else if (!eth_proto_is_802_3(eth_type)) {
		OVS_NLERR(log, "EtherType %x is less than min %x",
				ntohs(eth_type), ETH_P_802_3_MIN);
		return -EINVAL;
	}

	SW_FLOW_KEY_PUT(match, eth.type, eth_type, is_mask);
	*attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE);
	return 0;
}

static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
				 u64 *attrs, const struct nlattr **a,
				 bool is_mask, bool log)
{
	u8 mac_proto = MAC_PROTO_ETHERNET;

	if (*attrs & (1 << OVS_KEY_ATTR_DP_HASH)) {
		u32 hash_val = nla_get_u32(a[OVS_KEY_ATTR_DP_HASH]);

@@ -1060,9 +1083,19 @@ static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
		*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_LABELS);
	}

	/* For layer 3 packets the Ethernet type is provided
	 * and treated as metadata but no MAC addresses are provided.
	 */
	if (!(*attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) &&
	    (*attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE)))
		mac_proto = MAC_PROTO_NONE;

	/* Always exact match mac_proto */
	SW_FLOW_KEY_PUT(match, mac_proto, is_mask ? 0xff : MAC_PROTO_ETHERNET,
			is_mask);
	SW_FLOW_KEY_PUT(match, mac_proto, is_mask ? 0xff : mac_proto, is_mask);

	if (mac_proto == MAC_PROTO_NONE)
		return parse_eth_type_from_nlattrs(match, attrs, a, is_mask,
						   log);

	return 0;
}
@@ -1086,7 +1119,6 @@ static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match,
		SW_FLOW_KEY_MEMCPY(match, eth.dst,
				eth_key->eth_dst, ETH_ALEN, is_mask);
		attrs &= ~(1 << OVS_KEY_ATTR_ETHERNET);
	}

		if (attrs & (1 << OVS_KEY_ATTR_VLAN)) {
			/* VLAN attribute is always parsed before getting here since it
@@ -1097,23 +1129,17 @@ static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match,
		}

		if (attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) {
		__be16 eth_type;

		eth_type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
		if (is_mask) {
			/* Always exact match EtherType. */
			eth_type = htons(0xffff);
		} else if (!eth_proto_is_802_3(eth_type)) {
			OVS_NLERR(log, "EtherType %x is less than min %x",
				  ntohs(eth_type), ETH_P_802_3_MIN);
			return -EINVAL;
		}

		SW_FLOW_KEY_PUT(match, eth.type, eth_type, is_mask);
		attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE);
			err = parse_eth_type_from_nlattrs(match, &attrs, a, is_mask,
							  log);
			if (err)
				return err;
		} else if (!is_mask) {
			SW_FLOW_KEY_PUT(match, eth.type, htons(ETH_P_802_2), is_mask);
		}
	} else if (!match->key->eth.type) {
		OVS_NLERR(log, "Either Ethernet header or EtherType is required.");
		return -EINVAL;
	}

	if (attrs & (1 << OVS_KEY_ATTR_IPV4)) {
		const struct ovs_key_ipv4 *ipv4_key;
@@ -1561,6 +1587,7 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
	if (ovs_ct_put_key(output, skb))
		goto nla_put_failure;

	if (ovs_key_mac_proto(swkey) == MAC_PROTO_ETHERNET) {
		nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key));
		if (!nla)
			goto nla_put_failure;
@@ -1598,6 +1625,7 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
					goto nla_put_failure;
			goto unencap;
		}
	}

	if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, output->eth.type))
		goto nla_put_failure;
@@ -2131,8 +2159,8 @@ static bool validate_masked(u8 *data, int len)

static int validate_set(const struct nlattr *a,
			const struct sw_flow_key *flow_key,
			struct sw_flow_actions **sfa,
			bool *skip_copy, __be16 eth_type, bool masked, bool log)
			struct sw_flow_actions **sfa, bool *skip_copy,
			u8 mac_proto, __be16 eth_type, bool masked, bool log)
{
	const struct nlattr *ovs_key = nla_data(a);
	int key_type = nla_type(ovs_key);
@@ -2162,9 +2190,12 @@ static int validate_set(const struct nlattr *a,
	case OVS_KEY_ATTR_SKB_MARK:
	case OVS_KEY_ATTR_CT_MARK:
	case OVS_KEY_ATTR_CT_LABELS:
	case OVS_KEY_ATTR_ETHERNET:
		break;

	case OVS_KEY_ATTR_ETHERNET:
		if (mac_proto != MAC_PROTO_ETHERNET)
			return -EINVAL;

	case OVS_KEY_ATTR_TUNNEL:
		if (masked)
			return -EINVAL; /* Masked tunnel set not supported. */
@@ -2329,6 +2360,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
				  int depth, struct sw_flow_actions **sfa,
				  __be16 eth_type, __be16 vlan_tci, bool log)
{
	u8 mac_proto = ovs_key_mac_proto(key);
	const struct nlattr *a;
	int rem, err;

@@ -2399,10 +2431,14 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
		}

		case OVS_ACTION_ATTR_POP_VLAN:
			if (mac_proto != MAC_PROTO_ETHERNET)
				return -EINVAL;
			vlan_tci = htons(0);
			break;

		case OVS_ACTION_ATTR_PUSH_VLAN:
			if (mac_proto != MAC_PROTO_ETHERNET)
				return -EINVAL;
			vlan = nla_data(a);
			if (!eth_type_vlan(vlan->vlan_tpid))
				return -EINVAL;
@@ -2452,14 +2488,16 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,

		case OVS_ACTION_ATTR_SET:
			err = validate_set(a, key, sfa,
					   &skip_copy, eth_type, false, log);
					   &skip_copy, mac_proto, eth_type,
					   false, log);
			if (err)
				return err;
			break;

		case OVS_ACTION_ATTR_SET_MASKED:
			err = validate_set(a, key, sfa,
					   &skip_copy, eth_type, true, log);
					   &skip_copy, mac_proto, eth_type,
					   true, log);
			if (err)
				return err;
			break;