mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-03 11:35:19 +00:00
util: functions to manage bridge fdb (forwarding database)
These two functions use netlink RTM_NEWNEIGH and RTM_DELNEIGH messages to add and delete entries from a bridge's fdb. The bridge itself is not referenced in the arguments to the functions, only the name of the device that is attached to the bridge (since a device can only be attached to one bridge at a time, and must be attached for this function to make sense, the kernel easily infers which bridge's fdb is being modified by looking at the device name/index).
This commit is contained in:
parent
100b7a72a4
commit
19a5474d04
@ -1661,6 +1661,8 @@ virNetDevBandwidthUpdateRate;
|
|||||||
virNetDevBridgeAddPort;
|
virNetDevBridgeAddPort;
|
||||||
virNetDevBridgeCreate;
|
virNetDevBridgeCreate;
|
||||||
virNetDevBridgeDelete;
|
virNetDevBridgeDelete;
|
||||||
|
virNetDevBridgeFDBAdd;
|
||||||
|
virNetDevBridgeFDBDel;
|
||||||
virNetDevBridgeGetSTP;
|
virNetDevBridgeGetSTP;
|
||||||
virNetDevBridgeGetSTPDelay;
|
virNetDevBridgeGetSTPDelay;
|
||||||
virNetDevBridgeGetVlanFiltering;
|
virNetDevBridgeGetVlanFiltering;
|
||||||
|
@ -37,6 +37,9 @@
|
|||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
# if defined(HAVE_LIBNL)
|
||||||
|
# include "virnetlink.h"
|
||||||
|
# endif
|
||||||
# include <linux/sockios.h>
|
# include <linux/sockios.h>
|
||||||
# include <linux/param.h> /* HZ */
|
# include <linux/param.h> /* HZ */
|
||||||
# if NETINET_LINUX_WORKAROUND
|
# if NETINET_LINUX_WORKAROUND
|
||||||
@ -913,3 +916,147 @@ virNetDevBridgeSetVlanFiltering(const char *brname ATTRIBUTE_UNUSED,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__linux__) && defined(HAVE_LIBNL)
|
||||||
|
/* virNetDevBridgeFDBAddDel:
|
||||||
|
* @mac: the MAC address being added to the table
|
||||||
|
* @ifname: name of the port (interface) of the bridge that wants this MAC
|
||||||
|
* @flags: any of virNetDevBridgeFDBFlags ORed together.
|
||||||
|
* @isAdd: true if adding the entry, fals if deleting
|
||||||
|
*
|
||||||
|
* Use netlink RTM_NEWNEIGH and RTM_DELNEIGH messages to add and
|
||||||
|
* delete entries from a bridge's fdb. The bridge itself is not
|
||||||
|
* referenced in the arguments to the function, only the name of the
|
||||||
|
* device that is attached to the bridge (since a device can only be
|
||||||
|
* attached to one bridge at a time, and must be attached for this
|
||||||
|
* function to make sense, the kernel easily infers which bridge's fdb
|
||||||
|
* is being modified by looking at the device name/index).
|
||||||
|
*
|
||||||
|
* Attempting to add an existing entry, or delete a non-existing entry
|
||||||
|
* *is* an error.
|
||||||
|
*
|
||||||
|
* returns 0 on success, -1 on failure.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
virNetDevBridgeFDBAddDel(const virMacAddr *mac, const char *ifname,
|
||||||
|
unsigned int flags, bool isAdd)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
struct nlmsghdr *resp = NULL;
|
||||||
|
struct nlmsgerr *err;
|
||||||
|
unsigned int recvbuflen;
|
||||||
|
struct nl_msg *nl_msg;
|
||||||
|
struct ndmsg ndm = { .ndm_family = PF_BRIDGE, .ndm_state = NUD_NOARP };
|
||||||
|
|
||||||
|
if (virNetDevGetIndex(ifname, &ndm.ndm_ifindex) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (flags & VIR_NETDEVBRIDGE_FDB_FLAG_ROUTER)
|
||||||
|
ndm.ndm_flags |= NTF_ROUTER;
|
||||||
|
if (flags & VIR_NETDEVBRIDGE_FDB_FLAG_SELF)
|
||||||
|
ndm.ndm_flags |= NTF_SELF;
|
||||||
|
if (flags & VIR_NETDEVBRIDGE_FDB_FLAG_MASTER)
|
||||||
|
ndm.ndm_flags |= NTF_MASTER;
|
||||||
|
/* default self (same as iproute2's bridge command */
|
||||||
|
if (!(ndm.ndm_flags & (NTF_MASTER | NTF_SELF)))
|
||||||
|
ndm.ndm_flags |= NTF_SELF;
|
||||||
|
|
||||||
|
if (flags & VIR_NETDEVBRIDGE_FDB_FLAG_PERMANENT)
|
||||||
|
ndm.ndm_state |= NUD_PERMANENT;
|
||||||
|
if (flags & VIR_NETDEVBRIDGE_FDB_FLAG_TEMP)
|
||||||
|
ndm.ndm_state |= NUD_REACHABLE;
|
||||||
|
/* default permanent, same as iproute2's bridge command */
|
||||||
|
if (!(ndm.ndm_state & (NUD_PERMANENT | NUD_REACHABLE)))
|
||||||
|
ndm.ndm_state |= NUD_PERMANENT;
|
||||||
|
|
||||||
|
nl_msg = nlmsg_alloc_simple(isAdd ? RTM_NEWNEIGH : RTM_DELNEIGH,
|
||||||
|
NLM_F_REQUEST |
|
||||||
|
(isAdd ? (NLM_F_CREATE | NLM_F_EXCL) : 0));
|
||||||
|
if (!nl_msg) {
|
||||||
|
virReportOOMError();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nlmsg_append(nl_msg, &ndm, sizeof(ndm), NLMSG_ALIGNTO) < 0)
|
||||||
|
goto buffer_too_small;
|
||||||
|
if (nla_put(nl_msg, NDA_LLADDR, VIR_MAC_BUFLEN, mac) < 0)
|
||||||
|
goto buffer_too_small;
|
||||||
|
|
||||||
|
/* NB: this message can also accept a Destination IP, a port, a
|
||||||
|
* vlan tag, and a via (see iproute2/bridge/fdb.c:fdb_modify()),
|
||||||
|
* but those aren't required for our application
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, 0, 0,
|
||||||
|
NETLINK_ROUTE, 0) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL)
|
||||||
|
goto malformed_resp;
|
||||||
|
|
||||||
|
switch (resp->nlmsg_type) {
|
||||||
|
case NLMSG_ERROR:
|
||||||
|
err = (struct nlmsgerr *)NLMSG_DATA(resp);
|
||||||
|
if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
|
||||||
|
goto malformed_resp;
|
||||||
|
if (err->error) {
|
||||||
|
virReportSystemError(-err->error,
|
||||||
|
_("error adding fdb entry for %s"), ifname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NLMSG_DONE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto malformed_resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
nlmsg_free(nl_msg);
|
||||||
|
VIR_FREE(resp);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
malformed_resp:
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("malformed netlink response message"));
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
buffer_too_small:
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("allocated netlink buffer is too small"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
static int
|
||||||
|
virNetDevBridgeFDBAddDel(const virMacAddr *mac ATTRIBUTE_UNUSED,
|
||||||
|
const char *ifname ATTRIBUTE_UNUSED,
|
||||||
|
unsigned int fdbFlags ATTRIBUTE_UNUSED,
|
||||||
|
bool isAdd ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
virReportSystemError(ENOSYS, "%s",
|
||||||
|
_("Unable to add/delete fdb entries on this platform"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
virNetDevBridgeFDBAdd(const virMacAddr *mac, const char *ifname,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
return virNetDevBridgeFDBAddDel(mac, ifname, flags, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
virNetDevBridgeFDBDel(const virMacAddr *mac, const char *ifname,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
return virNetDevBridgeFDBAddDel(mac, ifname, flags, false);
|
||||||
|
}
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
# define __VIR_NETDEV_BRIDGE_H__
|
# define __VIR_NETDEV_BRIDGE_H__
|
||||||
|
|
||||||
# include "internal.h"
|
# include "internal.h"
|
||||||
|
# include "virmacaddr.h"
|
||||||
|
|
||||||
int virNetDevBridgeCreate(const char *brname)
|
int virNetDevBridgeCreate(const char *brname)
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||||
@ -77,4 +78,19 @@ int virNetDevBridgePortSetUnicastFlood(const char *brname,
|
|||||||
bool enable)
|
bool enable)
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
VIR_NETDEVBRIDGE_FDB_FLAG_ROUTER = (1 << 0),
|
||||||
|
VIR_NETDEVBRIDGE_FDB_FLAG_SELF = (1 << 1),
|
||||||
|
VIR_NETDEVBRIDGE_FDB_FLAG_MASTER = (1 << 2),
|
||||||
|
|
||||||
|
VIR_NETDEVBRIDGE_FDB_FLAG_PERMANENT = (1 << 3),
|
||||||
|
VIR_NETDEVBRIDGE_FDB_FLAG_TEMP = (1 << 4),
|
||||||
|
} virNetDevBridgeFDBFlags;
|
||||||
|
|
||||||
|
int virNetDevBridgeFDBAdd(const virMacAddr *mac, const char *ifname,
|
||||||
|
unsigned int flags)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
int virNetDevBridgeFDBDel(const virMacAddr *mac, const char *ifname,
|
||||||
|
unsigned int flags)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||||
#endif /* __VIR_NETDEV_BRIDGE_H__ */
|
#endif /* __VIR_NETDEV_BRIDGE_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user