>From net-next commit 0a6410fbde597ebcf82dda4a0b0e889e82242678.

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: Lorand Jakab <[email protected]>
Signed-off-by: Simon Horman <[email protected]>
Signed-off-by: Jiri Benc <[email protected]>
Acked-by: Pravin B Shelar <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Yi Yang <[email protected]>
---
 datapath/flow_netlink.c | 178 ++++++++++++++++++++++++++++++------------------
 1 file changed, 113 insertions(+), 65 deletions(-)

diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
index 3975fbc..d5828f3 100644
--- a/datapath/flow_netlink.c
+++ b/datapath/flow_netlink.c
@@ -124,7 +124,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 = 1ULL << 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
@@ -810,10 +810,33 @@ int ovs_nla_put_tunnel_info(struct sk_buff *skb,
                                  ip_tunnel_info_af(tun_info));
 }
 
+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 & (1ULL << OVS_KEY_ATTR_DP_HASH)) {
                u32 hash_val = nla_get_u32(a[OVS_KEY_ATTR_DP_HASH]);
 
@@ -901,9 +924,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;
 }
@@ -927,42 +960,45 @@ 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 &= ~(1ULL << OVS_KEY_ATTR_ETHERNET);
-       }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_VLAN)) {
-               __be16 tci;
+               if (attrs & (1ULL << OVS_KEY_ATTR_VLAN)) {
+                       __be16 tci;
 
-               tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
-               if (!(tci & htons(VLAN_TAG_PRESENT))) {
-                       if (is_mask)
-                               OVS_NLERR(log, "VLAN TCI mask does not have 
exact match for VLAN_TAG_PRESENT bit.");
-                       else
-                               OVS_NLERR(log, "VLAN TCI does not have 
VLAN_TAG_PRESENT bit set.");
+                       tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
+                       if (!(tci & htons(VLAN_TAG_PRESENT))) {
+                               if (is_mask)
+                                       OVS_NLERR(log, "VLAN TCI mask does not 
have exact match for VLAN_TAG_PRESENT bit.");
+                               else
+                                       OVS_NLERR(log, "VLAN TCI does not have 
VLAN_TAG_PRESENT bit set.");
 
-                       return -EINVAL;
+                               return -EINVAL;
+                       }
+
+                       SW_FLOW_KEY_PUT(match, eth.tci, tci, is_mask);
+                       attrs &= ~(1ULL << OVS_KEY_ATTR_VLAN);
                }
 
-               SW_FLOW_KEY_PUT(match, eth.tci, tci, is_mask);
-               attrs &= ~(1ULL << OVS_KEY_ATTR_VLAN);
-       }
+               if (attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE)) {
+                       __be16 eth_type;
 
-       if (attrs & (1ULL << 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;
+                       }
 
-               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 &= ~(1ULL << OVS_KEY_ATTR_ETHERTYPE);
+               } else if (!is_mask) {
+                       SW_FLOW_KEY_PUT(match, eth.type, htons(ETH_P_802_2), 
is_mask);
                }
-
-               SW_FLOW_KEY_PUT(match, eth.type, eth_type, is_mask);
-               attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERTYPE);
-       } 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)) {
@@ -1463,38 +1499,40 @@ static int __ovs_nla_put_key(const struct sw_flow_key 
*swkey,
        if (ovs_ct_put_key(output, skb))
                goto nla_put_failure;
 
-       nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key));
-       if (!nla)
-               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;
 
-       eth_key = nla_data(nla);
-       ether_addr_copy(eth_key->eth_src, output->eth.src);
-       ether_addr_copy(eth_key->eth_dst, output->eth.dst);
+               eth_key = nla_data(nla);
+               ether_addr_copy(eth_key->eth_src, output->eth.src);
+               ether_addr_copy(eth_key->eth_dst, output->eth.dst);
 
-       if (swkey->eth.tci || swkey->eth.type == htons(ETH_P_8021Q)) {
-               __be16 eth_type;
-               eth_type = !is_mask ? htons(ETH_P_8021Q) : htons(0xffff);
-               if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, eth_type) ||
-                   nla_put_be16(skb, OVS_KEY_ATTR_VLAN, output->eth.tci))
-                       goto nla_put_failure;
-               encap = nla_nest_start(skb, OVS_KEY_ATTR_ENCAP);
-               if (!swkey->eth.tci)
-                       goto unencap;
-       } else
-               encap = NULL;
-
-       if (swkey->eth.type == htons(ETH_P_802_2)) {
-               /*
-                * Ethertype 802.2 is represented in the netlink with omitted
-                * OVS_KEY_ATTR_ETHERTYPE in the flow key attribute, and
-                * 0xffff in the mask attribute.  Ethertype can also
-                * be wildcarded.
-                */
-               if (is_mask && output->eth.type)
-                       if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE,
-                                               output->eth.type))
+               if (swkey->eth.tci || swkey->eth.type == htons(ETH_P_8021Q)) {
+                       __be16 eth_type;
+                       eth_type = !is_mask ? htons(ETH_P_8021Q) : 
htons(0xffff);
+                       if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, eth_type) 
||
+                           nla_put_be16(skb, OVS_KEY_ATTR_VLAN, 
output->eth.tci))
                                goto nla_put_failure;
-               goto unencap;
+                       encap = nla_nest_start(skb, OVS_KEY_ATTR_ENCAP);
+                       if (!swkey->eth.tci)
+                               goto unencap;
+               } else
+                       encap = NULL;
+
+               if (swkey->eth.type == htons(ETH_P_802_2)) {
+                       /*
+                        * Ethertype 802.2 is represented in the netlink with 
omitted
+                        * OVS_KEY_ATTR_ETHERTYPE in the flow key attribute, and
+                        * 0xffff in the mask attribute.  Ethertype can also
+                        * be wildcarded.
+                        */
+                       if (is_mask && output->eth.type)
+                               if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE,
+                                                       output->eth.type))
+                                       goto nla_put_failure;
+                       goto unencap;
+               }
        }
 
        if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, output->eth.type))
@@ -2016,8 +2054,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);
@@ -2047,9 +2085,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:
 #ifndef USE_UPSTREAM_TUNNEL
                if (eth_p_mpls(eth_type))
@@ -2218,6 +2259,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;
 
@@ -2288,10 +2330,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 (vlan->vlan_tpid != htons(ETH_P_8021Q))
                                return -EINVAL;
@@ -2341,14 +2387,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;
-- 
2.1.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to