nfp: flower: remove offloaded MACs when reprs are applied to OvS bridges
authorJohn Hurley <john.hurley@netronome.com>
Sun, 4 Aug 2019 15:09:11 +0000 (16:09 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 6 Aug 2019 21:24:22 +0000 (14:24 -0700)
MAC addresses along with an identifying index are offloaded to firmware to
allow tunnel decapsulation. If a tunnel packet arrives with a matching
destination MAC address and a verified index, it can continue on the
decapsulation process. This replicates the MAC verifications carried out
in the kernel network stack.

When a netdev is added to a bridge (e.g. OvS) then packets arriving on
that dev are directed through the bridge datapath instead of passing
through the network stack. Therefore, tunnelled packets matching the MAC
of that dev will not be decapped here.

Replicate this behaviour on firmware by removing offloaded MAC addresses
when a MAC representer is added to an OvS bridge. This can prevent any
false positive tunnel decaps.

Signed-off-by: John Hurley <john.hurley@netronome.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/netronome/nfp/flower/main.h
drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c

index 5d302d79c004044beaf13c50685aacba21faa6e3..31d94592a7c02b1da63855d33b8896fde4bfeb24 100644 (file)
@@ -221,6 +221,7 @@ struct nfp_fl_qos {
  * @block_shared:      Flag indicating if offload applies to shared blocks
  * @mac_list:          List entry of reprs that share the same offloaded MAC
  * @qos_table:         Stored info on filters implementing qos
+ * @on_bridge:         Indicates if the repr is attached to a bridge
  */
 struct nfp_flower_repr_priv {
        struct nfp_repr *nfp_repr;
@@ -230,6 +231,7 @@ struct nfp_flower_repr_priv {
        bool block_shared;
        struct list_head mac_list;
        struct nfp_fl_qos qos_table;
+       bool on_bridge;
 };
 
 /**
@@ -341,6 +343,11 @@ static inline bool nfp_flower_is_merge_flow(struct nfp_fl_payload *flow_pay)
        return flow_pay->tc_flower_cookie == (unsigned long)flow_pay;
 }
 
+static inline bool nfp_flower_is_supported_bridge(struct net_device *netdev)
+{
+       return netif_is_ovs_master(netdev);
+}
+
 int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count,
                             unsigned int host_ctx_split);
 void nfp_flower_metadata_cleanup(struct nfp_app *app);
index b9dbfb7f6c1fca9a8b4e6fe85b52c88bb5c0e4f8..a61e7f26664434c9dfd13ddec91342f462169992 100644 (file)
@@ -730,6 +730,9 @@ nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev,
                        return 0;
 
                repr_priv = repr->app_priv;
+               if (repr_priv->on_bridge)
+                       return 0;
+
                mac_offloaded = &repr_priv->mac_offloaded;
                off_mac = &repr_priv->offloaded_mac_addr[0];
                port = nfp_repr_get_port_id(netdev);
@@ -845,6 +848,45 @@ int nfp_tunnel_mac_event_handler(struct nfp_app *app,
                if (err)
                        nfp_flower_cmsg_warn(app, "Failed to offload MAC change on %s.\n",
                                             netdev_name(netdev));
+       } else if (event == NETDEV_CHANGEUPPER) {
+               /* If a repr is attached to a bridge then tunnel packets
+                * entering the physical port are directed through the bridge
+                * datapath and cannot be directly detunneled. Therefore,
+                * associated offloaded MACs and indexes should not be used
+                * by fw for detunneling.
+                */
+               struct netdev_notifier_changeupper_info *info = ptr;
+               struct net_device *upper = info->upper_dev;
+               struct nfp_flower_repr_priv *repr_priv;
+               struct nfp_repr *repr;
+
+               if (!nfp_netdev_is_nfp_repr(netdev) ||
+                   !nfp_flower_is_supported_bridge(upper))
+                       return NOTIFY_OK;
+
+               repr = netdev_priv(netdev);
+               if (repr->app != app)
+                       return NOTIFY_OK;
+
+               repr_priv = repr->app_priv;
+
+               if (info->linking) {
+                       if (nfp_tunnel_offload_mac(app, netdev,
+                                                  NFP_TUNNEL_MAC_OFFLOAD_DEL))
+                               nfp_flower_cmsg_warn(app, "Failed to delete offloaded MAC on %s.\n",
+                                                    netdev_name(netdev));
+                       repr_priv->on_bridge = true;
+               } else {
+                       repr_priv->on_bridge = false;
+
+                       if (!(netdev->flags & IFF_UP))
+                               return NOTIFY_OK;
+
+                       if (nfp_tunnel_offload_mac(app, netdev,
+                                                  NFP_TUNNEL_MAC_OFFLOAD_ADD))
+                               nfp_flower_cmsg_warn(app, "Failed to offload MAC on %s.\n",
+                                                    netdev_name(netdev));
+               }
        }
        return NOTIFY_OK;
 }