openvswitch: add mac_proto field to the flow key
authorJiri Benc <jbenc@redhat.com>
Thu, 10 Nov 2016 15:28:18 +0000 (16:28 +0100)
committerDavid S. Miller <davem@davemloft.net>
Sun, 13 Nov 2016 05:51:02 +0000 (00:51 -0500)
Use a hole in the structure. We support only Ethernet so far and will add
a support for L2-less packets shortly. We could use a bool to indicate
whether the Ethernet header is present or not but the approach with the
mac_proto field is more generic and occupies the same number of bytes in the
struct, while allowing later extensibility. It also makes the code in the
next patches more self explaining.

It would be nice to use ARPHRD_ constants but those are u16 which would be
waste. Thus define our own constants.

Another upside of this is that we can overload this new field to also denote
whether the flow key is valid. This has the advantage that on
refragmentation, we don't have to reparse the packet but can rely on the
stored eth.type. This is especially important for the next patches in this
series - instead of adding another branch for L2-less packets before calling
ovs_fragment, we can just remove all those branches completely.

Signed-off-by: Jiri Benc <jbenc@redhat.com>
Acked-by: Pravin B Shelar <pshelar@ovn.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/openvswitch/actions.c
net/openvswitch/flow.c
net/openvswitch/flow.h
net/openvswitch/flow_netlink.c

index 49af167105d332396664353122b7407227d867dd..44144f914920a4f8ba0229db64fdf78187540195 100644 (file)
@@ -137,12 +137,12 @@ static struct deferred_action *add_deferred_actions(struct sk_buff *skb,
 
 static void invalidate_flow_key(struct sw_flow_key *key)
 {
-       key->eth.type = htons(0);
+       key->mac_proto |= SW_FLOW_KEY_INVALID;
 }
 
 static bool is_flow_key_valid(const struct sw_flow_key *key)
 {
-       return !!key->eth.type;
+       return !(key->mac_proto & SW_FLOW_KEY_INVALID);
 }
 
 static void update_ethertype(struct sk_buff *skb, struct ethhdr *hdr,
@@ -796,16 +796,8 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
                        ovs_vport_send(vport, skb);
                } else if (mru <= vport->dev->mtu) {
                        struct net *net = read_pnet(&dp->net);
-                       __be16 ethertype = key->eth.type;
 
-                       if (!is_flow_key_valid(key)) {
-                               if (eth_p_mpls(skb->protocol))
-                                       ethertype = skb->inner_protocol;
-                               else
-                                       ethertype = vlan_get_protocol(skb);
-                       }
-
-                       ovs_fragment(net, vport, skb, mru, ethertype);
+                       ovs_fragment(net, vport, skb, mru, key->eth.type);
                } else {
                        kfree_skb(skb);
                }
index 22087062bd1013e7c526dc95bce379bcaaebc4b9..96c8c4716603c77ec3fb1fd81f71a4fda6f586b7 100644 (file)
@@ -751,6 +751,7 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
        key->phy.skb_mark = skb->mark;
        ovs_ct_fill_key(skb, key);
        key->ovs_flow_hash = 0;
+       key->mac_proto = MAC_PROTO_ETHERNET;
        key->recirc_id = 0;
 
        return key_extract(skb, key);
index ae783f5c6695867a0941037700b36c2d8ef16a58..f61cae7f9030df68c3001e5e63dc2c903b3d1d3f 100644 (file)
 
 struct sk_buff;
 
+enum sw_flow_mac_proto {
+       MAC_PROTO_NONE = 0,
+       MAC_PROTO_ETHERNET,
+};
+#define SW_FLOW_KEY_INVALID    0x80
+
 /* Store options at the end of the array if they are less than the
  * maximum size. This allows us to get the benefits of variable length
  * matching for small options.
@@ -68,6 +74,7 @@ struct sw_flow_key {
                u32     skb_mark;       /* SKB mark. */
                u16     in_port;        /* Input switch port (or DP_MAX_PORTS). */
        } __packed phy; /* Safe when right after 'tun_key'. */
+       u8 mac_proto;                   /* MAC layer protocol (e.g. Ethernet). */
        u8 tun_proto;                   /* Protocol of encapsulating tunnel. */
        u32 ovs_flow_hash;              /* Datapath computed hash value.  */
        u32 recirc_id;                  /* Recirculation ID.  */
@@ -206,6 +213,21 @@ struct arp_eth_header {
        unsigned char       ar_tip[4];          /* target IP address        */
 } __packed;
 
+static inline u8 ovs_key_mac_proto(const struct sw_flow_key *key)
+{
+       return key->mac_proto & ~SW_FLOW_KEY_INVALID;
+}
+
+static inline u16 __ovs_mac_header_len(u8 mac_proto)
+{
+       return mac_proto == MAC_PROTO_ETHERNET ? ETH_HLEN : 0;
+}
+
+static inline u16 ovs_mac_header_len(const struct sw_flow_key *key)
+{
+       return __ovs_mac_header_len(ovs_key_mac_proto(key));
+}
+
 static inline bool ovs_identifier_is_ufid(const struct sw_flow_id *sfid)
 {
        return sfid->ufid_len;
index ae25ded82b3baa779438d3460aa1aa8d5ef964f9..ccb9900c5230fa61004545f5adc159c2ff1b1a70 100644 (file)
@@ -1059,6 +1059,11 @@ static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
                                   sizeof(*cl), is_mask);
                *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_LABELS);
        }
+
+       /* Always exact match mac_proto */
+       SW_FLOW_KEY_PUT(match, mac_proto, is_mask ? 0xff : MAC_PROTO_ETHERNET,
+                       is_mask);
+
        return 0;
 }