nfp: flower: modify pre-tunnel and set tunnel action for ipv6
authorJohn Hurley <john.hurley@netronome.com>
Tue, 17 Dec 2019 21:57:20 +0000 (21:57 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 20 Dec 2019 01:37:13 +0000 (17:37 -0800)
The IPv4 set tunnel action allows the setting of tunnel metadata such as
the TTL and ToS values. The pre-tunnel action includes the destination IP
address and is used to calculate the next hop from from the neighbour
table.

Much of the IPv4 tunnel actions can be reused for IPv6 tunnels. Change the
names of associated functions and structs to remove the IPv4 identifier
and make minor modifcations to support IPv6 tunnel actions.

Ensure the pre-tunnel action contains the IPv6 address along with an
identifying flag when an IPv6 tunnel action is required.

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

index 1b019fd..c06600f 100644 (file)
@@ -22,8 +22,9 @@
 #define NFP_FL_TUNNEL_CSUM                     cpu_to_be16(0x01)
 #define NFP_FL_TUNNEL_KEY                      cpu_to_be16(0x04)
 #define NFP_FL_TUNNEL_GENEVE_OPT               cpu_to_be16(0x0800)
-#define NFP_FL_SUPPORTED_TUNNEL_INFO_FLAGS     IP_TUNNEL_INFO_TX
-#define NFP_FL_SUPPORTED_IPV4_UDP_TUN_FLAGS    (NFP_FL_TUNNEL_CSUM | \
+#define NFP_FL_SUPPORTED_TUNNEL_INFO_FLAGS     (IP_TUNNEL_INFO_TX | \
+                                                IP_TUNNEL_INFO_IPV6)
+#define NFP_FL_SUPPORTED_UDP_TUN_FLAGS         (NFP_FL_TUNNEL_CSUM | \
                                                 NFP_FL_TUNNEL_KEY | \
                                                 NFP_FL_TUNNEL_GENEVE_OPT)
 
@@ -394,19 +395,26 @@ nfp_fl_push_geneve_options(struct nfp_fl_payload *nfp_fl, int *list_len,
 }
 
 static int
-nfp_fl_set_ipv4_tun(struct nfp_app *app, struct nfp_fl_set_ipv4_tun *set_tun,
-                   const struct flow_action_entry *act,
-                   struct nfp_fl_pre_tunnel *pre_tun,
-                   enum nfp_flower_tun_type tun_type,
-                   struct net_device *netdev, struct netlink_ext_ack *extack)
+nfp_fl_set_tun(struct nfp_app *app, struct nfp_fl_set_tun *set_tun,
+              const struct flow_action_entry *act,
+              struct nfp_fl_pre_tunnel *pre_tun,
+              enum nfp_flower_tun_type tun_type,
+              struct net_device *netdev, struct netlink_ext_ack *extack)
 {
-       size_t act_size = sizeof(struct nfp_fl_set_ipv4_tun);
        const struct ip_tunnel_info *ip_tun = act->tunnel;
+       bool ipv6 = ip_tunnel_info_af(ip_tun) == AF_INET6;
+       size_t act_size = sizeof(struct nfp_fl_set_tun);
        struct nfp_flower_priv *priv = app->priv;
        u32 tmp_set_ip_tun_type_index = 0;
        /* Currently support one pre-tunnel so index is always 0. */
        int pretun_idx = 0;
 
+       if (!IS_ENABLED(CONFIG_IPV6) && ipv6)
+               return -EOPNOTSUPP;
+
+       if (ipv6 && !(priv->flower_ext_feats & NFP_FL_FEATS_IPV6_TUN))
+               return -EOPNOTSUPP;
+
        BUILD_BUG_ON(NFP_FL_TUNNEL_CSUM != TUNNEL_CSUM ||
                     NFP_FL_TUNNEL_KEY  != TUNNEL_KEY ||
                     NFP_FL_TUNNEL_GENEVE_OPT != TUNNEL_GENEVE_OPT);
@@ -417,19 +425,35 @@ nfp_fl_set_ipv4_tun(struct nfp_app *app, struct nfp_fl_set_ipv4_tun *set_tun,
                return -EOPNOTSUPP;
        }
 
-       set_tun->head.jump_id = NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL;
+       set_tun->head.jump_id = NFP_FL_ACTION_OPCODE_SET_TUNNEL;
        set_tun->head.len_lw = act_size >> NFP_FL_LW_SIZ;
 
        /* Set tunnel type and pre-tunnel index. */
        tmp_set_ip_tun_type_index |=
-               FIELD_PREP(NFP_FL_IPV4_TUNNEL_TYPE, tun_type) |
-               FIELD_PREP(NFP_FL_IPV4_PRE_TUN_INDEX, pretun_idx);
+               FIELD_PREP(NFP_FL_TUNNEL_TYPE, tun_type) |
+               FIELD_PREP(NFP_FL_PRE_TUN_INDEX, pretun_idx);
 
        set_tun->tun_type_index = cpu_to_be32(tmp_set_ip_tun_type_index);
        set_tun->tun_id = ip_tun->key.tun_id;
 
        if (ip_tun->key.ttl) {
                set_tun->ttl = ip_tun->key.ttl;
+#ifdef CONFIG_IPV6
+       } else if (ipv6) {
+               struct net *net = dev_net(netdev);
+               struct flowi6 flow = {};
+               struct dst_entry *dst;
+
+               flow.daddr = ip_tun->key.u.ipv6.dst;
+               flow.flowi4_proto = IPPROTO_UDP;
+               dst = ipv6_stub->ipv6_dst_lookup_flow(net, NULL, &flow, NULL);
+               if (!IS_ERR(dst)) {
+                       set_tun->ttl = ip6_dst_hoplimit(dst);
+                       dst_release(dst);
+               } else {
+                       set_tun->ttl = net->ipv6.devconf_all->hop_limit;
+               }
+#endif
        } else {
                struct net *net = dev_net(netdev);
                struct flowi4 flow = {};
@@ -455,7 +479,7 @@ nfp_fl_set_ipv4_tun(struct nfp_app *app, struct nfp_fl_set_ipv4_tun *set_tun,
        set_tun->tos = ip_tun->key.tos;
 
        if (!(ip_tun->key.tun_flags & NFP_FL_TUNNEL_KEY) ||
-           ip_tun->key.tun_flags & ~NFP_FL_SUPPORTED_IPV4_UDP_TUN_FLAGS) {
+           ip_tun->key.tun_flags & ~NFP_FL_SUPPORTED_UDP_TUN_FLAGS) {
                NL_SET_ERR_MSG_MOD(extack, "unsupported offload: loaded firmware does not support tunnel flag offload");
                return -EOPNOTSUPP;
        }
@@ -467,7 +491,12 @@ nfp_fl_set_ipv4_tun(struct nfp_app *app, struct nfp_fl_set_ipv4_tun *set_tun,
        }
 
        /* Complete pre_tunnel action. */
-       pre_tun->ipv4_dst = ip_tun->key.u.ipv4.dst;
+       if (ipv6) {
+               pre_tun->flags |= cpu_to_be16(NFP_FL_PRE_TUN_IPV6);
+               pre_tun->ipv6_dst = ip_tun->key.u.ipv6.dst;
+       } else {
+               pre_tun->ipv4_dst = ip_tun->key.u.ipv4.dst;
+       }
 
        return 0;
 }
@@ -956,8 +985,8 @@ nfp_flower_loop_action(struct nfp_app *app, const struct flow_action_entry *act,
                       struct nfp_flower_pedit_acts *set_act, bool *pkt_host,
                       struct netlink_ext_ack *extack, int act_idx)
 {
-       struct nfp_fl_set_ipv4_tun *set_tun;
        struct nfp_fl_pre_tunnel *pre_tun;
+       struct nfp_fl_set_tun *set_tun;
        struct nfp_fl_push_vlan *psh_v;
        struct nfp_fl_push_mpls *psh_m;
        struct nfp_fl_pop_vlan *pop_v;
@@ -1032,7 +1061,7 @@ nfp_flower_loop_action(struct nfp_app *app, const struct flow_action_entry *act,
                 * If none, the packet falls back before applying other actions.
                 */
                if (*a_len + sizeof(struct nfp_fl_pre_tunnel) +
-                   sizeof(struct nfp_fl_set_ipv4_tun) > NFP_FL_MAX_A_SIZ) {
+                   sizeof(struct nfp_fl_set_tun) > NFP_FL_MAX_A_SIZ) {
                        NL_SET_ERR_MSG_MOD(extack, "unsupported offload: maximum allowed action list size exceeded at tunnel encap");
                        return -EOPNOTSUPP;
                }
@@ -1046,11 +1075,11 @@ nfp_flower_loop_action(struct nfp_app *app, const struct flow_action_entry *act,
                        return err;
 
                set_tun = (void *)&nfp_fl->action_data[*a_len];
-               err = nfp_fl_set_ipv4_tun(app, set_tun, act, pre_tun,
-                                         *tun_type, netdev, extack);
+               err = nfp_fl_set_tun(app, set_tun, act, pre_tun, *tun_type,
+                                    netdev, extack);
                if (err)
                        return err;
-               *a_len += sizeof(struct nfp_fl_set_ipv4_tun);
+               *a_len += sizeof(struct nfp_fl_set_tun);
                }
                break;
        case FLOW_ACTION_TUNNEL_DECAP:
index cbb94cf..7537695 100644 (file)
@@ -72,7 +72,7 @@
 #define NFP_FL_ACTION_OPCODE_POP_VLAN          2
 #define NFP_FL_ACTION_OPCODE_PUSH_MPLS         3
 #define NFP_FL_ACTION_OPCODE_POP_MPLS          4
-#define NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL   6
+#define NFP_FL_ACTION_OPCODE_SET_TUNNEL                6
 #define NFP_FL_ACTION_OPCODE_SET_ETHERNET      7
 #define NFP_FL_ACTION_OPCODE_SET_MPLS          8
 #define NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS    9
 
 /* Tunnel ports */
 #define NFP_FL_PORT_TYPE_TUN           0x50000000
-#define NFP_FL_IPV4_TUNNEL_TYPE                GENMASK(7, 4)
-#define NFP_FL_IPV4_PRE_TUN_INDEX      GENMASK(2, 0)
+#define NFP_FL_TUNNEL_TYPE             GENMASK(7, 4)
+#define NFP_FL_PRE_TUN_INDEX           GENMASK(2, 0)
 
 #define NFP_FLOWER_WORKQ_MAX_SKBS      30000
 
@@ -208,13 +208,16 @@ struct nfp_fl_pre_lag {
 
 struct nfp_fl_pre_tunnel {
        struct nfp_fl_act_head head;
-       __be16 reserved;
-       __be32 ipv4_dst;
-       /* reserved for use with IPv6 addresses */
-       __be32 extra[3];
+       __be16 flags;
+       union {
+               __be32 ipv4_dst;
+               struct in6_addr ipv6_dst;
+       };
 };
 
-struct nfp_fl_set_ipv4_tun {
+#define NFP_FL_PRE_TUN_IPV6    BIT(0)
+
+struct nfp_fl_set_tun {
        struct nfp_fl_act_head head;
        __be16 reserved;
        __be64 tun_id __packed;
index 83ada1b..d512105 100644 (file)
@@ -591,7 +591,7 @@ nfp_flower_update_merge_with_actions(struct nfp_fl_payload *flow,
                case NFP_FL_ACTION_OPCODE_POP_VLAN:
                        merge->tci = cpu_to_be16(0);
                        break;
-               case NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL:
+               case NFP_FL_ACTION_OPCODE_SET_TUNNEL:
                        /* New tunnel header means l2 to l4 can be matched. */
                        eth_broadcast_addr(&merge->l2.mac_dst[0]);
                        eth_broadcast_addr(&merge->l2.mac_src[0]);
@@ -814,15 +814,15 @@ nfp_fl_verify_post_tun_acts(char *acts, int len, struct nfp_fl_push_vlan **vlan)
 static int
 nfp_fl_push_vlan_after_tun(char *acts, int len, struct nfp_fl_push_vlan *vlan)
 {
-       struct nfp_fl_set_ipv4_tun *tun;
+       struct nfp_fl_set_tun *tun;
        struct nfp_fl_act_head *a;
        unsigned int act_off = 0;
 
        while (act_off < len) {
                a = (struct nfp_fl_act_head *)&acts[act_off];
 
-               if (a->jump_id == NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL) {
-                       tun = (struct nfp_fl_set_ipv4_tun *)a;
+               if (a->jump_id == NFP_FL_ACTION_OPCODE_SET_TUNNEL) {
+                       tun = (struct nfp_fl_set_tun *)a;
                        tun->outer_vlan_tpid = vlan->vlan_tpid;
                        tun->outer_vlan_tci = vlan->vlan_tci;