2016-11-25 06:30:30 +00:00
|
|
|
/*
|
|
|
|
* virmacmap.c: MAC address <-> Domain name mapping
|
|
|
|
*
|
|
|
|
* Copyright (C) 2016 Red Hat, Inc.
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library. If not, see
|
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "virmacmap.h"
|
|
|
|
#include "virobject.h"
|
|
|
|
#include "virlog.h"
|
|
|
|
#include "virjson.h"
|
|
|
|
#include "virfile.h"
|
|
|
|
#include "virhash.h"
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_NETWORK
|
|
|
|
|
|
|
|
VIR_LOG_INIT("util.virmacmap");
|
|
|
|
|
|
|
|
/**
|
|
|
|
* VIR_MAC_MAP_FILE_SIZE_MAX:
|
|
|
|
*
|
|
|
|
* Macro providing the upper limit on the size of mac maps file
|
|
|
|
*/
|
|
|
|
#define VIR_MAC_MAP_FILE_SIZE_MAX (32 * 1024 * 1024)
|
|
|
|
|
|
|
|
struct virMacMap {
|
|
|
|
virObjectLockable parent;
|
|
|
|
|
2020-10-22 17:04:18 +00:00
|
|
|
GHashTable *macs;
|
2016-11-25 06:30:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static virClass *virMacMapClass;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
static void
|
2017-01-02 09:35:33 +00:00
|
|
|
virMacMapDispose(void *obj)
|
2016-11-25 06:30:30 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacMap *mgr = obj;
|
2021-02-05 13:25:16 +00:00
|
|
|
GHashTableIter htitr;
|
|
|
|
void *value;
|
|
|
|
|
|
|
|
g_hash_table_iter_init(&htitr, mgr->macs);
|
|
|
|
|
|
|
|
while (g_hash_table_iter_next(&htitr, NULL, &value))
|
|
|
|
g_slist_free_full(value, g_free);
|
|
|
|
|
2021-11-30 13:13:28 +00:00
|
|
|
g_clear_pointer(&mgr->macs, g_hash_table_unref);
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int virMacMapOnceInit(void)
|
|
|
|
{
|
2018-04-17 15:42:33 +00:00
|
|
|
if (!VIR_CLASS_NEW(virMacMap, virClassForObjectLockable()))
|
2016-11-25 06:30:30 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_ONCE_GLOBAL_INIT(virMacMap);
|
|
|
|
|
|
|
|
|
2021-02-05 13:25:16 +00:00
|
|
|
static void
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacMapAddLocked(virMacMap *mgr,
|
2016-11-25 06:30:30 +00:00
|
|
|
const char *domain,
|
|
|
|
const char *mac)
|
|
|
|
{
|
2021-02-05 13:25:16 +00:00
|
|
|
GSList *orig_list;
|
|
|
|
GSList *list;
|
|
|
|
GSList *next;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
2021-02-05 13:25:16 +00:00
|
|
|
list = orig_list = g_hash_table_lookup(mgr->macs, domain);
|
|
|
|
|
|
|
|
for (next = list; next; next = next->next) {
|
|
|
|
if (STREQ((const char *) next->data, mac))
|
|
|
|
return;
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
2021-02-05 13:25:16 +00:00
|
|
|
list = g_slist_append(list, g_strdup(mac));
|
2016-11-25 06:30:30 +00:00
|
|
|
|
2021-02-05 13:25:16 +00:00
|
|
|
if (list != orig_list)
|
|
|
|
g_hash_table_insert(mgr->macs, g_strdup(domain), list);
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-02-05 13:25:16 +00:00
|
|
|
static void
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacMapRemoveLocked(virMacMap *mgr,
|
2016-11-25 06:30:30 +00:00
|
|
|
const char *domain,
|
|
|
|
const char *mac)
|
|
|
|
{
|
2021-02-05 13:25:16 +00:00
|
|
|
GSList *orig_list;
|
|
|
|
GSList *list;
|
|
|
|
GSList *next;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
2021-02-05 13:25:16 +00:00
|
|
|
list = orig_list = g_hash_table_lookup(mgr->macs, domain);
|
2016-11-25 06:30:30 +00:00
|
|
|
|
2021-02-05 13:25:16 +00:00
|
|
|
if (!orig_list)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (next = list; next; next = next->next) {
|
|
|
|
if (STREQ((const char *) next->data, mac)) {
|
|
|
|
list = g_slist_remove_link(list, next);
|
|
|
|
g_slist_free_full(next, g_free);
|
|
|
|
break;
|
|
|
|
}
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
2021-02-05 13:25:16 +00:00
|
|
|
if (list != orig_list) {
|
|
|
|
if (list)
|
|
|
|
g_hash_table_insert(mgr->macs, g_strdup(domain), list);
|
|
|
|
else
|
|
|
|
g_hash_table_remove(mgr->macs, domain);
|
|
|
|
}
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacMapLoadFile(virMacMap *mgr,
|
2016-11-25 06:30:30 +00:00
|
|
|
const char *file)
|
|
|
|
{
|
2020-11-23 22:09:34 +00:00
|
|
|
g_autofree char *map_str = NULL;
|
2021-02-05 10:14:09 +00:00
|
|
|
g_autoptr(virJSONValue) map = NULL;
|
2016-11-25 06:30:30 +00:00
|
|
|
int map_str_len = 0;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (virFileExists(file) &&
|
|
|
|
(map_str_len = virFileReadAll(file,
|
|
|
|
VIR_MAC_MAP_FILE_SIZE_MAX,
|
|
|
|
&map_str)) < 0)
|
2021-02-05 10:14:43 +00:00
|
|
|
return -1;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
2021-02-05 10:14:43 +00:00
|
|
|
if (map_str_len == 0)
|
|
|
|
return 0;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
|
|
|
if (!(map = virJSONValueFromString(map_str))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2023-03-09 14:13:35 +00:00
|
|
|
_("invalid json in file: %1$s"),
|
2016-11-25 06:30:30 +00:00
|
|
|
file);
|
2021-02-05 10:14:43 +00:00
|
|
|
return -1;
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!virJSONValueIsArray(map)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2023-03-09 14:13:35 +00:00
|
|
|
_("Malformed file structure: %1$s"),
|
2016-11-25 06:30:30 +00:00
|
|
|
file);
|
2021-02-05 10:14:43 +00:00
|
|
|
return -1;
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < virJSONValueArraySize(map); i++) {
|
2021-03-11 07:16:13 +00:00
|
|
|
virJSONValue *tmp = virJSONValueArrayGet(map, i);
|
|
|
|
virJSONValue *macs;
|
2016-11-25 06:30:30 +00:00
|
|
|
const char *domain;
|
|
|
|
size_t j;
|
2021-02-05 13:25:16 +00:00
|
|
|
GSList *vals = NULL;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
|
|
|
if (!(domain = virJSONValueObjectGetString(tmp, "domain"))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Missing domain"));
|
2021-02-05 10:14:43 +00:00
|
|
|
return -1;
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(macs = virJSONValueObjectGetArray(tmp, "macs"))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Missing macs"));
|
2021-02-05 10:14:43 +00:00
|
|
|
return -1;
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
2021-02-05 13:25:16 +00:00
|
|
|
if (g_hash_table_contains(mgr->macs, domain)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2023-03-09 14:13:35 +00:00
|
|
|
_("duplicate domain '%1$s'"), domain);
|
2021-02-05 13:25:16 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-11-25 06:30:30 +00:00
|
|
|
for (j = 0; j < virJSONValueArraySize(macs); j++) {
|
2021-03-11 07:16:13 +00:00
|
|
|
virJSONValue *macJSON = virJSONValueArrayGet(macs, j);
|
2016-11-25 06:30:30 +00:00
|
|
|
|
2021-02-05 13:25:16 +00:00
|
|
|
vals = g_slist_prepend(vals, g_strdup(virJSONValueGetString(macJSON)));
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
2021-02-05 13:25:16 +00:00
|
|
|
|
|
|
|
vals = g_slist_reverse(vals);
|
|
|
|
g_hash_table_insert(mgr->macs, g_strdup(domain), vals);
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
2021-02-05 10:14:43 +00:00
|
|
|
return 0;
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virMACMapHashDumper(void *payload,
|
2020-10-21 11:31:16 +00:00
|
|
|
const char *name,
|
2016-11-25 06:30:30 +00:00
|
|
|
void *data)
|
|
|
|
{
|
2021-02-05 10:14:09 +00:00
|
|
|
g_autoptr(virJSONValue) obj = virJSONValueNewObject();
|
|
|
|
g_autoptr(virJSONValue) arr = virJSONValueNewArray();
|
2021-02-05 13:25:16 +00:00
|
|
|
GSList *macs = payload;
|
|
|
|
GSList *next;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
2021-02-05 13:25:16 +00:00
|
|
|
for (next = macs; next; next = next->next) {
|
2021-12-20 13:41:03 +00:00
|
|
|
if (virJSONValueArrayAppendString(arr, (const char *) next->data) < 0)
|
2021-02-05 10:14:43 +00:00
|
|
|
return -1;
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virJSONValueObjectAppendString(obj, "domain", name) < 0 ||
|
2021-02-11 16:57:45 +00:00
|
|
|
virJSONValueObjectAppend(obj, "macs", &arr) < 0)
|
2021-02-05 10:14:43 +00:00
|
|
|
return -1;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
2021-02-11 16:57:45 +00:00
|
|
|
if (virJSONValueArrayAppend(data, &obj) < 0)
|
2021-02-05 10:14:43 +00:00
|
|
|
return -1;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
2021-02-05 10:14:43 +00:00
|
|
|
return 0;
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacMapDumpStrLocked(virMacMap *mgr,
|
2016-11-25 06:30:30 +00:00
|
|
|
char **str)
|
|
|
|
{
|
2021-02-05 10:14:09 +00:00
|
|
|
g_autoptr(virJSONValue) arr = virJSONValueNewArray();
|
2016-11-25 06:30:30 +00:00
|
|
|
|
2020-10-23 07:07:02 +00:00
|
|
|
if (virHashForEachSorted(mgr->macs, virMACMapHashDumper, arr) < 0)
|
2021-02-05 10:14:43 +00:00
|
|
|
return -1;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
|
|
|
if (!(*str = virJSONValueToString(arr, true)))
|
2021-02-05 10:14:43 +00:00
|
|
|
return -1;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
2021-02-05 10:14:43 +00:00
|
|
|
return 0;
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacMapWriteFileLocked(virMacMap *mgr,
|
2016-11-25 06:30:30 +00:00
|
|
|
const char *file)
|
|
|
|
{
|
2020-03-05 16:16:29 +00:00
|
|
|
g_autofree char *str = NULL;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
|
|
|
if (virMacMapDumpStrLocked(mgr, &str) < 0)
|
2020-03-05 16:16:29 +00:00
|
|
|
return -1;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
|
|
|
if (virFileRewriteStr(file, 0644, str) < 0)
|
2020-03-05 16:16:29 +00:00
|
|
|
return -1;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
2020-03-05 16:16:29 +00:00
|
|
|
return 0;
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-26 10:59:19 +00:00
|
|
|
char *
|
|
|
|
virMacMapFileName(const char *dnsmasqStateDir,
|
|
|
|
const char *bridge)
|
|
|
|
{
|
2021-10-22 08:56:01 +00:00
|
|
|
return g_strdup_printf("%s/%s.macs", dnsmasqStateDir, bridge);
|
2017-07-26 10:59:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-11-25 06:30:30 +00:00
|
|
|
#define VIR_MAC_HASH_TABLE_SIZE 10
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacMap *
|
2016-11-25 06:30:30 +00:00
|
|
|
virMacMapNew(const char *file)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacMap *mgr;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
|
|
|
if (virMacMapInitialize() < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!(mgr = virObjectLockableNew(virMacMapClass)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
virObjectLock(mgr);
|
2021-02-05 13:25:16 +00:00
|
|
|
|
|
|
|
mgr->macs = virHashNew(NULL);
|
2016-11-25 06:30:30 +00:00
|
|
|
|
|
|
|
if (file &&
|
|
|
|
virMacMapLoadFile(mgr, file) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virObjectUnlock(mgr);
|
|
|
|
return mgr;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virObjectUnlock(mgr);
|
|
|
|
virObjectUnref(mgr);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacMapAdd(virMacMap *mgr,
|
2016-11-25 06:30:30 +00:00
|
|
|
const char *domain,
|
|
|
|
const char *mac)
|
|
|
|
{
|
|
|
|
virObjectLock(mgr);
|
2021-02-05 13:25:16 +00:00
|
|
|
virMacMapAddLocked(mgr, domain, mac);
|
2016-11-25 06:30:30 +00:00
|
|
|
virObjectUnlock(mgr);
|
2021-02-05 13:25:16 +00:00
|
|
|
return 0;
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacMapRemove(virMacMap *mgr,
|
2016-11-25 06:30:30 +00:00
|
|
|
const char *domain,
|
|
|
|
const char *mac)
|
|
|
|
{
|
|
|
|
virObjectLock(mgr);
|
2021-02-05 13:25:16 +00:00
|
|
|
virMacMapRemoveLocked(mgr, domain, mac);
|
2016-11-25 06:30:30 +00:00
|
|
|
virObjectUnlock(mgr);
|
2021-02-05 13:25:16 +00:00
|
|
|
return 0;
|
2016-11-25 06:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-02-05 13:25:16 +00:00
|
|
|
/* note that the returned pointer may be invalidated by other APIs in this module */
|
|
|
|
GSList *
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacMapLookup(virMacMap *mgr,
|
2016-11-25 06:30:30 +00:00
|
|
|
const char *domain)
|
|
|
|
{
|
2021-02-05 13:25:16 +00:00
|
|
|
GSList *ret;
|
2016-11-25 06:30:30 +00:00
|
|
|
|
|
|
|
virObjectLock(mgr);
|
|
|
|
ret = virHashLookup(mgr->macs, domain);
|
|
|
|
virObjectUnlock(mgr);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacMapWriteFile(virMacMap *mgr,
|
2016-11-25 06:30:30 +00:00
|
|
|
const char *filename)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
virObjectLock(mgr);
|
|
|
|
ret = virMacMapWriteFileLocked(mgr, filename);
|
|
|
|
virObjectUnlock(mgr);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacMapDumpStr(virMacMap *mgr,
|
2016-11-25 06:30:30 +00:00
|
|
|
char **str)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
virObjectLock(mgr);
|
|
|
|
ret = virMacMapDumpStrLocked(mgr, str);
|
|
|
|
virObjectUnlock(mgr);
|
|
|
|
return ret;
|
|
|
|
}
|