mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 19:41:16 +00:00
util: move IP route & address object-related functions to virnetdevip.c
These functions all need to be called from a utility function that must be located in the util directory, so we move them all into util/virnetdevip.[ch] now that it exists. Function and struct names were appropriately changed for the new location, but all code is unchanged aside from motion and renaming.
This commit is contained in:
parent
cf0568b0af
commit
fa18e814ba
@ -1804,7 +1804,7 @@ virDomainNetDefClear(virDomainNetDefPtr def)
|
|||||||
VIR_FREE(def->ips);
|
VIR_FREE(def->ips);
|
||||||
|
|
||||||
for (i = 0; i < def->nroutes; i++)
|
for (i = 0; i < def->nroutes; i++)
|
||||||
virNetworkRouteDefFree(def->routes[i]);
|
virNetDevIPRouteFree(def->routes[i]);
|
||||||
VIR_FREE(def->routes);
|
VIR_FREE(def->routes);
|
||||||
|
|
||||||
virDomainDeviceInfoClear(&def->info);
|
virDomainDeviceInfoClear(&def->info);
|
||||||
@ -2212,7 +2212,7 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
|
|||||||
VIR_FREE(def->source.caps.u.net.ips[i]);
|
VIR_FREE(def->source.caps.u.net.ips[i]);
|
||||||
VIR_FREE(def->source.caps.u.net.ips);
|
VIR_FREE(def->source.caps.u.net.ips);
|
||||||
for (i = 0; i < def->source.caps.u.net.nroutes; i++)
|
for (i = 0; i < def->source.caps.u.net.nroutes; i++)
|
||||||
virNetworkRouteDefFree(def->source.caps.u.net.routes[i]);
|
virNetDevIPRouteFree(def->source.caps.u.net.routes[i]);
|
||||||
VIR_FREE(def->source.caps.u.net.routes);
|
VIR_FREE(def->source.caps.u.net.routes);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -6128,11 +6128,11 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static virDomainNetIPDefPtr
|
static virNetDevIPAddrPtr
|
||||||
virDomainNetIPParseXML(xmlNodePtr node)
|
virDomainNetIPParseXML(xmlNodePtr node)
|
||||||
{
|
{
|
||||||
/* Parse the prefix in every case */
|
/* Parse the prefix in every case */
|
||||||
virDomainNetIPDefPtr ip = NULL, ret = NULL;
|
virNetDevIPAddrPtr ip = NULL, ret = NULL;
|
||||||
char *prefixStr = NULL;
|
char *prefixStr = NULL;
|
||||||
unsigned int prefixValue = 0;
|
unsigned int prefixValue = 0;
|
||||||
char *familyStr = NULL;
|
char *familyStr = NULL;
|
||||||
@ -6259,7 +6259,7 @@ virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
|
|||||||
if (nipnodes) {
|
if (nipnodes) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < nipnodes; i++) {
|
for (i = 0; i < nipnodes; i++) {
|
||||||
virDomainNetIPDefPtr ip = virDomainNetIPParseXML(ipnodes[i]);
|
virNetDevIPAddrPtr ip = virDomainNetIPParseXML(ipnodes[i]);
|
||||||
|
|
||||||
if (!ip)
|
if (!ip)
|
||||||
goto error;
|
goto error;
|
||||||
@ -6279,17 +6279,17 @@ virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
|
|||||||
if (nroutenodes) {
|
if (nroutenodes) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < nroutenodes; i++) {
|
for (i = 0; i < nroutenodes; i++) {
|
||||||
virNetworkRouteDefPtr route = NULL;
|
virNetDevIPRoutePtr route = NULL;
|
||||||
|
|
||||||
if (!(route = virNetworkRouteDefParseXML(_("Domain hostdev device"),
|
if (!(route = virNetDevIPRouteParseXML(_("Domain hostdev device"),
|
||||||
routenodes[i],
|
routenodes[i],
|
||||||
ctxt)))
|
ctxt)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
|
||||||
if (VIR_APPEND_ELEMENT(def->source.caps.u.net.routes,
|
if (VIR_APPEND_ELEMENT(def->source.caps.u.net.routes,
|
||||||
def->source.caps.u.net.nroutes, route) < 0) {
|
def->source.caps.u.net.nroutes, route) < 0) {
|
||||||
virNetworkRouteDefFree(route);
|
virNetDevIPRouteFree(route);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8896,7 +8896,7 @@ virDomainNetAppendIPAddress(virDomainNetDefPtr def,
|
|||||||
int family,
|
int family,
|
||||||
unsigned int prefix)
|
unsigned int prefix)
|
||||||
{
|
{
|
||||||
virDomainNetIPDefPtr ipDef = NULL;
|
virNetDevIPAddrPtr ipDef = NULL;
|
||||||
if (VIR_ALLOC(ipDef) < 0)
|
if (VIR_ALLOC(ipDef) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -8968,9 +8968,9 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
|
|||||||
int ret, val;
|
int ret, val;
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t nips = 0;
|
size_t nips = 0;
|
||||||
virDomainNetIPDefPtr *ips = NULL;
|
virNetDevIPAddrPtr *ips = NULL;
|
||||||
size_t nroutes = 0;
|
size_t nroutes = 0;
|
||||||
virNetworkRouteDefPtr *routes = NULL;
|
virNetDevIPRoutePtr *routes = NULL;
|
||||||
|
|
||||||
if (VIR_ALLOC(def) < 0)
|
if (VIR_ALLOC(def) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -9087,7 +9087,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
|
|||||||
ctxt->node = tmpnode;
|
ctxt->node = tmpnode;
|
||||||
}
|
}
|
||||||
} else if (xmlStrEqual(cur->name, BAD_CAST "ip")) {
|
} else if (xmlStrEqual(cur->name, BAD_CAST "ip")) {
|
||||||
virDomainNetIPDefPtr ip = NULL;
|
virNetDevIPAddrPtr ip = NULL;
|
||||||
|
|
||||||
if (!(ip = virDomainNetIPParseXML(cur)))
|
if (!(ip = virDomainNetIPParseXML(cur)))
|
||||||
goto error;
|
goto error;
|
||||||
@ -9095,13 +9095,13 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
|
|||||||
if (VIR_APPEND_ELEMENT(ips, nips, ip) < 0)
|
if (VIR_APPEND_ELEMENT(ips, nips, ip) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
} else if (xmlStrEqual(cur->name, BAD_CAST "route")) {
|
} else if (xmlStrEqual(cur->name, BAD_CAST "route")) {
|
||||||
virNetworkRouteDefPtr route = NULL;
|
virNetDevIPRoutePtr route = NULL;
|
||||||
if (!(route = virNetworkRouteDefParseXML(_("Domain interface"),
|
if (!(route = virNetDevIPRouteParseXML(_("Domain interface"),
|
||||||
cur, ctxt)))
|
cur, ctxt)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (VIR_APPEND_ELEMENT(routes, nroutes, route) < 0) {
|
if (VIR_APPEND_ELEMENT(routes, nroutes, route) < 0) {
|
||||||
virNetworkRouteDefFree(route);
|
virNetDevIPRouteFree(route);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else if (!ifname &&
|
} else if (!ifname &&
|
||||||
@ -20281,7 +20281,7 @@ virDomainFSDefFormat(virBufferPtr buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
virDomainNetIPsFormat(virBufferPtr buf, virDomainNetIPDefPtr *ips, size_t nips)
|
virDomainNetIPsFormat(virBufferPtr buf, virNetDevIPAddrPtr *ips, size_t nips)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
@ -20311,13 +20311,13 @@ virDomainNetIPsFormat(virBufferPtr buf, virDomainNetIPDefPtr *ips, size_t nips)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
virDomainNetRoutesFormat(virBufferPtr buf,
|
virDomainNetRoutesFormat(virBufferPtr buf,
|
||||||
virNetworkRouteDefPtr *routes,
|
virNetDevIPRoutePtr *routes,
|
||||||
size_t nroutes)
|
size_t nroutes)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < nroutes; i++)
|
for (i = 0; i < nroutes; i++)
|
||||||
if (virNetworkRouteDefFormat(buf, routes[i]) < 0)
|
if (virNetDevIPRouteFormat(buf, routes[i]) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
# include "numa_conf.h"
|
# include "numa_conf.h"
|
||||||
# include "virnetdevmacvlan.h"
|
# include "virnetdevmacvlan.h"
|
||||||
# include "virsysinfo.h"
|
# include "virsysinfo.h"
|
||||||
|
# include "virnetdevip.h"
|
||||||
# include "virnetdevvportprofile.h"
|
# include "virnetdevvportprofile.h"
|
||||||
# include "virnetdevbandwidth.h"
|
# include "virnetdevbandwidth.h"
|
||||||
# include "virnetdevvlan.h"
|
# include "virnetdevvlan.h"
|
||||||
@ -382,13 +383,6 @@ typedef enum {
|
|||||||
VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST
|
VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST
|
||||||
} virDomainHostdevCapsType;
|
} virDomainHostdevCapsType;
|
||||||
|
|
||||||
typedef struct _virDomainNetIPDef virDomainNetIPDef;
|
|
||||||
typedef virDomainNetIPDef *virDomainNetIPDefPtr;
|
|
||||||
struct _virDomainNetIPDef {
|
|
||||||
virSocketAddr address; /* ipv4 or ipv6 address */
|
|
||||||
unsigned int prefix; /* number of 1 bits in the net mask */
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _virDomainHostdevCaps virDomainHostdevCaps;
|
typedef struct _virDomainHostdevCaps virDomainHostdevCaps;
|
||||||
typedef virDomainHostdevCaps *virDomainHostdevCapsPtr;
|
typedef virDomainHostdevCaps *virDomainHostdevCapsPtr;
|
||||||
struct _virDomainHostdevCaps {
|
struct _virDomainHostdevCaps {
|
||||||
@ -403,9 +397,9 @@ struct _virDomainHostdevCaps {
|
|||||||
struct {
|
struct {
|
||||||
char *iface;
|
char *iface;
|
||||||
size_t nips;
|
size_t nips;
|
||||||
virDomainNetIPDefPtr *ips;
|
virNetDevIPAddrPtr *ips;
|
||||||
size_t nroutes;
|
size_t nroutes;
|
||||||
virNetworkRouteDefPtr *routes;
|
virNetDevIPRoutePtr *routes;
|
||||||
} net;
|
} net;
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
@ -983,9 +977,9 @@ struct _virDomainNetDef {
|
|||||||
int trustGuestRxFilters; /* enum virTristateBool */
|
int trustGuestRxFilters; /* enum virTristateBool */
|
||||||
int linkstate;
|
int linkstate;
|
||||||
size_t nips;
|
size_t nips;
|
||||||
virDomainNetIPDefPtr *ips;
|
virNetDevIPAddrPtr *ips;
|
||||||
size_t nroutes;
|
size_t nroutes;
|
||||||
virNetworkRouteDefPtr *routes;
|
virNetDevIPRoutePtr *routes;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Used for prefix of ifname of any network name generated dynamically
|
/* Used for prefix of ifname of any network name generated dynamically
|
||||||
|
@ -406,7 +406,7 @@ virNetworkDefFree(virNetworkDefPtr def)
|
|||||||
VIR_FREE(def->ips);
|
VIR_FREE(def->ips);
|
||||||
|
|
||||||
for (i = 0; i < def->nroutes && def->routes; i++)
|
for (i = 0; i < def->nroutes && def->routes; i++)
|
||||||
virNetworkRouteDefFree(def->routes[i]);
|
virNetDevIPRouteFree(def->routes[i]);
|
||||||
VIR_FREE(def->routes);
|
VIR_FREE(def->routes);
|
||||||
|
|
||||||
for (i = 0; i < def->nPortGroups && def->portGroups; i++)
|
for (i = 0; i < def->nPortGroups && def->portGroups; i++)
|
||||||
@ -804,7 +804,7 @@ virNetworkDefGetIPByIndex(const virNetworkDef *def,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* return routes[index], or NULL if there aren't enough routes */
|
/* return routes[index], or NULL if there aren't enough routes */
|
||||||
virNetworkRouteDefPtr
|
virNetDevIPRoutePtr
|
||||||
virNetworkDefGetRouteByIndex(const virNetworkDef *def,
|
virNetworkDefGetRouteByIndex(const virNetworkDef *def,
|
||||||
int family, size_t n)
|
int family, size_t n)
|
||||||
{
|
{
|
||||||
@ -818,7 +818,7 @@ virNetworkDefGetRouteByIndex(const virNetworkDef *def,
|
|||||||
|
|
||||||
/* find the nth route of type "family" */
|
/* find the nth route of type "family" */
|
||||||
for (i = 0; i < def->nroutes; i++) {
|
for (i = 0; i < def->nroutes; i++) {
|
||||||
virSocketAddrPtr addr = virNetworkRouteDefGetAddress(def->routes[i]);
|
virSocketAddrPtr addr = virNetDevIPRouteGetAddress(def->routes[i]);
|
||||||
if (VIR_SOCKET_ADDR_IS_FAMILY(addr, family)
|
if (VIR_SOCKET_ADDR_IS_FAMILY(addr, family)
|
||||||
&& (n-- <= 0)) {
|
&& (n-- <= 0)) {
|
||||||
return def->routes[i];
|
return def->routes[i];
|
||||||
@ -2261,11 +2261,11 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
|
|||||||
goto error;
|
goto error;
|
||||||
/* parse each definition */
|
/* parse each definition */
|
||||||
for (i = 0; i < nRoutes; i++) {
|
for (i = 0; i < nRoutes; i++) {
|
||||||
virNetworkRouteDefPtr route = NULL;
|
virNetDevIPRoutePtr route = NULL;
|
||||||
|
|
||||||
if (!(route = virNetworkRouteDefParseXML(def->name,
|
if (!(route = virNetDevIPRouteParseXML(def->name,
|
||||||
routeNodes[i],
|
routeNodes[i],
|
||||||
ctxt)))
|
ctxt)))
|
||||||
goto error;
|
goto error;
|
||||||
def->routes[i] = route;
|
def->routes[i] = route;
|
||||||
def->nroutes++;
|
def->nroutes++;
|
||||||
@ -2283,8 +2283,8 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
|
|||||||
size_t j;
|
size_t j;
|
||||||
virSocketAddr testAddr, testGw;
|
virSocketAddr testAddr, testGw;
|
||||||
bool addrMatch;
|
bool addrMatch;
|
||||||
virNetworkRouteDefPtr gwdef = def->routes[i];
|
virNetDevIPRoutePtr gwdef = def->routes[i];
|
||||||
virSocketAddrPtr gateway = virNetworkRouteDefGetGateway(gwdef);
|
virSocketAddrPtr gateway = virNetDevIPRouteGetGateway(gwdef);
|
||||||
addrMatch = false;
|
addrMatch = false;
|
||||||
for (j = 0; j < nips; j++) {
|
for (j = 0; j < nips; j++) {
|
||||||
virNetworkIPDefPtr def2 = &def->ips[j];
|
virNetworkIPDefPtr def2 = &def->ips[j];
|
||||||
@ -2876,7 +2876,7 @@ virNetworkDefFormatBuf(virBufferPtr buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < def->nroutes; i++) {
|
for (i = 0; i < def->nroutes; i++) {
|
||||||
if (virNetworkRouteDefFormat(buf, def->routes[i]) < 0)
|
if (virNetDevIPRouteFormat(buf, def->routes[i]) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,7 +243,7 @@ struct _virNetworkDef {
|
|||||||
virNetworkIPDefPtr ips; /* ptr to array of IP addresses on this network */
|
virNetworkIPDefPtr ips; /* ptr to array of IP addresses on this network */
|
||||||
|
|
||||||
size_t nroutes;
|
size_t nroutes;
|
||||||
virNetworkRouteDefPtr *routes; /* ptr to array of static routes on this interface */
|
virNetDevIPRoutePtr *routes; /* ptr to array of static routes on this interface */
|
||||||
|
|
||||||
virNetworkDNSDef dns; /* dns related configuration */
|
virNetworkDNSDef dns; /* dns related configuration */
|
||||||
virNetDevVPortProfilePtr virtPortProfile;
|
virNetDevVPortProfilePtr virtPortProfile;
|
||||||
@ -354,7 +354,7 @@ virPortGroupDefPtr virPortGroupFindByName(virNetworkDefPtr net,
|
|||||||
virNetworkIPDefPtr
|
virNetworkIPDefPtr
|
||||||
virNetworkDefGetIPByIndex(const virNetworkDef *def,
|
virNetworkDefGetIPByIndex(const virNetworkDef *def,
|
||||||
int family, size_t n);
|
int family, size_t n);
|
||||||
virNetworkRouteDefPtr
|
virNetDevIPRoutePtr
|
||||||
virNetworkDefGetRouteByIndex(const virNetworkDef *def,
|
virNetworkDefGetRouteByIndex(const virNetworkDef *def,
|
||||||
int family, size_t n);
|
int family, size_t n);
|
||||||
int virNetworkIPDefPrefix(const virNetworkIPDef *def);
|
int virNetworkIPDefPrefix(const virNetworkIPDef *def);
|
||||||
|
@ -32,44 +32,18 @@
|
|||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_NETWORK
|
#define VIR_FROM_THIS VIR_FROM_NETWORK
|
||||||
|
|
||||||
struct _virNetworkRouteDef {
|
virNetDevIPRoutePtr
|
||||||
char *family; /* ipv4 or ipv6 - default is ipv4 */
|
virNetDevIPRouteCreate(const char *errorDetail,
|
||||||
virSocketAddr address; /* Routed Network IP address */
|
const char *family,
|
||||||
|
const char *address,
|
||||||
/* One or the other of the following two will be used for a given
|
const char *netmask,
|
||||||
* Network address, but never both. The parser guarantees this.
|
const char *gateway,
|
||||||
* The virSocketAddrGetIPPrefix() can be used to get a
|
unsigned int prefix,
|
||||||
* valid prefix.
|
bool hasPrefix,
|
||||||
*/
|
unsigned int metric,
|
||||||
virSocketAddr netmask; /* ipv4 - either netmask or prefix specified */
|
bool hasMetric)
|
||||||
unsigned int prefix; /* ipv6 - only prefix allowed */
|
|
||||||
bool has_prefix; /* prefix= was specified */
|
|
||||||
unsigned int metric; /* value for metric (defaults to 1) */
|
|
||||||
bool has_metric; /* metric= was specified */
|
|
||||||
virSocketAddr gateway; /* gateway IP address for ip-route */
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
virNetworkRouteDefFree(virNetworkRouteDefPtr def)
|
|
||||||
{
|
{
|
||||||
if (!def)
|
virNetDevIPRoutePtr def = NULL;
|
||||||
return;
|
|
||||||
VIR_FREE(def->family);
|
|
||||||
VIR_FREE(def);
|
|
||||||
}
|
|
||||||
|
|
||||||
virNetworkRouteDefPtr
|
|
||||||
virNetworkRouteDefCreate(const char *errorDetail,
|
|
||||||
const char *family,
|
|
||||||
const char *address,
|
|
||||||
const char *netmask,
|
|
||||||
const char *gateway,
|
|
||||||
unsigned int prefix,
|
|
||||||
bool hasPrefix,
|
|
||||||
unsigned int metric,
|
|
||||||
bool hasMetric)
|
|
||||||
{
|
|
||||||
virNetworkRouteDefPtr def = NULL;
|
|
||||||
virSocketAddr testAddr;
|
virSocketAddr testAddr;
|
||||||
|
|
||||||
if (VIR_ALLOC(def) < 0)
|
if (VIR_ALLOC(def) < 0)
|
||||||
@ -242,21 +216,21 @@ virNetworkRouteDefCreate(const char *errorDetail,
|
|||||||
return def;
|
return def;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
virNetworkRouteDefFree(def);
|
virNetDevIPRouteFree(def);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
virNetworkRouteDefPtr
|
virNetDevIPRoutePtr
|
||||||
virNetworkRouteDefParseXML(const char *errorDetail,
|
virNetDevIPRouteParseXML(const char *errorDetail,
|
||||||
xmlNodePtr node,
|
xmlNodePtr node,
|
||||||
xmlXPathContextPtr ctxt)
|
xmlXPathContextPtr ctxt)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* virNetworkRouteDef object is already allocated as part
|
* virNetDevIPRoute object is already allocated as part
|
||||||
* of an array. On failure clear: it out, but don't free it.
|
* of an array. On failure clear: it out, but don't free it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
virNetworkRouteDefPtr def = NULL;
|
virNetDevIPRoutePtr def = NULL;
|
||||||
xmlNodePtr save;
|
xmlNodePtr save;
|
||||||
char *family = NULL;
|
char *family = NULL;
|
||||||
char *address = NULL, *netmask = NULL;
|
char *address = NULL, *netmask = NULL;
|
||||||
@ -302,9 +276,9 @@ virNetworkRouteDefParseXML(const char *errorDetail,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def = virNetworkRouteDefCreate(errorDetail, family, address, netmask,
|
def = virNetDevIPRouteCreate(errorDetail, family, address, netmask,
|
||||||
gateway, prefix, hasPrefix, metric,
|
gateway, prefix, hasPrefix, metric,
|
||||||
hasMetric);
|
hasMetric);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
ctxt->node = save;
|
ctxt->node = save;
|
||||||
@ -316,8 +290,8 @@ virNetworkRouteDefParseXML(const char *errorDetail,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
virNetworkRouteDefFormat(virBufferPtr buf,
|
virNetDevIPRouteFormat(virBufferPtr buf,
|
||||||
const virNetworkRouteDef *def)
|
const virNetDevIPRoute *def)
|
||||||
{
|
{
|
||||||
int result = -1;
|
int result = -1;
|
||||||
char *addr = NULL;
|
char *addr = NULL;
|
||||||
@ -354,62 +328,3 @@ virNetworkRouteDefFormat(virBufferPtr buf,
|
|||||||
cleanup:
|
cleanup:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
virSocketAddrPtr
|
|
||||||
virNetworkRouteDefGetAddress(virNetworkRouteDefPtr def)
|
|
||||||
{
|
|
||||||
if (def)
|
|
||||||
return &def->address;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
virNetworkRouteDefGetPrefix(virNetworkRouteDefPtr def)
|
|
||||||
{
|
|
||||||
int prefix = 0;
|
|
||||||
virSocketAddr zero;
|
|
||||||
|
|
||||||
if (!def)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* this creates an all-0 address of the appropriate family */
|
|
||||||
ignore_value(virSocketAddrParse(&zero,
|
|
||||||
(VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)
|
|
||||||
? VIR_SOCKET_ADDR_IPV4_ALL
|
|
||||||
: VIR_SOCKET_ADDR_IPV6_ALL),
|
|
||||||
VIR_SOCKET_ADDR_FAMILY(&def->address)));
|
|
||||||
|
|
||||||
if (virSocketAddrEqual(&def->address, &zero)) {
|
|
||||||
if (def->has_prefix && def->prefix == 0)
|
|
||||||
prefix = 0;
|
|
||||||
else if ((VIR_SOCKET_ADDR_IS_FAMILY(&def->netmask, AF_INET) &&
|
|
||||||
virSocketAddrEqual(&def->netmask, &zero)))
|
|
||||||
prefix = 0;
|
|
||||||
else
|
|
||||||
prefix = virSocketAddrGetIPPrefix(&def->address, &def->netmask,
|
|
||||||
def->prefix);
|
|
||||||
} else {
|
|
||||||
prefix = virSocketAddrGetIPPrefix(&def->address, &def->netmask,
|
|
||||||
def->prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
return prefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int
|
|
||||||
virNetworkRouteDefGetMetric(virNetworkRouteDefPtr def)
|
|
||||||
{
|
|
||||||
if (def && def->has_metric && def->metric > 0)
|
|
||||||
return def->metric;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
virSocketAddrPtr
|
|
||||||
virNetworkRouteDefGetGateway(virNetworkRouteDefPtr def)
|
|
||||||
{
|
|
||||||
if (def)
|
|
||||||
return &def->gateway;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
@ -31,42 +31,25 @@
|
|||||||
# include "internal.h"
|
# include "internal.h"
|
||||||
# include "virbuffer.h"
|
# include "virbuffer.h"
|
||||||
# include "virsocketaddr.h"
|
# include "virsocketaddr.h"
|
||||||
|
# include "virnetdevip.h"
|
||||||
|
|
||||||
typedef struct _virNetworkRouteDef virNetworkRouteDef;
|
virNetDevIPRoutePtr
|
||||||
typedef virNetworkRouteDef *virNetworkRouteDefPtr;
|
virNetDevIPRouteCreate(const char *networkName,
|
||||||
|
const char *family,
|
||||||
|
const char *address,
|
||||||
|
const char *netmask,
|
||||||
|
const char *gateway,
|
||||||
|
unsigned int prefix,
|
||||||
|
bool hasPrefix,
|
||||||
|
unsigned int metric,
|
||||||
|
bool hasMetric);
|
||||||
|
|
||||||
void
|
virNetDevIPRoutePtr
|
||||||
virNetworkRouteDefFree(virNetworkRouteDefPtr def);
|
virNetDevIPRouteParseXML(const char *networkName,
|
||||||
|
xmlNodePtr node,
|
||||||
virNetworkRouteDefPtr
|
xmlXPathContextPtr ctxt);
|
||||||
virNetworkRouteDefCreate(const char *networkName,
|
|
||||||
const char *family,
|
|
||||||
const char *address,
|
|
||||||
const char *netmask,
|
|
||||||
const char *gateway,
|
|
||||||
unsigned int prefix,
|
|
||||||
bool hasPrefix,
|
|
||||||
unsigned int metric,
|
|
||||||
bool hasMetric);
|
|
||||||
|
|
||||||
virNetworkRouteDefPtr
|
|
||||||
virNetworkRouteDefParseXML(const char *networkName,
|
|
||||||
xmlNodePtr node,
|
|
||||||
xmlXPathContextPtr ctxt);
|
|
||||||
int
|
int
|
||||||
virNetworkRouteDefFormat(virBufferPtr buf,
|
virNetDevIPRouteFormat(virBufferPtr buf,
|
||||||
const virNetworkRouteDef *def);
|
const virNetDevIPRoute *def);
|
||||||
|
|
||||||
virSocketAddrPtr
|
|
||||||
virNetworkRouteDefGetAddress(virNetworkRouteDefPtr def);
|
|
||||||
|
|
||||||
int
|
|
||||||
virNetworkRouteDefGetPrefix(virNetworkRouteDefPtr def);
|
|
||||||
|
|
||||||
unsigned int
|
|
||||||
virNetworkRouteDefGetMetric(virNetworkRouteDefPtr def);
|
|
||||||
|
|
||||||
virSocketAddrPtr
|
|
||||||
virNetworkRouteDefGetGateway(virNetworkRouteDefPtr def);
|
|
||||||
|
|
||||||
#endif /* __NETWORKCOMMON_CONF_H__ */
|
#endif /* __NETWORKCOMMON_CONF_H__ */
|
||||||
|
@ -644,14 +644,9 @@ virNetworkEventStateRegisterID;
|
|||||||
|
|
||||||
|
|
||||||
# conf/networkcommon_conf.h
|
# conf/networkcommon_conf.h
|
||||||
virNetworkRouteDefCreate;
|
virNetDevIPRouteCreate;
|
||||||
virNetworkRouteDefFormat;
|
virNetDevIPRouteFormat;
|
||||||
virNetworkRouteDefFree;
|
virNetDevIPRouteParseXML;
|
||||||
virNetworkRouteDefGetAddress;
|
|
||||||
virNetworkRouteDefGetGateway;
|
|
||||||
virNetworkRouteDefGetMetric;
|
|
||||||
virNetworkRouteDefGetPrefix;
|
|
||||||
virNetworkRouteDefParseXML;
|
|
||||||
|
|
||||||
|
|
||||||
# conf/node_device_conf.h
|
# conf/node_device_conf.h
|
||||||
@ -1937,6 +1932,11 @@ virNetDevIPAddrAdd;
|
|||||||
virNetDevIPAddrDel;
|
virNetDevIPAddrDel;
|
||||||
virNetDevIPAddrGet;
|
virNetDevIPAddrGet;
|
||||||
virNetDevIPRouteAdd;
|
virNetDevIPRouteAdd;
|
||||||
|
virNetDevIPRouteFree;
|
||||||
|
virNetDevIPRouteGetAddress;
|
||||||
|
virNetDevIPRouteGetGateway;
|
||||||
|
virNetDevIPRouteGetMetric;
|
||||||
|
virNetDevIPRouteGetPrefix;
|
||||||
virNetDevIPWaitDadFinish;
|
virNetDevIPWaitDadFinish;
|
||||||
|
|
||||||
|
|
||||||
|
@ -513,7 +513,7 @@ static int lxcContainerRenameAndEnableInterfaces(virDomainDefPtr vmDef,
|
|||||||
goto error_out;
|
goto error_out;
|
||||||
|
|
||||||
for (j = 0; j < netDef->nips; j++) {
|
for (j = 0; j < netDef->nips; j++) {
|
||||||
virDomainNetIPDefPtr ip = netDef->ips[j];
|
virNetDevIPAddrPtr ip = netDef->ips[j];
|
||||||
int prefix;
|
int prefix;
|
||||||
char *ipStr = virSocketAddrFormat(&ip->address);
|
char *ipStr = virSocketAddrFormat(&ip->address);
|
||||||
|
|
||||||
@ -547,13 +547,13 @@ static int lxcContainerRenameAndEnableInterfaces(virDomainDefPtr vmDef,
|
|||||||
|
|
||||||
/* Set the routes */
|
/* Set the routes */
|
||||||
for (j = 0; j < netDef->nroutes; j++) {
|
for (j = 0; j < netDef->nroutes; j++) {
|
||||||
virNetworkRouteDefPtr route = netDef->routes[j];
|
virNetDevIPRoutePtr route = netDef->routes[j];
|
||||||
|
|
||||||
if (virNetDevIPRouteAdd(newname,
|
if (virNetDevIPRouteAdd(newname,
|
||||||
virNetworkRouteDefGetAddress(route),
|
virNetDevIPRouteGetAddress(route),
|
||||||
virNetworkRouteDefGetPrefix(route),
|
virNetDevIPRouteGetPrefix(route),
|
||||||
virNetworkRouteDefGetGateway(route),
|
virNetDevIPRouteGetGateway(route),
|
||||||
virNetworkRouteDefGetMetric(route)) < 0) {
|
virNetDevIPRouteGetMetric(route)) < 0) {
|
||||||
goto error_out;
|
goto error_out;
|
||||||
}
|
}
|
||||||
VIR_FREE(toStr);
|
VIR_FREE(toStr);
|
||||||
|
@ -419,7 +419,7 @@ typedef struct {
|
|||||||
char *macvlanmode;
|
char *macvlanmode;
|
||||||
char *vlanid;
|
char *vlanid;
|
||||||
char *name;
|
char *name;
|
||||||
virDomainNetIPDefPtr *ips;
|
virNetDevIPAddrPtr *ips;
|
||||||
size_t nips;
|
size_t nips;
|
||||||
char *gateway_ipv4;
|
char *gateway_ipv4;
|
||||||
char *gateway_ipv6;
|
char *gateway_ipv6;
|
||||||
@ -430,10 +430,10 @@ typedef struct {
|
|||||||
static int
|
static int
|
||||||
lxcAddNetworkRouteDefinition(const char *address,
|
lxcAddNetworkRouteDefinition(const char *address,
|
||||||
int family,
|
int family,
|
||||||
virNetworkRouteDefPtr **routes,
|
virNetDevIPRoutePtr **routes,
|
||||||
size_t *nroutes)
|
size_t *nroutes)
|
||||||
{
|
{
|
||||||
virNetworkRouteDefPtr route = NULL;
|
virNetDevIPRoutePtr route = NULL;
|
||||||
char *familyStr = NULL;
|
char *familyStr = NULL;
|
||||||
char *zero = NULL;
|
char *zero = NULL;
|
||||||
|
|
||||||
@ -444,9 +444,9 @@ lxcAddNetworkRouteDefinition(const char *address,
|
|||||||
if (VIR_STRDUP(familyStr, family == AF_INET ? "ipv4" : "ipv6") < 0)
|
if (VIR_STRDUP(familyStr, family == AF_INET ? "ipv4" : "ipv6") < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!(route = virNetworkRouteDefCreate(_("Domain interface"), familyStr,
|
if (!(route = virNetDevIPRouteCreate(_("Domain interface"), familyStr,
|
||||||
zero, NULL, address, 0, false,
|
zero, NULL, address, 0, false,
|
||||||
0, false)))
|
0, false)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (VIR_APPEND_ELEMENT(*routes, *nroutes, route) < 0)
|
if (VIR_APPEND_ELEMENT(*routes, *nroutes, route) < 0)
|
||||||
@ -460,7 +460,7 @@ lxcAddNetworkRouteDefinition(const char *address,
|
|||||||
error:
|
error:
|
||||||
VIR_FREE(familyStr);
|
VIR_FREE(familyStr);
|
||||||
VIR_FREE(zero);
|
VIR_FREE(zero);
|
||||||
virNetworkRouteDefFree(route);
|
virNetDevIPRouteFree(route);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -601,7 +601,7 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data)
|
|||||||
STREQ(name, "lxc.network.ipv6")) {
|
STREQ(name, "lxc.network.ipv6")) {
|
||||||
int family = AF_INET;
|
int family = AF_INET;
|
||||||
char **ipparts = NULL;
|
char **ipparts = NULL;
|
||||||
virDomainNetIPDefPtr ip = NULL;
|
virNetDevIPAddrPtr ip = NULL;
|
||||||
|
|
||||||
if (VIR_ALLOC(ip) < 0)
|
if (VIR_ALLOC(ip) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -2011,12 +2011,12 @@ networkStartHandleMACTableManagerMode(virNetworkObjPtr network,
|
|||||||
/* add an IP (static) route to a bridge */
|
/* add an IP (static) route to a bridge */
|
||||||
static int
|
static int
|
||||||
networkAddRouteToBridge(virNetworkObjPtr network,
|
networkAddRouteToBridge(virNetworkObjPtr network,
|
||||||
virNetworkRouteDefPtr routedef)
|
virNetDevIPRoutePtr routedef)
|
||||||
{
|
{
|
||||||
int prefix = virNetworkRouteDefGetPrefix(routedef);
|
int prefix = virNetDevIPRouteGetPrefix(routedef);
|
||||||
unsigned int metric = virNetworkRouteDefGetMetric(routedef);
|
unsigned int metric = virNetDevIPRouteGetMetric(routedef);
|
||||||
virSocketAddrPtr addr = virNetworkRouteDefGetAddress(routedef);
|
virSocketAddrPtr addr = virNetDevIPRouteGetAddress(routedef);
|
||||||
virSocketAddrPtr gateway = virNetworkRouteDefGetGateway(routedef);
|
virSocketAddrPtr gateway = virNetDevIPRouteGetGateway(routedef);
|
||||||
|
|
||||||
if (prefix < 0) {
|
if (prefix < 0) {
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
@ -2067,7 +2067,7 @@ networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
|
|||||||
bool v4present = false, v6present = false;
|
bool v4present = false, v6present = false;
|
||||||
virErrorPtr save_err = NULL;
|
virErrorPtr save_err = NULL;
|
||||||
virNetworkIPDefPtr ipdef;
|
virNetworkIPDefPtr ipdef;
|
||||||
virNetworkRouteDefPtr routedef;
|
virNetDevIPRoutePtr routedef;
|
||||||
char *macTapIfName = NULL;
|
char *macTapIfName = NULL;
|
||||||
int tapfd = -1;
|
int tapfd = -1;
|
||||||
|
|
||||||
@ -2162,7 +2162,7 @@ networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
|
|||||||
virSocketAddrPtr gateway = NULL;
|
virSocketAddrPtr gateway = NULL;
|
||||||
|
|
||||||
routedef = network->def->routes[i];
|
routedef = network->def->routes[i];
|
||||||
gateway = virNetworkRouteDefGetGateway(routedef);
|
gateway = virNetDevIPRouteGetGateway(routedef);
|
||||||
|
|
||||||
/* Add the IP route to the bridge */
|
/* Add the IP route to the bridge */
|
||||||
/* ignore errors, error msg will be generated */
|
/* ignore errors, error msg will be generated */
|
||||||
|
@ -69,7 +69,7 @@ int networkCheckRouteCollision(virNetworkDefPtr def)
|
|||||||
char iface[17], dest[128], mask[128];
|
char iface[17], dest[128], mask[128];
|
||||||
unsigned int addr_val, mask_val;
|
unsigned int addr_val, mask_val;
|
||||||
virNetworkIPDefPtr ipdef;
|
virNetworkIPDefPtr ipdef;
|
||||||
virNetworkRouteDefPtr routedef;
|
virNetDevIPRoutePtr routedef;
|
||||||
int num;
|
int num;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
@ -130,8 +130,8 @@ int networkCheckRouteCollision(virNetworkDefPtr def)
|
|||||||
i++) {
|
i++) {
|
||||||
|
|
||||||
virSocketAddr r_mask, r_addr;
|
virSocketAddr r_mask, r_addr;
|
||||||
virSocketAddrPtr tmp_addr = virNetworkRouteDefGetAddress(routedef);
|
virSocketAddrPtr tmp_addr = virNetDevIPRouteGetAddress(routedef);
|
||||||
int r_prefix = virNetworkRouteDefGetPrefix(routedef);
|
int r_prefix = virNetDevIPRouteGetPrefix(routedef);
|
||||||
|
|
||||||
if (!tmp_addr ||
|
if (!tmp_addr ||
|
||||||
virSocketAddrMaskByPrefix(tmp_addr, r_prefix, &r_addr) < 0 ||
|
virSocketAddrMaskByPrefix(tmp_addr, r_prefix, &r_addr) < 0 ||
|
||||||
|
@ -776,3 +776,72 @@ virNetDevIPAddrGet(const char *ifname,
|
|||||||
_("Unable to get IP address on this platform"));
|
_("Unable to get IP address on this platform"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* manipulating the virNetDevIPRoute object */
|
||||||
|
void
|
||||||
|
virNetDevIPRouteFree(virNetDevIPRoutePtr def)
|
||||||
|
{
|
||||||
|
if (!def)
|
||||||
|
return;
|
||||||
|
VIR_FREE(def->family);
|
||||||
|
VIR_FREE(def);
|
||||||
|
}
|
||||||
|
|
||||||
|
virSocketAddrPtr
|
||||||
|
virNetDevIPRouteGetAddress(virNetDevIPRoutePtr def)
|
||||||
|
{
|
||||||
|
if (def)
|
||||||
|
return &def->address;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
virNetDevIPRouteGetPrefix(virNetDevIPRoutePtr def)
|
||||||
|
{
|
||||||
|
int prefix = 0;
|
||||||
|
virSocketAddr zero;
|
||||||
|
|
||||||
|
if (!def)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* this creates an all-0 address of the appropriate family */
|
||||||
|
ignore_value(virSocketAddrParse(&zero,
|
||||||
|
(VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)
|
||||||
|
? VIR_SOCKET_ADDR_IPV4_ALL
|
||||||
|
: VIR_SOCKET_ADDR_IPV6_ALL),
|
||||||
|
VIR_SOCKET_ADDR_FAMILY(&def->address)));
|
||||||
|
|
||||||
|
if (virSocketAddrEqual(&def->address, &zero)) {
|
||||||
|
if (def->has_prefix && def->prefix == 0)
|
||||||
|
prefix = 0;
|
||||||
|
else if ((VIR_SOCKET_ADDR_IS_FAMILY(&def->netmask, AF_INET) &&
|
||||||
|
virSocketAddrEqual(&def->netmask, &zero)))
|
||||||
|
prefix = 0;
|
||||||
|
else
|
||||||
|
prefix = virSocketAddrGetIPPrefix(&def->address, &def->netmask,
|
||||||
|
def->prefix);
|
||||||
|
} else {
|
||||||
|
prefix = virSocketAddrGetIPPrefix(&def->address, &def->netmask,
|
||||||
|
def->prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
virNetDevIPRouteGetMetric(virNetDevIPRoutePtr def)
|
||||||
|
{
|
||||||
|
if (def && def->has_metric && def->metric > 0)
|
||||||
|
return def->metric;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
virSocketAddrPtr
|
||||||
|
virNetDevIPRouteGetGateway(virNetDevIPRoutePtr def)
|
||||||
|
{
|
||||||
|
if (def)
|
||||||
|
return &def->gateway;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@ -25,6 +25,28 @@
|
|||||||
|
|
||||||
# include "virsocketaddr.h"
|
# include "virsocketaddr.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
virSocketAddr address; /* ipv4 or ipv6 address */
|
||||||
|
unsigned int prefix; /* number of 1 bits in the net mask */
|
||||||
|
} virNetDevIPAddr, *virNetDevIPAddrPtr;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *family; /* ipv4 or ipv6 - default is ipv4 */
|
||||||
|
virSocketAddr address; /* Routed Network IP address */
|
||||||
|
|
||||||
|
/* One or the other of the following two will be used for a given
|
||||||
|
* Network address, but never both. The parser guarantees this.
|
||||||
|
* The virSocketAddrGetIPPrefix() can be used to get a
|
||||||
|
* valid prefix.
|
||||||
|
*/
|
||||||
|
virSocketAddr netmask; /* ipv4 - either netmask or prefix specified */
|
||||||
|
unsigned int prefix; /* ipv6 - only prefix allowed */
|
||||||
|
bool has_prefix; /* prefix= was specified */
|
||||||
|
unsigned int metric; /* value for metric (defaults to 1) */
|
||||||
|
bool has_metric; /* metric= was specified */
|
||||||
|
virSocketAddr gateway; /* gateway IP address for ip-route */
|
||||||
|
} virNetDevIPRoute, *virNetDevIPRoutePtr;
|
||||||
|
|
||||||
/* manipulating/querying the netdev */
|
/* manipulating/querying the netdev */
|
||||||
int virNetDevIPAddrAdd(const char *ifname,
|
int virNetDevIPAddrAdd(const char *ifname,
|
||||||
virSocketAddr *addr,
|
virSocketAddr *addr,
|
||||||
@ -47,4 +69,11 @@ int virNetDevIPAddrGet(const char *ifname, virSocketAddrPtr addr)
|
|||||||
int virNetDevIPWaitDadFinish(virSocketAddrPtr *addrs, size_t count)
|
int virNetDevIPWaitDadFinish(virSocketAddrPtr *addrs, size_t count)
|
||||||
ATTRIBUTE_NONNULL(1);
|
ATTRIBUTE_NONNULL(1);
|
||||||
|
|
||||||
|
/* virNetDevIPRoute object */
|
||||||
|
void virNetDevIPRouteFree(virNetDevIPRoutePtr def);
|
||||||
|
virSocketAddrPtr virNetDevIPRouteGetAddress(virNetDevIPRoutePtr def);
|
||||||
|
int virNetDevIPRouteGetPrefix(virNetDevIPRoutePtr def);
|
||||||
|
unsigned int virNetDevIPRouteGetMetric(virNetDevIPRoutePtr def);
|
||||||
|
virSocketAddrPtr virNetDevIPRouteGetGateway(virNetDevIPRoutePtr def);
|
||||||
|
|
||||||
#endif /* __VIR_NETDEVIP_H__ */
|
#endif /* __VIR_NETDEVIP_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user