Skip to content

Commit

Permalink
Merge branch 'nfp-more-set-actions-and-notifier-refactor'
Browse files Browse the repository at this point in the history
Jakub Kicinski says:

====================
nfp: more set actions and notifier refactor

This series brings updates to flower offload code.  First Pieter adds
support for setting TTL, ToS, Flow Label and Hop Limit fields in IPv4
and IPv6 headers.

Remaining 5 patches deal with factoring out netdev notifiers from flower
code.  We already have two instances, and more is coming, so it's time
to move to one central notifier which then feeds individual feature
handlers.

I start that part by cleaning up the existing notifiers.  Next a central
notifier is added, and used by flower offloads.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Nov 7, 2018
2 parents 6a02d1f + 0c665e2 commit 75790a7
Show file tree
Hide file tree
Showing 8 changed files with 252 additions and 104 deletions.
134 changes: 124 additions & 10 deletions drivers/net/ethernet/netronome/nfp/flower/action.c
Original file line number Diff line number Diff line change
Expand Up @@ -384,10 +384,21 @@ nfp_fl_set_eth(const struct tc_action *action, int idx, u32 off,
return 0;
}

struct ipv4_ttl_word {
__u8 ttl;
__u8 protocol;
__sum16 check;
};

static int
nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off,
struct nfp_fl_set_ip4_addrs *set_ip_addr)
struct nfp_fl_set_ip4_addrs *set_ip_addr,
struct nfp_fl_set_ip4_ttl_tos *set_ip_ttl_tos)
{
struct ipv4_ttl_word *ttl_word_mask;
struct ipv4_ttl_word *ttl_word;
struct iphdr *tos_word_mask;
struct iphdr *tos_word;
__be32 exact, mask;

/* We are expecting tcf_pedit to return a big endian value */
Expand All @@ -402,20 +413,53 @@ nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off,
set_ip_addr->ipv4_dst_mask |= mask;
set_ip_addr->ipv4_dst &= ~mask;
set_ip_addr->ipv4_dst |= exact & mask;
set_ip_addr->head.jump_id = NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS;
set_ip_addr->head.len_lw = sizeof(*set_ip_addr) >>
NFP_FL_LW_SIZ;
break;
case offsetof(struct iphdr, saddr):
set_ip_addr->ipv4_src_mask |= mask;
set_ip_addr->ipv4_src &= ~mask;
set_ip_addr->ipv4_src |= exact & mask;
set_ip_addr->head.jump_id = NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS;
set_ip_addr->head.len_lw = sizeof(*set_ip_addr) >>
NFP_FL_LW_SIZ;
break;
case offsetof(struct iphdr, ttl):
ttl_word_mask = (struct ipv4_ttl_word *)&mask;
ttl_word = (struct ipv4_ttl_word *)&exact;

if (ttl_word_mask->protocol || ttl_word_mask->check)
return -EOPNOTSUPP;

set_ip_ttl_tos->ipv4_ttl_mask |= ttl_word_mask->ttl;
set_ip_ttl_tos->ipv4_ttl &= ~ttl_word_mask->ttl;
set_ip_ttl_tos->ipv4_ttl |= ttl_word->ttl & ttl_word_mask->ttl;
set_ip_ttl_tos->head.jump_id =
NFP_FL_ACTION_OPCODE_SET_IPV4_TTL_TOS;
set_ip_ttl_tos->head.len_lw = sizeof(*set_ip_ttl_tos) >>
NFP_FL_LW_SIZ;
break;
case round_down(offsetof(struct iphdr, tos), 4):
tos_word_mask = (struct iphdr *)&mask;
tos_word = (struct iphdr *)&exact;

if (tos_word_mask->version || tos_word_mask->ihl ||
tos_word_mask->tot_len)
return -EOPNOTSUPP;

set_ip_ttl_tos->ipv4_tos_mask |= tos_word_mask->tos;
set_ip_ttl_tos->ipv4_tos &= ~tos_word_mask->tos;
set_ip_ttl_tos->ipv4_tos |= tos_word->tos & tos_word_mask->tos;
set_ip_ttl_tos->head.jump_id =
NFP_FL_ACTION_OPCODE_SET_IPV4_TTL_TOS;
set_ip_ttl_tos->head.len_lw = sizeof(*set_ip_ttl_tos) >>
NFP_FL_LW_SIZ;
break;
default:
return -EOPNOTSUPP;
}

set_ip_addr->reserved = cpu_to_be16(0);
set_ip_addr->head.jump_id = NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS;
set_ip_addr->head.len_lw = sizeof(*set_ip_addr) >> NFP_FL_LW_SIZ;

return 0;
}

Expand All @@ -432,12 +476,57 @@ nfp_fl_set_ip6_helper(int opcode_tag, u8 word, __be32 exact, __be32 mask,
ip6->head.len_lw = sizeof(*ip6) >> NFP_FL_LW_SIZ;
}

struct ipv6_hop_limit_word {
__be16 payload_len;
u8 nexthdr;
u8 hop_limit;
};

static int
nfp_fl_set_ip6_hop_limit_flow_label(u32 off, __be32 exact, __be32 mask,
struct nfp_fl_set_ipv6_tc_hl_fl *ip_hl_fl)
{
struct ipv6_hop_limit_word *fl_hl_mask;
struct ipv6_hop_limit_word *fl_hl;

switch (off) {
case offsetof(struct ipv6hdr, payload_len):
fl_hl_mask = (struct ipv6_hop_limit_word *)&mask;
fl_hl = (struct ipv6_hop_limit_word *)&exact;

if (fl_hl_mask->nexthdr || fl_hl_mask->payload_len)
return -EOPNOTSUPP;

ip_hl_fl->ipv6_hop_limit_mask |= fl_hl_mask->hop_limit;
ip_hl_fl->ipv6_hop_limit &= ~fl_hl_mask->hop_limit;
ip_hl_fl->ipv6_hop_limit |= fl_hl->hop_limit &
fl_hl_mask->hop_limit;
break;
case round_down(offsetof(struct ipv6hdr, flow_lbl), 4):
if (mask & ~IPV6_FLOW_LABEL_MASK ||
exact & ~IPV6_FLOW_LABEL_MASK)
return -EOPNOTSUPP;

ip_hl_fl->ipv6_label_mask |= mask;
ip_hl_fl->ipv6_label &= ~mask;
ip_hl_fl->ipv6_label |= exact & mask;
break;
}

ip_hl_fl->head.jump_id = NFP_FL_ACTION_OPCODE_SET_IPV6_TC_HL_FL;
ip_hl_fl->head.len_lw = sizeof(*ip_hl_fl) >> NFP_FL_LW_SIZ;

return 0;
}

static int
nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off,
struct nfp_fl_set_ipv6_addr *ip_dst,
struct nfp_fl_set_ipv6_addr *ip_src)
struct nfp_fl_set_ipv6_addr *ip_src,
struct nfp_fl_set_ipv6_tc_hl_fl *ip_hl_fl)
{
__be32 exact, mask;
int err = 0;
u8 word;

/* We are expecting tcf_pedit to return a big endian value */
Expand All @@ -448,7 +537,8 @@ nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off,
return -EOPNOTSUPP;

if (off < offsetof(struct ipv6hdr, saddr)) {
return -EOPNOTSUPP;
err = nfp_fl_set_ip6_hop_limit_flow_label(off, exact, mask,
ip_hl_fl);
} else if (off < offsetof(struct ipv6hdr, daddr)) {
word = (off - offsetof(struct ipv6hdr, saddr)) / sizeof(exact);
nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_SRC, word,
Expand All @@ -462,7 +552,7 @@ nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off,
return -EOPNOTSUPP;
}

return 0;
return err;
}

static int
Expand Down Expand Up @@ -513,6 +603,8 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
char *nfp_action, int *a_len, u32 *csum_updated)
{
struct nfp_fl_set_ipv6_addr set_ip6_dst, set_ip6_src;
struct nfp_fl_set_ipv6_tc_hl_fl set_ip6_tc_hl_fl;
struct nfp_fl_set_ip4_ttl_tos set_ip_ttl_tos;
struct nfp_fl_set_ip4_addrs set_ip_addr;
struct nfp_fl_set_tport set_tport;
struct nfp_fl_set_eth set_eth;
Expand All @@ -522,6 +614,8 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
u32 offset, cmd;
u8 ip_proto = 0;

memset(&set_ip6_tc_hl_fl, 0, sizeof(set_ip6_tc_hl_fl));
memset(&set_ip_ttl_tos, 0, sizeof(set_ip_ttl_tos));
memset(&set_ip6_dst, 0, sizeof(set_ip6_dst));
memset(&set_ip6_src, 0, sizeof(set_ip6_src));
memset(&set_ip_addr, 0, sizeof(set_ip_addr));
Expand All @@ -542,11 +636,12 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
err = nfp_fl_set_eth(action, idx, offset, &set_eth);
break;
case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4:
err = nfp_fl_set_ip4(action, idx, offset, &set_ip_addr);
err = nfp_fl_set_ip4(action, idx, offset, &set_ip_addr,
&set_ip_ttl_tos);
break;
case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6:
err = nfp_fl_set_ip6(action, idx, offset, &set_ip6_dst,
&set_ip6_src);
&set_ip6_src, &set_ip6_tc_hl_fl);
break;
case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP:
err = nfp_fl_set_tport(action, idx, offset, &set_tport,
Expand Down Expand Up @@ -577,6 +672,16 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
memcpy(nfp_action, &set_eth, act_size);
*a_len += act_size;
}
if (set_ip_ttl_tos.head.len_lw) {
nfp_action += act_size;
act_size = sizeof(set_ip_ttl_tos);
memcpy(nfp_action, &set_ip_ttl_tos, act_size);
*a_len += act_size;

/* Hardware will automatically fix IPv4 and TCP/UDP checksum. */
*csum_updated |= TCA_CSUM_UPDATE_FLAG_IPV4HDR |
nfp_fl_csum_l4_to_flag(ip_proto);
}
if (set_ip_addr.head.len_lw) {
nfp_action += act_size;
act_size = sizeof(set_ip_addr);
Expand All @@ -587,6 +692,15 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
*csum_updated |= TCA_CSUM_UPDATE_FLAG_IPV4HDR |
nfp_fl_csum_l4_to_flag(ip_proto);
}
if (set_ip6_tc_hl_fl.head.len_lw) {
nfp_action += act_size;
act_size = sizeof(set_ip6_tc_hl_fl);
memcpy(nfp_action, &set_ip6_tc_hl_fl, act_size);
*a_len += act_size;

/* Hardware will automatically fix TCP/UDP checksum. */
*csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto);
}
if (set_ip6_dst.head.len_lw && set_ip6_src.head.len_lw) {
/* TC compiles set src and dst IPv6 address as a single action,
* the hardware requires this to be 2 separate actions.
Expand Down
24 changes: 24 additions & 0 deletions drivers/net/ethernet/netronome/nfp/flower/cmsg.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@
#define NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL 6
#define NFP_FL_ACTION_OPCODE_SET_ETHERNET 7
#define NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS 9
#define NFP_FL_ACTION_OPCODE_SET_IPV4_TTL_TOS 10
#define NFP_FL_ACTION_OPCODE_SET_IPV6_SRC 11
#define NFP_FL_ACTION_OPCODE_SET_IPV6_DST 12
#define NFP_FL_ACTION_OPCODE_SET_IPV6_TC_HL_FL 13
#define NFP_FL_ACTION_OPCODE_SET_UDP 14
#define NFP_FL_ACTION_OPCODE_SET_TCP 15
#define NFP_FL_ACTION_OPCODE_PRE_LAG 16
Expand All @@ -82,6 +84,8 @@
#define NFP_FL_PUSH_VLAN_CFI BIT(12)
#define NFP_FL_PUSH_VLAN_VID GENMASK(11, 0)

#define IPV6_FLOW_LABEL_MASK cpu_to_be32(0x000fffff)

/* LAG ports */
#define NFP_FL_LAG_OUT 0xC0DE0000

Expand Down Expand Up @@ -125,6 +129,26 @@ struct nfp_fl_set_ip4_addrs {
__be32 ipv4_dst;
};

struct nfp_fl_set_ip4_ttl_tos {
struct nfp_fl_act_head head;
u8 ipv4_ttl_mask;
u8 ipv4_tos_mask;
u8 ipv4_ttl;
u8 ipv4_tos;
__be16 reserved;
};

struct nfp_fl_set_ipv6_tc_hl_fl {
struct nfp_fl_act_head head;
u8 ipv6_tc_mask;
u8 ipv6_hop_limit_mask;
__be16 reserved;
u8 ipv6_tc;
u8 ipv6_hop_limit;
__be32 ipv6_label_mask;
__be32 ipv6_label;
};

struct nfp_fl_set_ipv6_addr {
struct nfp_fl_act_head head;
__be16 reserved;
Expand Down
48 changes: 21 additions & 27 deletions drivers/net/ethernet/netronome/nfp/flower/lag_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,25 +472,32 @@ nfp_fl_lag_schedule_group_remove(struct nfp_fl_lag *lag,
schedule_delayed_work(&lag->work, NFP_FL_LAG_DELAY);
}

static int
static void
nfp_fl_lag_schedule_group_delete(struct nfp_fl_lag *lag,
struct net_device *master)
{
struct nfp_fl_lag_group *group;
struct nfp_flower_priv *priv;

priv = container_of(lag, struct nfp_flower_priv, nfp_lag);

if (!netif_is_bond_master(master))
return;

mutex_lock(&lag->lock);
group = nfp_fl_lag_find_group_for_master_with_lag(lag, master);
if (!group) {
mutex_unlock(&lag->lock);
return -ENOENT;
nfp_warn(priv->app->cpp, "untracked bond got unregistered %s\n",
netdev_name(master));
return;
}

group->to_remove = true;
group->to_destroy = true;
mutex_unlock(&lag->lock);

schedule_delayed_work(&lag->work, NFP_FL_LAG_DELAY);
return 0;
}

static int
Expand Down Expand Up @@ -575,7 +582,7 @@ nfp_fl_lag_changeupper_event(struct nfp_fl_lag *lag,
return 0;
}

static int
static void
nfp_fl_lag_changels_event(struct nfp_fl_lag *lag, struct net_device *netdev,
struct netdev_notifier_changelowerstate_info *info)
{
Expand All @@ -586,18 +593,18 @@ nfp_fl_lag_changels_event(struct nfp_fl_lag *lag, struct net_device *netdev,
unsigned long *flags;

if (!netif_is_lag_port(netdev) || !nfp_netdev_is_nfp_repr(netdev))
return 0;
return;

lag_lower_info = info->lower_state_info;
if (!lag_lower_info)
return 0;
return;

priv = container_of(lag, struct nfp_flower_priv, nfp_lag);
repr = netdev_priv(netdev);

/* Verify that the repr is associated with this app. */
if (repr->app != priv->app)
return 0;
return;

repr_priv = repr->app_priv;
flags = &repr_priv->lag_port_flags;
Expand All @@ -617,38 +624,27 @@ nfp_fl_lag_changels_event(struct nfp_fl_lag *lag, struct net_device *netdev,
mutex_unlock(&lag->lock);

schedule_delayed_work(&lag->work, NFP_FL_LAG_DELAY);
return 0;
}

static int
nfp_fl_lag_netdev_event(struct notifier_block *nb, unsigned long event,
void *ptr)
int nfp_flower_lag_netdev_event(struct nfp_flower_priv *priv,
struct net_device *netdev,
unsigned long event, void *ptr)
{
struct net_device *netdev;
struct nfp_fl_lag *lag;
struct nfp_fl_lag *lag = &priv->nfp_lag;
int err;

netdev = netdev_notifier_info_to_dev(ptr);
lag = container_of(nb, struct nfp_fl_lag, lag_nb);

switch (event) {
case NETDEV_CHANGEUPPER:
err = nfp_fl_lag_changeupper_event(lag, ptr);
if (err)
return NOTIFY_BAD;
return NOTIFY_OK;
case NETDEV_CHANGELOWERSTATE:
err = nfp_fl_lag_changels_event(lag, netdev, ptr);
if (err)
return NOTIFY_BAD;
nfp_fl_lag_changels_event(lag, netdev, ptr);
return NOTIFY_OK;
case NETDEV_UNREGISTER:
if (netif_is_bond_master(netdev)) {
err = nfp_fl_lag_schedule_group_delete(lag, netdev);
if (err)
return NOTIFY_BAD;
return NOTIFY_OK;
}
nfp_fl_lag_schedule_group_delete(lag, netdev);
return NOTIFY_OK;
}

return NOTIFY_DONE;
Expand All @@ -673,8 +669,6 @@ void nfp_flower_lag_init(struct nfp_fl_lag *lag)

/* 0 is a reserved batch version so increment to first valid value. */
nfp_fl_increment_version(lag);

lag->lag_nb.notifier_call = nfp_fl_lag_netdev_event;
}

void nfp_flower_lag_cleanup(struct nfp_fl_lag *lag)
Expand Down
Loading

0 comments on commit 75790a7

Please sign in to comment.