16dd844dbSPaolo Bonzini /* 26dd844dbSPaolo Bonzini * Serving QEMU block devices via NBD 36dd844dbSPaolo Bonzini * 46dd844dbSPaolo Bonzini * Copyright (c) 2012 Red Hat, Inc. 56dd844dbSPaolo Bonzini * 66dd844dbSPaolo Bonzini * Author: Paolo Bonzini <pbonzini@redhat.com> 76dd844dbSPaolo Bonzini * 86dd844dbSPaolo Bonzini * This work is licensed under the terms of the GNU GPL, version 2 or 96dd844dbSPaolo Bonzini * later. See the COPYING file in the top-level directory. 106dd844dbSPaolo Bonzini */ 116dd844dbSPaolo Bonzini 12d38ea87aSPeter Maydell #include "qemu/osdep.h" 139c17d615SPaolo Bonzini #include "sysemu/blockdev.h" 14e140177dSMax Reitz #include "sysemu/block-backend.h" 150d09e41aSPaolo Bonzini #include "hw/block/block.h" 16e688df6bSMarkus Armbruster #include "qapi/error.h" 178675cbd6SEric Blake #include "qapi/clone-visitor.h" 188675cbd6SEric Blake #include "qapi/qapi-visit-block-export.h" 195daa6bfdSKevin Wolf #include "qapi/qapi-commands-block-export.h" 20737e150eSPaolo Bonzini #include "block/nbd.h" 21ae398278SDaniel P. Berrange #include "io/channel-socket.h" 22862172f4SDaniel P. Berrange #include "io/net-listener.h" 236dd844dbSPaolo Bonzini 24ddffee39SDaniel P. Berrange typedef struct NBDServerData { 25862172f4SDaniel P. Berrange QIONetListener *listener; 26ddffee39SDaniel P. Berrange QCryptoTLSCreds *tlscreds; 2700019455SDaniel P. Berrange char *tlsauthz; 281c8222b0SKevin Wolf uint32_t max_connections; 291c8222b0SKevin Wolf uint32_t connections; 30ddffee39SDaniel P. Berrange } NBDServerData; 31ddffee39SDaniel P. Berrange 32ddffee39SDaniel P. Berrange static NBDServerData *nbd_server; 3300917172SKevin Wolf static bool is_qemu_nbd; 34ddffee39SDaniel P. Berrange 351c8222b0SKevin Wolf static void nbd_update_server_watch(NBDServerData *s); 361c8222b0SKevin Wolf 3700917172SKevin Wolf void nbd_server_is_qemu_nbd(bool value) 3800917172SKevin Wolf { 3900917172SKevin Wolf is_qemu_nbd = value; 4000917172SKevin Wolf } 4100917172SKevin Wolf 425b1cb497SKevin Wolf bool nbd_server_is_running(void) 435b1cb497SKevin Wolf { 445b1cb497SKevin Wolf return nbd_server || is_qemu_nbd; 455b1cb497SKevin Wolf } 465b1cb497SKevin Wolf 470c9390d9SEric Blake static void nbd_blockdev_client_closed(NBDClient *client, bool ignored) 480c9390d9SEric Blake { 490c9390d9SEric Blake nbd_client_put(client); 501c8222b0SKevin Wolf assert(nbd_server->connections > 0); 511c8222b0SKevin Wolf nbd_server->connections--; 521c8222b0SKevin Wolf nbd_update_server_watch(nbd_server); 530c9390d9SEric Blake } 546dd844dbSPaolo Bonzini 55862172f4SDaniel P. Berrange static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc, 56ae398278SDaniel P. Berrange gpointer opaque) 576dd844dbSPaolo Bonzini { 581c8222b0SKevin Wolf nbd_server->connections++; 591c8222b0SKevin Wolf nbd_update_server_watch(nbd_server); 601c8222b0SKevin Wolf 610d73f725SDaniel P. Berrange qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server"); 6200019455SDaniel P. Berrange nbd_client_new(cioc, nbd_server->tlscreds, nbd_server->tlsauthz, 630c9390d9SEric Blake nbd_blockdev_client_closed); 646dd844dbSPaolo Bonzini } 656dd844dbSPaolo Bonzini 661c8222b0SKevin Wolf static void nbd_update_server_watch(NBDServerData *s) 671c8222b0SKevin Wolf { 681c8222b0SKevin Wolf if (!s->max_connections || s->connections < s->max_connections) { 691c8222b0SKevin Wolf qio_net_listener_set_client_func(s->listener, nbd_accept, NULL, NULL); 701c8222b0SKevin Wolf } else { 711c8222b0SKevin Wolf qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL); 721c8222b0SKevin Wolf } 731c8222b0SKevin Wolf } 74ddffee39SDaniel P. Berrange 75ddffee39SDaniel P. Berrange static void nbd_server_free(NBDServerData *server) 766dd844dbSPaolo Bonzini { 77ddffee39SDaniel P. Berrange if (!server) { 78ddffee39SDaniel P. Berrange return; 79ddffee39SDaniel P. Berrange } 80ddffee39SDaniel P. Berrange 81862172f4SDaniel P. Berrange qio_net_listener_disconnect(server->listener); 82862172f4SDaniel P. Berrange object_unref(OBJECT(server->listener)); 83ddffee39SDaniel P. Berrange if (server->tlscreds) { 84ddffee39SDaniel P. Berrange object_unref(OBJECT(server->tlscreds)); 85ddffee39SDaniel P. Berrange } 8600019455SDaniel P. Berrange g_free(server->tlsauthz); 87ddffee39SDaniel P. Berrange 88ddffee39SDaniel P. Berrange g_free(server); 89ddffee39SDaniel P. Berrange } 90ddffee39SDaniel P. Berrange 91ddffee39SDaniel P. Berrange static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp) 92ddffee39SDaniel P. Berrange { 93ddffee39SDaniel P. Berrange Object *obj; 94ddffee39SDaniel P. Berrange QCryptoTLSCreds *creds; 95ddffee39SDaniel P. Berrange 96ddffee39SDaniel P. Berrange obj = object_resolve_path_component( 97ddffee39SDaniel P. Berrange object_get_objects_root(), id); 98ddffee39SDaniel P. Berrange if (!obj) { 99ddffee39SDaniel P. Berrange error_setg(errp, "No TLS credentials with id '%s'", 100ddffee39SDaniel P. Berrange id); 101ddffee39SDaniel P. Berrange return NULL; 102ddffee39SDaniel P. Berrange } 103ddffee39SDaniel P. Berrange creds = (QCryptoTLSCreds *) 104ddffee39SDaniel P. Berrange object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS); 105ddffee39SDaniel P. Berrange if (!creds) { 106ddffee39SDaniel P. Berrange error_setg(errp, "Object with id '%s' is not TLS credentials", 107ddffee39SDaniel P. Berrange id); 108ddffee39SDaniel P. Berrange return NULL; 109ddffee39SDaniel P. Berrange } 110ddffee39SDaniel P. Berrange 111*7b3b6168SPhilippe Mathieu-Daudé if (!qcrypto_tls_creds_check_endpoint(creds, 112*7b3b6168SPhilippe Mathieu-Daudé QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, 113*7b3b6168SPhilippe Mathieu-Daudé errp)) { 114ddffee39SDaniel P. Berrange return NULL; 115ddffee39SDaniel P. Berrange } 116ddffee39SDaniel P. Berrange object_ref(obj); 117ddffee39SDaniel P. Berrange return creds; 118ddffee39SDaniel P. Berrange } 119ddffee39SDaniel P. Berrange 120ddffee39SDaniel P. Berrange 121bd269ebcSMarkus Armbruster void nbd_server_start(SocketAddress *addr, const char *tls_creds, 1221c8222b0SKevin Wolf const char *tls_authz, uint32_t max_connections, 1231c8222b0SKevin Wolf Error **errp) 124ddffee39SDaniel P. Berrange { 125ddffee39SDaniel P. Berrange if (nbd_server) { 1266dd844dbSPaolo Bonzini error_setg(errp, "NBD server already running"); 1276dd844dbSPaolo Bonzini return; 1286dd844dbSPaolo Bonzini } 1296dd844dbSPaolo Bonzini 130ddffee39SDaniel P. Berrange nbd_server = g_new0(NBDServerData, 1); 1311c8222b0SKevin Wolf nbd_server->max_connections = max_connections; 132862172f4SDaniel P. Berrange nbd_server->listener = qio_net_listener_new(); 133862172f4SDaniel P. Berrange 134862172f4SDaniel P. Berrange qio_net_listener_set_name(nbd_server->listener, 1350d73f725SDaniel P. Berrange "nbd-listener"); 136862172f4SDaniel P. Berrange 137582d4210SEric Blake /* 138582d4210SEric Blake * Because this server is persistent, a backlog of SOMAXCONN is 139582d4210SEric Blake * better than trying to size it to max_connections. 140582d4210SEric Blake */ 141582d4210SEric Blake if (qio_net_listener_open_sync(nbd_server->listener, addr, SOMAXCONN, 142582d4210SEric Blake errp) < 0) { 143ddffee39SDaniel P. Berrange goto error; 1446dd844dbSPaolo Bonzini } 145ae398278SDaniel P. Berrange 146bd269ebcSMarkus Armbruster if (tls_creds) { 147ddffee39SDaniel P. Berrange nbd_server->tlscreds = nbd_get_tls_creds(tls_creds, errp); 148ddffee39SDaniel P. Berrange if (!nbd_server->tlscreds) { 149ddffee39SDaniel P. Berrange goto error; 150ddffee39SDaniel P. Berrange } 151ddffee39SDaniel P. Berrange 152bd269ebcSMarkus Armbruster /* TODO SOCKET_ADDRESS_TYPE_FD where fd has AF_INET or AF_INET6 */ 153bd269ebcSMarkus Armbruster if (addr->type != SOCKET_ADDRESS_TYPE_INET) { 154ddffee39SDaniel P. Berrange error_setg(errp, "TLS is only supported with IPv4/IPv6"); 155ddffee39SDaniel P. Berrange goto error; 156ddffee39SDaniel P. Berrange } 157ddffee39SDaniel P. Berrange } 158ddffee39SDaniel P. Berrange 15900019455SDaniel P. Berrange nbd_server->tlsauthz = g_strdup(tls_authz); 16000019455SDaniel P. Berrange 1611c8222b0SKevin Wolf nbd_update_server_watch(nbd_server); 162ddffee39SDaniel P. Berrange 163ddffee39SDaniel P. Berrange return; 164ddffee39SDaniel P. Berrange 165ddffee39SDaniel P. Berrange error: 166ddffee39SDaniel P. Berrange nbd_server_free(nbd_server); 167ddffee39SDaniel P. Berrange nbd_server = NULL; 1686dd844dbSPaolo Bonzini } 1696dd844dbSPaolo Bonzini 170eed8b691SKevin Wolf void nbd_server_start_options(NbdServerOptions *arg, Error **errp) 171eed8b691SKevin Wolf { 1721c8222b0SKevin Wolf nbd_server_start(arg->addr, arg->tls_creds, arg->tls_authz, 1731c8222b0SKevin Wolf arg->max_connections, errp); 174eed8b691SKevin Wolf } 175eed8b691SKevin Wolf 176bd269ebcSMarkus Armbruster void qmp_nbd_server_start(SocketAddressLegacy *addr, 177bd269ebcSMarkus Armbruster bool has_tls_creds, const char *tls_creds, 17800019455SDaniel P. Berrange bool has_tls_authz, const char *tls_authz, 1791c8222b0SKevin Wolf bool has_max_connections, uint32_t max_connections, 180bd269ebcSMarkus Armbruster Error **errp) 181bd269ebcSMarkus Armbruster { 182bd269ebcSMarkus Armbruster SocketAddress *addr_flat = socket_address_flatten(addr); 183bd269ebcSMarkus Armbruster 1841c8222b0SKevin Wolf nbd_server_start(addr_flat, tls_creds, tls_authz, max_connections, errp); 185bd269ebcSMarkus Armbruster qapi_free_SocketAddress(addr_flat); 186bd269ebcSMarkus Armbruster } 187bd269ebcSMarkus Armbruster 188b6076afcSKevin Wolf void qmp_nbd_server_add(NbdServerAddOptions *arg, Error **errp) 18956ee8626SKevin Wolf { 1909b562c64SKevin Wolf BlockExport *export; 1919b562c64SKevin Wolf BlockDriverState *bs; 1929b562c64SKevin Wolf BlockBackend *on_eject_blk; 193b6076afcSKevin Wolf BlockExportOptions *export_opts; 1949b562c64SKevin Wolf 1959b562c64SKevin Wolf bs = bdrv_lookup_bs(arg->device, arg->device, errp); 1969b562c64SKevin Wolf if (!bs) { 1979b562c64SKevin Wolf return; 1989b562c64SKevin Wolf } 1999b562c64SKevin Wolf 200b6076afcSKevin Wolf /* 201b6076afcSKevin Wolf * block-export-add would default to the node-name, but we may have to use 202b6076afcSKevin Wolf * the device name as a default here for compatibility. 203b6076afcSKevin Wolf */ 204b6076afcSKevin Wolf if (!arg->has_name) { 2058675cbd6SEric Blake arg->has_name = true; 2068675cbd6SEric Blake arg->name = g_strdup(arg->device); 207b6076afcSKevin Wolf } 208b6076afcSKevin Wolf 209b6076afcSKevin Wolf export_opts = g_new(BlockExportOptions, 1); 210b6076afcSKevin Wolf *export_opts = (BlockExportOptions) { 21156ee8626SKevin Wolf .type = BLOCK_EXPORT_TYPE_NBD, 212d53be9ceSKevin Wolf .id = g_strdup(arg->name), 213b6076afcSKevin Wolf .node_name = g_strdup(bdrv_get_node_name(bs)), 21430dbc81dSKevin Wolf .has_writable = arg->has_writable, 21530dbc81dSKevin Wolf .writable = arg->writable, 21656ee8626SKevin Wolf }; 217cbad81ceSEric Blake QAPI_CLONE_MEMBERS(BlockExportOptionsNbdBase, &export_opts->u.nbd, 2188675cbd6SEric Blake qapi_NbdServerAddOptions_base(arg)); 219cbad81ceSEric Blake if (arg->has_bitmap) { 220cbad81ceSEric Blake export_opts->u.nbd.has_bitmaps = true; 221cbad81ceSEric Blake QAPI_LIST_PREPEND(export_opts->u.nbd.bitmaps, g_strdup(arg->bitmap)); 222cbad81ceSEric Blake } 2239b562c64SKevin Wolf 2249b562c64SKevin Wolf /* 2259b562c64SKevin Wolf * nbd-server-add doesn't complain when a read-only device should be 2269b562c64SKevin Wolf * exported as writable, but simply downgrades it. This is an error with 2279b562c64SKevin Wolf * block-export-add. 2289b562c64SKevin Wolf */ 2299b562c64SKevin Wolf if (bdrv_is_read_only(bs)) { 23030dbc81dSKevin Wolf export_opts->has_writable = true; 23130dbc81dSKevin Wolf export_opts->writable = false; 2329b562c64SKevin Wolf } 2339b562c64SKevin Wolf 234b6076afcSKevin Wolf export = blk_exp_add(export_opts, errp); 2359b562c64SKevin Wolf if (!export) { 236b6076afcSKevin Wolf goto fail; 2379b562c64SKevin Wolf } 2389b562c64SKevin Wolf 2399b562c64SKevin Wolf /* 2409b562c64SKevin Wolf * nbd-server-add removes the export when the named BlockBackend used for 2419b562c64SKevin Wolf * @device goes away. 2429b562c64SKevin Wolf */ 2439b562c64SKevin Wolf on_eject_blk = blk_by_name(arg->device); 2449b562c64SKevin Wolf if (on_eject_blk) { 2459b562c64SKevin Wolf nbd_export_set_on_eject_blk(export, on_eject_blk); 2469b562c64SKevin Wolf } 247b6076afcSKevin Wolf 248b6076afcSKevin Wolf fail: 249b6076afcSKevin Wolf qapi_free_BlockExportOptions(export_opts); 2506dd844dbSPaolo Bonzini } 2516dd844dbSPaolo Bonzini 252a3b0dc75SVladimir Sementsov-Ogievskiy void qmp_nbd_server_remove(const char *name, 2533c3bc462SKevin Wolf bool has_mode, BlockExportRemoveMode mode, 254a3b0dc75SVladimir Sementsov-Ogievskiy Error **errp) 255a3b0dc75SVladimir Sementsov-Ogievskiy { 2563c3bc462SKevin Wolf BlockExport *exp; 257a3b0dc75SVladimir Sementsov-Ogievskiy 2583c3bc462SKevin Wolf exp = blk_exp_find(name); 2593c3bc462SKevin Wolf if (exp && exp->drv->type != BLOCK_EXPORT_TYPE_NBD) { 2603c3bc462SKevin Wolf error_setg(errp, "Block export '%s' is not an NBD export", name); 261a3b0dc75SVladimir Sementsov-Ogievskiy return; 262a3b0dc75SVladimir Sementsov-Ogievskiy } 263a3b0dc75SVladimir Sementsov-Ogievskiy 2643c3bc462SKevin Wolf qmp_block_export_del(name, has_mode, mode, errp); 265a3b0dc75SVladimir Sementsov-Ogievskiy } 266a3b0dc75SVladimir Sementsov-Ogievskiy 2676dd844dbSPaolo Bonzini void qmp_nbd_server_stop(Error **errp) 2686dd844dbSPaolo Bonzini { 2697801c3a7SEric Blake if (!nbd_server) { 2707801c3a7SEric Blake error_setg(errp, "NBD server not running"); 2717801c3a7SEric Blake return; 2727801c3a7SEric Blake } 2737801c3a7SEric Blake 274bc4ee65bSKevin Wolf blk_exp_close_all_type(BLOCK_EXPORT_TYPE_NBD); 2756dd844dbSPaolo Bonzini 276ddffee39SDaniel P. Berrange nbd_server_free(nbd_server); 277ddffee39SDaniel P. Berrange nbd_server = NULL; 278fc6467eaSPaolo Bonzini } 279