linux/net/smc/smc_diag.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Shared Memory Communications over RDMA (SMC-R) and RoCE
   4 *
   5 * Monitoring SMC transport protocol sockets
   6 *
   7 * Copyright IBM Corp. 2016
   8 *
   9 * Author(s):  Ursula Braun <ubraun@linux.vnet.ibm.com>
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14#include <linux/types.h>
  15#include <linux/init.h>
  16#include <linux/sock_diag.h>
  17#include <linux/inet_diag.h>
  18#include <linux/smc_diag.h>
  19#include <net/netlink.h>
  20#include <net/smc.h>
  21
  22#include "smc.h"
  23#include "smc_core.h"
  24
  25static void smc_gid_be16_convert(__u8 *buf, u8 *gid_raw)
  26{
  27        sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
  28                be16_to_cpu(((__be16 *)gid_raw)[0]),
  29                be16_to_cpu(((__be16 *)gid_raw)[1]),
  30                be16_to_cpu(((__be16 *)gid_raw)[2]),
  31                be16_to_cpu(((__be16 *)gid_raw)[3]),
  32                be16_to_cpu(((__be16 *)gid_raw)[4]),
  33                be16_to_cpu(((__be16 *)gid_raw)[5]),
  34                be16_to_cpu(((__be16 *)gid_raw)[6]),
  35                be16_to_cpu(((__be16 *)gid_raw)[7]));
  36}
  37
  38static void smc_diag_msg_common_fill(struct smc_diag_msg *r, struct sock *sk)
  39{
  40        struct smc_sock *smc = smc_sk(sk);
  41
  42        r->diag_family = sk->sk_family;
  43        if (!smc->clcsock)
  44                return;
  45        r->id.idiag_sport = htons(smc->clcsock->sk->sk_num);
  46        r->id.idiag_dport = smc->clcsock->sk->sk_dport;
  47        r->id.idiag_if = smc->clcsock->sk->sk_bound_dev_if;
  48        sock_diag_save_cookie(sk, r->id.idiag_cookie);
  49        if (sk->sk_protocol == SMCPROTO_SMC) {
  50                memset(&r->id.idiag_src, 0, sizeof(r->id.idiag_src));
  51                memset(&r->id.idiag_dst, 0, sizeof(r->id.idiag_dst));
  52                r->id.idiag_src[0] = smc->clcsock->sk->sk_rcv_saddr;
  53                r->id.idiag_dst[0] = smc->clcsock->sk->sk_daddr;
  54#if IS_ENABLED(CONFIG_IPV6)
  55        } else if (sk->sk_protocol == SMCPROTO_SMC6) {
  56                memcpy(&r->id.idiag_src, &smc->clcsock->sk->sk_v6_rcv_saddr,
  57                       sizeof(smc->clcsock->sk->sk_v6_rcv_saddr));
  58                memcpy(&r->id.idiag_dst, &smc->clcsock->sk->sk_v6_daddr,
  59                       sizeof(smc->clcsock->sk->sk_v6_daddr));
  60#endif
  61        }
  62}
  63
  64static int smc_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb,
  65                                   struct smc_diag_msg *r,
  66                                   struct user_namespace *user_ns)
  67{
  68        if (nla_put_u8(skb, SMC_DIAG_SHUTDOWN, sk->sk_shutdown))
  69                return 1;
  70
  71        r->diag_uid = from_kuid_munged(user_ns, sock_i_uid(sk));
  72        r->diag_inode = sock_i_ino(sk);
  73        return 0;
  74}
  75
  76static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb,
  77                           struct netlink_callback *cb,
  78                           const struct smc_diag_req *req,
  79                           struct nlattr *bc)
  80{
  81        struct smc_sock *smc = smc_sk(sk);
  82        struct smc_diag_fallback fallback;
  83        struct user_namespace *user_ns;
  84        struct smc_diag_msg *r;
  85        struct nlmsghdr *nlh;
  86
  87        nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
  88                        cb->nlh->nlmsg_type, sizeof(*r), NLM_F_MULTI);
  89        if (!nlh)
  90                return -EMSGSIZE;
  91
  92        r = nlmsg_data(nlh);
  93        smc_diag_msg_common_fill(r, sk);
  94        r->diag_state = sk->sk_state;
  95        if (smc->use_fallback)
  96                r->diag_mode = SMC_DIAG_MODE_FALLBACK_TCP;
  97        else if (smc->conn.lgr && smc->conn.lgr->is_smcd)
  98                r->diag_mode = SMC_DIAG_MODE_SMCD;
  99        else
 100                r->diag_mode = SMC_DIAG_MODE_SMCR;
 101        user_ns = sk_user_ns(NETLINK_CB(cb->skb).sk);
 102        if (smc_diag_msg_attrs_fill(sk, skb, r, user_ns))
 103                goto errout;
 104
 105        fallback.reason = smc->fallback_rsn;
 106        fallback.peer_diagnosis = smc->peer_diagnosis;
 107        if (nla_put(skb, SMC_DIAG_FALLBACK, sizeof(fallback), &fallback) < 0)
 108                goto errout;
 109
 110        if ((req->diag_ext & (1 << (SMC_DIAG_CONNINFO - 1))) &&
 111            smc->conn.alert_token_local) {
 112                struct smc_connection *conn = &smc->conn;
 113                struct smc_diag_conninfo cinfo = {
 114                        .token = conn->alert_token_local,
 115                        .sndbuf_size = conn->sndbuf_desc ?
 116                                conn->sndbuf_desc->len : 0,
 117                        .rmbe_size = conn->rmb_desc ? conn->rmb_desc->len : 0,
 118                        .peer_rmbe_size = conn->peer_rmbe_size,
 119
 120                        .rx_prod.wrap = conn->local_rx_ctrl.prod.wrap,
 121                        .rx_prod.count = conn->local_rx_ctrl.prod.count,
 122                        .rx_cons.wrap = conn->local_rx_ctrl.cons.wrap,
 123                        .rx_cons.count = conn->local_rx_ctrl.cons.count,
 124
 125                        .tx_prod.wrap = conn->local_tx_ctrl.prod.wrap,
 126                        .tx_prod.count = conn->local_tx_ctrl.prod.count,
 127                        .tx_cons.wrap = conn->local_tx_ctrl.cons.wrap,
 128                        .tx_cons.count = conn->local_tx_ctrl.cons.count,
 129
 130                        .tx_prod_flags =
 131                                *(u8 *)&conn->local_tx_ctrl.prod_flags,
 132                        .tx_conn_state_flags =
 133                                *(u8 *)&conn->local_tx_ctrl.conn_state_flags,
 134                        .rx_prod_flags = *(u8 *)&conn->local_rx_ctrl.prod_flags,
 135                        .rx_conn_state_flags =
 136                                *(u8 *)&conn->local_rx_ctrl.conn_state_flags,
 137
 138                        .tx_prep.wrap = conn->tx_curs_prep.wrap,
 139                        .tx_prep.count = conn->tx_curs_prep.count,
 140                        .tx_sent.wrap = conn->tx_curs_sent.wrap,
 141                        .tx_sent.count = conn->tx_curs_sent.count,
 142                        .tx_fin.wrap = conn->tx_curs_fin.wrap,
 143                        .tx_fin.count = conn->tx_curs_fin.count,
 144                };
 145
 146                if (nla_put(skb, SMC_DIAG_CONNINFO, sizeof(cinfo), &cinfo) < 0)
 147                        goto errout;
 148        }
 149
 150        if (smc->conn.lgr && !smc->conn.lgr->is_smcd &&
 151            (req->diag_ext & (1 << (SMC_DIAG_LGRINFO - 1))) &&
 152            !list_empty(&smc->conn.lgr->list)) {
 153                struct smc_diag_lgrinfo linfo = {
 154                        .role = smc->conn.lgr->role,
 155                        .lnk[0].ibport = smc->conn.lgr->lnk[0].ibport,
 156                        .lnk[0].link_id = smc->conn.lgr->lnk[0].link_id,
 157                };
 158
 159                memcpy(linfo.lnk[0].ibname,
 160                       smc->conn.lgr->lnk[0].smcibdev->ibdev->name,
 161                       sizeof(smc->conn.lgr->lnk[0].smcibdev->ibdev->name));
 162                smc_gid_be16_convert(linfo.lnk[0].gid,
 163                                     smc->conn.lgr->lnk[0].gid);
 164                smc_gid_be16_convert(linfo.lnk[0].peer_gid,
 165                                     smc->conn.lgr->lnk[0].peer_gid);
 166
 167                if (nla_put(skb, SMC_DIAG_LGRINFO, sizeof(linfo), &linfo) < 0)
 168                        goto errout;
 169        }
 170        if (smc->conn.lgr && smc->conn.lgr->is_smcd &&
 171            (req->diag_ext & (1 << (SMC_DIAG_DMBINFO - 1))) &&
 172            !list_empty(&smc->conn.lgr->list)) {
 173                struct smc_connection *conn = &smc->conn;
 174                struct smcd_diag_dmbinfo dinfo = {
 175                        .linkid = *((u32 *)conn->lgr->id),
 176                        .peer_gid = conn->lgr->peer_gid,
 177                        .my_gid = conn->lgr->smcd->local_gid,
 178                        .token = conn->rmb_desc->token,
 179                        .peer_token = conn->peer_token
 180                };
 181
 182                if (nla_put(skb, SMC_DIAG_DMBINFO, sizeof(dinfo), &dinfo) < 0)
 183                        goto errout;
 184        }
 185
 186        nlmsg_end(skb, nlh);
 187        return 0;
 188
 189errout:
 190        nlmsg_cancel(skb, nlh);
 191        return -EMSGSIZE;
 192}
 193
 194static int smc_diag_dump_proto(struct proto *prot, struct sk_buff *skb,
 195                               struct netlink_callback *cb)
 196{
 197        struct net *net = sock_net(skb->sk);
 198        struct nlattr *bc = NULL;
 199        struct hlist_head *head;
 200        struct sock *sk;
 201        int rc = 0;
 202
 203        read_lock(&prot->h.smc_hash->lock);
 204        head = &prot->h.smc_hash->ht;
 205        if (hlist_empty(head))
 206                goto out;
 207
 208        sk_for_each(sk, head) {
 209                if (!net_eq(sock_net(sk), net))
 210                        continue;
 211                rc = __smc_diag_dump(sk, skb, cb, nlmsg_data(cb->nlh), bc);
 212                if (rc)
 213                        break;
 214        }
 215
 216out:
 217        read_unlock(&prot->h.smc_hash->lock);
 218        return rc;
 219}
 220
 221static int smc_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 222{
 223        int rc = 0;
 224
 225        rc = smc_diag_dump_proto(&smc_proto, skb, cb);
 226        if (!rc)
 227                rc = smc_diag_dump_proto(&smc_proto6, skb, cb);
 228        return rc;
 229}
 230
 231static int smc_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 232{
 233        struct net *net = sock_net(skb->sk);
 234
 235        if (h->nlmsg_type == SOCK_DIAG_BY_FAMILY &&
 236            h->nlmsg_flags & NLM_F_DUMP) {
 237                {
 238                        struct netlink_dump_control c = {
 239                                .dump = smc_diag_dump,
 240                                .min_dump_alloc = SKB_WITH_OVERHEAD(32768),
 241                        };
 242                        return netlink_dump_start(net->diag_nlsk, skb, h, &c);
 243                }
 244        }
 245        return 0;
 246}
 247
 248static const struct sock_diag_handler smc_diag_handler = {
 249        .family = AF_SMC,
 250        .dump = smc_diag_handler_dump,
 251};
 252
 253static int __init smc_diag_init(void)
 254{
 255        return sock_diag_register(&smc_diag_handler);
 256}
 257
 258static void __exit smc_diag_exit(void)
 259{
 260        sock_diag_unregister(&smc_diag_handler);
 261}
 262
 263module_init(smc_diag_init);
 264module_exit(smc_diag_exit);
 265MODULE_LICENSE("GPL");
 266MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 43 /* AF_SMC */);
 267