@@ -12,5 +12,7 @@ struct netns_smc {
/* protect fback_rsn */
struct mutex mutex_fback_rsn;
struct smc_stats_rsn *fback_rsn;
+
+ bool auto_fallback; /* whether allow auto_fallback */
};
#endif
@@ -59,6 +59,9 @@ enum {
SMC_NETLINK_DUMP_SEID,
SMC_NETLINK_ENABLE_SEID,
SMC_NETLINK_DISABLE_SEID,
+ SMC_NETLINK_DUMP_AUTO_FALLBACK,
+ SMC_NETLINK_ENABLE_AUTO_FALLBACK,
+ SMC_NETLINK_DISABLE_AUTO_FALLBACK,
};
/* SMC_GENL_FAMILY top level attributes */
@@ -285,6 +288,14 @@ enum {
SMC_NLA_SEID_TABLE_MAX = __SMC_NLA_SEID_TABLE_MAX - 1
};
+/* SMC_NETLINK_AUTO_FALLBACK attributes */
+enum {
+ SMC_NLA_AUTO_FALLBACK_UNSPEC,
+ SMC_NLA_AUTO_FALLBACK_ENABLED, /* u8 */
+ __SMC_NLA_AUTO_FALLBACK_MAX,
+ SMC_NLA_AUTO_FALLBACK_MAX = __SMC_NLA_AUTO_FALLBACK_MAX - 1
+};
+
/* SMC socket options */
#define SMC_AUTO_FALLBACK 1 /* allow auto fallback to TCP */
@@ -66,6 +66,44 @@
static void smc_tcp_listen_work(struct work_struct *);
static void smc_connect_work(struct work_struct *);
+int smc_nl_dump_auto_fallback(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb);
+ void *hdr;
+
+ if (cb_ctx->pos[0])
+ goto out;
+
+ hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
+ &smc_gen_nl_family, NLM_F_MULTI,
+ SMC_NETLINK_DUMP_AUTO_FALLBACK);
+ if (!hdr)
+ return -ENOMEM;
+
+ if (nla_put_u8(skb, SMC_NLA_AUTO_FALLBACK_ENABLED, sock_net(skb->sk)->smc.auto_fallback))
+ goto err;
+
+ genlmsg_end(skb, hdr);
+ cb_ctx->pos[0] = 1;
+out:
+ return skb->len;
+err:
+ genlmsg_cancel(skb, hdr);
+ return -EMSGSIZE;
+}
+
+int smc_nl_enable_auto_fallback(struct sk_buff *skb, struct genl_info *info)
+{
+ sock_net(skb->sk)->smc.auto_fallback = true;
+ return 0;
+}
+
+int smc_nl_disable_auto_fallback(struct sk_buff *skb, struct genl_info *info)
+{
+ sock_net(skb->sk)->smc.auto_fallback = false;
+ return 0;
+}
+
static void smc_set_keepalive(struct sock *sk, int val)
{
struct smc_sock *smc = smc_sk(sk);
@@ -3006,6 +3044,9 @@ static int __smc_create(struct net *net, struct socket *sock, int protocol,
smc->use_fallback = false; /* assume rdma capability first */
smc->fallback_rsn = 0;
+ /* default behavior from auto_fallback */
+ smc->auto_fallback = net->smc.auto_fallback;
+
rc = 0;
if (!clcsock) {
rc = sock_create_kern(net, family, SOCK_STREAM, IPPROTO_TCP,
@@ -14,6 +14,7 @@
#include <linux/socket.h>
#include <linux/types.h>
#include <linux/compiler.h> /* __aligned */
+#include <net/genetlink.h>
#include <net/sock.h>
#include "smc_ib.h"
@@ -336,4 +337,9 @@ void smc_fill_gid_list(struct smc_link_group *lgr,
struct smc_gidlist *gidlist,
struct smc_ib_device *known_dev, u8 *known_gid);
+/* smc auto_fallback interface for netlink */
+int smc_nl_dump_auto_fallback(struct sk_buff *skb, struct netlink_callback *cb);
+int smc_nl_enable_auto_fallback(struct sk_buff *skb, struct genl_info *info);
+int smc_nl_disable_auto_fallback(struct sk_buff *skb, struct genl_info *info);
+
#endif /* __SMC_H */
@@ -111,6 +111,21 @@
.flags = GENL_ADMIN_PERM,
.doit = smc_nl_disable_seid,
},
+ {
+ .cmd = SMC_NETLINK_DUMP_AUTO_FALLBACK,
+ /* can be retrieved by unprivileged users */
+ .dumpit = smc_nl_dump_auto_fallback,
+ },
+ {
+ .cmd = SMC_NETLINK_ENABLE_AUTO_FALLBACK,
+ .flags = GENL_ADMIN_PERM,
+ .doit = smc_nl_enable_auto_fallback,
+ },
+ {
+ .cmd = SMC_NETLINK_DISABLE_AUTO_FALLBACK,
+ .flags = GENL_ADMIN_PERM,
+ .doit = smc_nl_disable_auto_fallback,
+ },
};
static const struct nla_policy smc_gen_nl_policy[2] = {
@@ -868,6 +868,9 @@ int smc_pnet_net_init(struct net *net)
smc_pnet_create_pnetids_list(net);
+ /* disable auto fallback by default */
+ net->smc.auto_fallback = 0;
+
return 0;
}