Skip to content

Commit b6ed55c

Browse files
committed
Merge branch 'nfp-Flower-flow-merging'
Simon Horman says: ==================== nfp: Flower flow merging John Hurley says, These patches deal with 'implicit recirculation' on the NFP. This is a firmware feature whereby a packet egresses to an 'internal' port meaning that it will recirculate back to the header extract phase with the 'internal' port now marked as its ingress port. This internal port can then be matched on by another rule. This process simulates how OvS datapath outputs to an internal port. The FW traces the packet's recirculation route and sends a 'merge hint' to the driver telling it which flows it matched against. The driver can then decide if these flows can be merged to a single rule and offloaded. The patches deal with the following issues: - assigning/freeing IDs to/from each of these new internal ports - offloading rules that match on internal ports - offloading neighbour table entries whose egress port is internal - handling fallback traffic with an internal port as ingress - using merge hints to create 'faster path' flows and tracking stats etc. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 47a1a22 + 8af56f4 commit b6ed55c

File tree

11 files changed

+1016
-53
lines changed

11 files changed

+1016
-53
lines changed

drivers/net/ethernet/netronome/nfp/abm/main.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ nfp_abm_setup_tc(struct nfp_app *app, struct net_device *netdev,
5353
}
5454
}
5555

56-
static struct net_device *nfp_abm_repr_get(struct nfp_app *app, u32 port_id)
56+
static struct net_device *
57+
nfp_abm_repr_get(struct nfp_app *app, u32 port_id, bool *redir_egress)
5758
{
5859
enum nfp_repr_type rtype;
5960
struct nfp_reprs *reprs;
@@ -549,5 +550,5 @@ const struct nfp_app_type app_abm = {
549550
.eswitch_mode_get = nfp_abm_eswitch_mode_get,
550551
.eswitch_mode_set = nfp_abm_eswitch_mode_set,
551552

552-
.repr_get = nfp_abm_repr_get,
553+
.dev_get = nfp_abm_repr_get,
553554
};

drivers/net/ethernet/netronome/nfp/flower/cmsg.c

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ nfp_flower_cmsg_portmod_rx(struct nfp_app *app, struct sk_buff *skb)
159159

160160
rtnl_lock();
161161
rcu_read_lock();
162-
netdev = nfp_app_repr_get(app, be32_to_cpu(msg->portnum));
162+
netdev = nfp_app_dev_get(app, be32_to_cpu(msg->portnum), NULL);
163163
rcu_read_unlock();
164164
if (!netdev) {
165165
nfp_flower_cmsg_warn(app, "ctrl msg for unknown port 0x%08x\n",
@@ -192,7 +192,7 @@ nfp_flower_cmsg_portreify_rx(struct nfp_app *app, struct sk_buff *skb)
192192
msg = nfp_flower_cmsg_get_data(skb);
193193

194194
rcu_read_lock();
195-
exists = !!nfp_app_repr_get(app, be32_to_cpu(msg->portnum));
195+
exists = !!nfp_app_dev_get(app, be32_to_cpu(msg->portnum), NULL);
196196
rcu_read_unlock();
197197
if (!exists) {
198198
nfp_flower_cmsg_warn(app, "ctrl msg for unknown port 0x%08x\n",
@@ -204,6 +204,50 @@ nfp_flower_cmsg_portreify_rx(struct nfp_app *app, struct sk_buff *skb)
204204
wake_up(&priv->reify_wait_queue);
205205
}
206206

207+
static void
208+
nfp_flower_cmsg_merge_hint_rx(struct nfp_app *app, struct sk_buff *skb)
209+
{
210+
unsigned int msg_len = nfp_flower_cmsg_get_data_len(skb);
211+
struct nfp_flower_cmsg_merge_hint *msg;
212+
struct nfp_fl_payload *sub_flows[2];
213+
int err, i, flow_cnt;
214+
215+
msg = nfp_flower_cmsg_get_data(skb);
216+
/* msg->count starts at 0 and always assumes at least 1 entry. */
217+
flow_cnt = msg->count + 1;
218+
219+
if (msg_len < struct_size(msg, flow, flow_cnt)) {
220+
nfp_flower_cmsg_warn(app, "Merge hint ctrl msg too short - %d bytes but expect %ld\n",
221+
msg_len, struct_size(msg, flow, flow_cnt));
222+
return;
223+
}
224+
225+
if (flow_cnt != 2) {
226+
nfp_flower_cmsg_warn(app, "Merge hint contains %d flows - two are expected\n",
227+
flow_cnt);
228+
return;
229+
}
230+
231+
rtnl_lock();
232+
for (i = 0; i < flow_cnt; i++) {
233+
u32 ctx = be32_to_cpu(msg->flow[i].host_ctx);
234+
235+
sub_flows[i] = nfp_flower_get_fl_payload_from_ctx(app, ctx);
236+
if (!sub_flows[i]) {
237+
nfp_flower_cmsg_warn(app, "Invalid flow in merge hint\n");
238+
goto err_rtnl_unlock;
239+
}
240+
}
241+
242+
err = nfp_flower_merge_offloaded_flows(app, sub_flows[0], sub_flows[1]);
243+
/* Only warn on memory fail. Hint veto will not break functionality. */
244+
if (err == -ENOMEM)
245+
nfp_flower_cmsg_warn(app, "Flow merge memory fail.\n");
246+
247+
err_rtnl_unlock:
248+
rtnl_unlock();
249+
}
250+
207251
static void
208252
nfp_flower_cmsg_process_one_rx(struct nfp_app *app, struct sk_buff *skb)
209253
{
@@ -222,6 +266,12 @@ nfp_flower_cmsg_process_one_rx(struct nfp_app *app, struct sk_buff *skb)
222266
case NFP_FLOWER_CMSG_TYPE_PORT_MOD:
223267
nfp_flower_cmsg_portmod_rx(app, skb);
224268
break;
269+
case NFP_FLOWER_CMSG_TYPE_MERGE_HINT:
270+
if (app_priv->flower_ext_feats & NFP_FL_FEATS_FLOW_MERGE) {
271+
nfp_flower_cmsg_merge_hint_rx(app, skb);
272+
break;
273+
}
274+
goto err_default;
225275
case NFP_FLOWER_CMSG_TYPE_NO_NEIGH:
226276
nfp_tunnel_request_route(app, skb);
227277
break;
@@ -235,6 +285,7 @@ nfp_flower_cmsg_process_one_rx(struct nfp_app *app, struct sk_buff *skb)
235285
}
236286
/* fall through */
237287
default:
288+
err_default:
238289
nfp_flower_cmsg_warn(app, "Cannot handle invalid repr control type %u\n",
239290
type);
240291
goto out;

drivers/net/ethernet/netronome/nfp/flower/cmsg.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,11 +402,13 @@ struct nfp_flower_cmsg_hdr {
402402
/* Types defined for port related control messages */
403403
enum nfp_flower_cmsg_type_port {
404404
NFP_FLOWER_CMSG_TYPE_FLOW_ADD = 0,
405+
NFP_FLOWER_CMSG_TYPE_FLOW_MOD = 1,
405406
NFP_FLOWER_CMSG_TYPE_FLOW_DEL = 2,
406407
NFP_FLOWER_CMSG_TYPE_LAG_CONFIG = 4,
407408
NFP_FLOWER_CMSG_TYPE_PORT_REIFY = 6,
408409
NFP_FLOWER_CMSG_TYPE_MAC_REPR = 7,
409410
NFP_FLOWER_CMSG_TYPE_PORT_MOD = 8,
411+
NFP_FLOWER_CMSG_TYPE_MERGE_HINT = 9,
410412
NFP_FLOWER_CMSG_TYPE_NO_NEIGH = 10,
411413
NFP_FLOWER_CMSG_TYPE_TUN_MAC = 11,
412414
NFP_FLOWER_CMSG_TYPE_ACTIVE_TUNS = 12,
@@ -451,6 +453,16 @@ struct nfp_flower_cmsg_portreify {
451453

452454
#define NFP_FLOWER_CMSG_PORTREIFY_INFO_EXIST BIT(0)
453455

456+
/* NFP_FLOWER_CMSG_TYPE_FLOW_MERGE_HINT */
457+
struct nfp_flower_cmsg_merge_hint {
458+
u8 reserved[3];
459+
u8 count;
460+
struct {
461+
__be32 host_ctx;
462+
__be64 host_cookie;
463+
} __packed flow[0];
464+
};
465+
454466
enum nfp_flower_cmsg_port_type {
455467
NFP_FLOWER_CMSG_PORT_TYPE_UNSPEC = 0x0,
456468
NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT = 0x1,
@@ -473,6 +485,13 @@ enum nfp_flower_cmsg_port_vnic_type {
473485
#define NFP_FLOWER_CMSG_PORT_PCIE_Q GENMASK(5, 0)
474486
#define NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM GENMASK(7, 0)
475487

488+
static inline u32 nfp_flower_internal_port_get_port_id(u8 internal_port)
489+
{
490+
return FIELD_PREP(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM, internal_port) |
491+
FIELD_PREP(NFP_FLOWER_CMSG_PORT_TYPE,
492+
NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT);
493+
}
494+
476495
static inline u32 nfp_flower_cmsg_phys_port(u8 phys_port)
477496
{
478497
return FIELD_PREP(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM, phys_port) |

drivers/net/ethernet/netronome/nfp/flower/main.c

Lines changed: 147 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222

2323
#define NFP_FLOWER_ALLOWED_VER 0x0001000000010000UL
2424

25+
#define NFP_MIN_INT_PORT_ID 1
26+
#define NFP_MAX_INT_PORT_ID 256
27+
2528
static const char *nfp_flower_extra_cap(struct nfp_app *app, struct nfp_net *nn)
2629
{
2730
return "FLOWER";
@@ -32,6 +35,113 @@ static enum devlink_eswitch_mode eswitch_mode_get(struct nfp_app *app)
3235
return DEVLINK_ESWITCH_MODE_SWITCHDEV;
3336
}
3437

38+
static int
39+
nfp_flower_lookup_internal_port_id(struct nfp_flower_priv *priv,
40+
struct net_device *netdev)
41+
{
42+
struct net_device *entry;
43+
int i, id = 0;
44+
45+
rcu_read_lock();
46+
idr_for_each_entry(&priv->internal_ports.port_ids, entry, i)
47+
if (entry == netdev) {
48+
id = i;
49+
break;
50+
}
51+
rcu_read_unlock();
52+
53+
return id;
54+
}
55+
56+
static int
57+
nfp_flower_get_internal_port_id(struct nfp_app *app, struct net_device *netdev)
58+
{
59+
struct nfp_flower_priv *priv = app->priv;
60+
int id;
61+
62+
id = nfp_flower_lookup_internal_port_id(priv, netdev);
63+
if (id > 0)
64+
return id;
65+
66+
idr_preload(GFP_ATOMIC);
67+
spin_lock_bh(&priv->internal_ports.lock);
68+
id = idr_alloc(&priv->internal_ports.port_ids, netdev,
69+
NFP_MIN_INT_PORT_ID, NFP_MAX_INT_PORT_ID, GFP_ATOMIC);
70+
spin_unlock_bh(&priv->internal_ports.lock);
71+
idr_preload_end();
72+
73+
return id;
74+
}
75+
76+
u32 nfp_flower_get_port_id_from_netdev(struct nfp_app *app,
77+
struct net_device *netdev)
78+
{
79+
int ext_port;
80+
81+
if (nfp_netdev_is_nfp_repr(netdev)) {
82+
return nfp_repr_get_port_id(netdev);
83+
} else if (nfp_flower_internal_port_can_offload(app, netdev)) {
84+
ext_port = nfp_flower_get_internal_port_id(app, netdev);
85+
if (ext_port < 0)
86+
return 0;
87+
88+
return nfp_flower_internal_port_get_port_id(ext_port);
89+
}
90+
91+
return 0;
92+
}
93+
94+
static struct net_device *
95+
nfp_flower_get_netdev_from_internal_port_id(struct nfp_app *app, int port_id)
96+
{
97+
struct nfp_flower_priv *priv = app->priv;
98+
struct net_device *netdev;
99+
100+
rcu_read_lock();
101+
netdev = idr_find(&priv->internal_ports.port_ids, port_id);
102+
rcu_read_unlock();
103+
104+
return netdev;
105+
}
106+
107+
static void
108+
nfp_flower_free_internal_port_id(struct nfp_app *app, struct net_device *netdev)
109+
{
110+
struct nfp_flower_priv *priv = app->priv;
111+
int id;
112+
113+
id = nfp_flower_lookup_internal_port_id(priv, netdev);
114+
if (!id)
115+
return;
116+
117+
spin_lock_bh(&priv->internal_ports.lock);
118+
idr_remove(&priv->internal_ports.port_ids, id);
119+
spin_unlock_bh(&priv->internal_ports.lock);
120+
}
121+
122+
static int
123+
nfp_flower_internal_port_event_handler(struct nfp_app *app,
124+
struct net_device *netdev,
125+
unsigned long event)
126+
{
127+
if (event == NETDEV_UNREGISTER &&
128+
nfp_flower_internal_port_can_offload(app, netdev))
129+
nfp_flower_free_internal_port_id(app, netdev);
130+
131+
return NOTIFY_OK;
132+
}
133+
134+
static void nfp_flower_internal_port_init(struct nfp_flower_priv *priv)
135+
{
136+
spin_lock_init(&priv->internal_ports.lock);
137+
idr_init(&priv->internal_ports.port_ids);
138+
}
139+
140+
static void nfp_flower_internal_port_cleanup(struct nfp_flower_priv *priv)
141+
{
142+
idr_destroy(&priv->internal_ports.port_ids);
143+
}
144+
35145
static struct nfp_flower_non_repr_priv *
36146
nfp_flower_non_repr_priv_lookup(struct nfp_app *app, struct net_device *netdev)
37147
{
@@ -119,12 +229,21 @@ nfp_flower_repr_get_type_and_port(struct nfp_app *app, u32 port_id, u8 *port)
119229
}
120230

121231
static struct net_device *
122-
nfp_flower_repr_get(struct nfp_app *app, u32 port_id)
232+
nfp_flower_dev_get(struct nfp_app *app, u32 port_id, bool *redir_egress)
123233
{
124234
enum nfp_repr_type repr_type;
125235
struct nfp_reprs *reprs;
126236
u8 port = 0;
127237

238+
/* Check if the port is internal. */
239+
if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port_id) ==
240+
NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT) {
241+
if (redir_egress)
242+
*redir_egress = true;
243+
port = FIELD_GET(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM, port_id);
244+
return nfp_flower_get_netdev_from_internal_port_id(app, port);
245+
}
246+
128247
repr_type = nfp_flower_repr_get_type_and_port(app, port_id, &port);
129248
if (repr_type > NFP_REPR_TYPE_MAX)
130249
return NULL;
@@ -641,11 +760,30 @@ static int nfp_flower_init(struct nfp_app *app)
641760
goto err_cleanup_metadata;
642761
}
643762

763+
if (app_priv->flower_ext_feats & NFP_FL_FEATS_FLOW_MOD) {
764+
/* Tell the firmware that the driver supports flow merging. */
765+
err = nfp_rtsym_write_le(app->pf->rtbl,
766+
"_abi_flower_merge_hint_enable", 1);
767+
if (!err) {
768+
app_priv->flower_ext_feats |= NFP_FL_FEATS_FLOW_MERGE;
769+
nfp_flower_internal_port_init(app_priv);
770+
} else if (err == -ENOENT) {
771+
nfp_warn(app->cpp, "Flow merge not supported by FW.\n");
772+
} else {
773+
goto err_lag_clean;
774+
}
775+
} else {
776+
nfp_warn(app->cpp, "Flow mod/merge not supported by FW.\n");
777+
}
778+
644779
INIT_LIST_HEAD(&app_priv->indr_block_cb_priv);
645780
INIT_LIST_HEAD(&app_priv->non_repr_priv);
646781

647782
return 0;
648783

784+
err_lag_clean:
785+
if (app_priv->flower_ext_feats & NFP_FL_FEATS_LAG)
786+
nfp_flower_lag_cleanup(&app_priv->nfp_lag);
649787
err_cleanup_metadata:
650788
nfp_flower_metadata_cleanup(app);
651789
err_free_app_priv:
@@ -664,6 +802,9 @@ static void nfp_flower_clean(struct nfp_app *app)
664802
if (app_priv->flower_ext_feats & NFP_FL_FEATS_LAG)
665803
nfp_flower_lag_cleanup(&app_priv->nfp_lag);
666804

805+
if (app_priv->flower_ext_feats & NFP_FL_FEATS_FLOW_MERGE)
806+
nfp_flower_internal_port_cleanup(app_priv);
807+
667808
nfp_flower_metadata_cleanup(app);
668809
vfree(app->priv);
669810
app->priv = NULL;
@@ -762,6 +903,10 @@ nfp_flower_netdev_event(struct nfp_app *app, struct net_device *netdev,
762903
if (ret & NOTIFY_STOP_MASK)
763904
return ret;
764905

906+
ret = nfp_flower_internal_port_event_handler(app, netdev, event);
907+
if (ret & NOTIFY_STOP_MASK)
908+
return ret;
909+
765910
return nfp_tunnel_mac_event_handler(app, netdev, event, ptr);
766911
}
767912

@@ -800,7 +945,7 @@ const struct nfp_app_type app_flower = {
800945
.sriov_disable = nfp_flower_sriov_disable,
801946

802947
.eswitch_mode_get = eswitch_mode_get,
803-
.repr_get = nfp_flower_repr_get,
948+
.dev_get = nfp_flower_dev_get,
804949

805950
.setup_tc = nfp_flower_setup_tc,
806951
};

0 commit comments

Comments
 (0)