mirror of
https://github.com/openvswitch/ovs
synced 2025-10-23 14:57:06 +00:00
Windows: Add support for handling protocol (netlink family)
Windows datapath currently has no notion of netlink family. It assumes all netlink messages to belong to NETLINK_GENERIC family. This patch adds support for handling other protocols if the userspace sends it down to kernel. This patch introduces a new NETLINK_CMD - OVS_CTRL_CMD_SOCK_PROP to manage all properties associated with a socket. The properties are passed down as netlink message attributes. This makes it easier to introduce other properties in the future. Signed-off-by: Sairam Venugopal <vsairam@vmware.com> Acked-by: Nithin Raju <nithin@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
This commit is contained in:
committed by
Gurucharan Shetty
parent
1e25f5caef
commit
e70f55edbc
@@ -92,9 +92,12 @@ enum ovs_win_control_cmd {
|
||||
OVS_CTRL_CMD_MC_SUBSCRIBE_REQ,
|
||||
OVS_CTRL_CMD_PACKET_SUBSCRIBE_REQ,
|
||||
|
||||
/* This command is logically belong to the Vport family */
|
||||
/* This command logically belongs to the Vport family */
|
||||
OVS_CTRL_CMD_EVENT_NOTIFY,
|
||||
OVS_CTRL_CMD_READ_NOTIFY
|
||||
OVS_CTRL_CMD_READ_NOTIFY,
|
||||
|
||||
/* Used for Socket property */
|
||||
OVS_CTRL_CMD_SOCK_PROP
|
||||
};
|
||||
|
||||
/* NL Attributes for joining/unjoining an MC group */
|
||||
@@ -163,4 +166,14 @@ enum ovs_win_netdev_attr {
|
||||
typedef struct ovs_dp_stats OVS_DP_STATS;
|
||||
typedef enum ovs_vport_type OVS_VPORT_TYPE;
|
||||
|
||||
/* NL Attributes for setting socket attributes */
|
||||
enum ovs_nl_sock_attr {
|
||||
/* (UINT32) Netlink Protocol set in Userspace and read in Kernel */
|
||||
OVS_NL_ATTR_SOCK_PROTO,
|
||||
/* (UINT32) Instance PID set in Kernel and read in Userspace */
|
||||
OVS_NL_ATTR_SOCK_PID,
|
||||
__OVS_NL_ATTR_SOCK_MAX
|
||||
};
|
||||
#define OVS_WIN_SOCK_ATTR_MAX (__OVS_NL_ATTR_SOCK_MAX - 1)
|
||||
|
||||
#endif /* __OVS_DP_INTERFACE_EXT_H_ */
|
||||
|
||||
@@ -87,7 +87,8 @@ static NetlinkCmdHandler OvsPendEventCmdHandler,
|
||||
OvsReadEventCmdHandler,
|
||||
OvsNewDpCmdHandler,
|
||||
OvsGetDpCmdHandler,
|
||||
OvsSetDpCmdHandler;
|
||||
OvsSetDpCmdHandler,
|
||||
OvsSockPropCmdHandler;
|
||||
|
||||
NetlinkCmdHandler OvsGetNetdevCmdHandler,
|
||||
OvsGetVportCmdHandler,
|
||||
@@ -147,6 +148,11 @@ NETLINK_CMD nlControlFamilyCmdOps[] = {
|
||||
.handler = OvsReadPacketCmdHandler,
|
||||
.supportedDevOp = OVS_READ_DEV_OP,
|
||||
.validateDpIndex = FALSE,
|
||||
},
|
||||
{ .cmd = OVS_CTRL_CMD_SOCK_PROP,
|
||||
.handler = OvsSockPropCmdHandler,
|
||||
.supportedDevOp = OVS_TRANSACTION_DEV_OP,
|
||||
.validateDpIndex = FALSE,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1685,3 +1691,99 @@ OvsReadEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
|
||||
cleanup:
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* --------------------------------------------------------------------------
|
||||
* Command Handler for 'OVS_CTRL_CMD_SOCK_PROP'.
|
||||
*
|
||||
* Handler to set and verify socket properties between userspace and kernel.
|
||||
*
|
||||
* Protocol is passed down by the userspace. It refers to the NETLINK family
|
||||
* and could be of different types (NETLINK_GENERIC/NETLINK_NETFILTER etc.,)
|
||||
* This function parses out the protocol and adds it to the open instance.
|
||||
*
|
||||
* PID is generated by the kernel and is set in userspace after querying the
|
||||
* kernel for it. This function does not modify PID set in the kernel,
|
||||
* instead it verifies if it was sent down correctly.
|
||||
*
|
||||
* XXX -This method can be modified to handle all Socket properties thereby
|
||||
* eliminating the use of OVS_IOCTL_GET_PID
|
||||
*
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
static NTSTATUS
|
||||
OvsSockPropCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
|
||||
UINT32 *replyLen)
|
||||
{
|
||||
static const NL_POLICY ovsSocketPolicy[] = {
|
||||
[OVS_NL_ATTR_SOCK_PROTO] = { .type = NL_A_U32, .optional = TRUE },
|
||||
[OVS_NL_ATTR_SOCK_PID] = { .type = NL_A_U32, .optional = TRUE }
|
||||
};
|
||||
PNL_ATTR attrs[ARRAY_SIZE(ovsSocketPolicy)];
|
||||
|
||||
if (usrParamsCtx->outputLength < sizeof(OVS_MESSAGE)) {
|
||||
return STATUS_NDIS_INVALID_LENGTH;
|
||||
}
|
||||
|
||||
NL_BUFFER nlBuf;
|
||||
POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
|
||||
POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
|
||||
POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
|
||||
UINT32 protocol;
|
||||
PNL_MSG_HDR nlMsg;
|
||||
UINT32 pid;
|
||||
|
||||
/* Parse the input */
|
||||
if (!NlAttrParse((PNL_MSG_HDR)msgIn,
|
||||
NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
|
||||
NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
|
||||
ovsSocketPolicy,
|
||||
ARRAY_SIZE(ovsSocketPolicy),
|
||||
attrs,
|
||||
ARRAY_SIZE(attrs))) {
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Set the Protocol if it was passed down */
|
||||
if (attrs[OVS_NL_ATTR_SOCK_PROTO]) {
|
||||
protocol = NlAttrGetU32(attrs[OVS_NL_ATTR_SOCK_PROTO]);
|
||||
if (protocol) {
|
||||
instance->protocol = protocol;
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify if the PID sent down matches the kernel */
|
||||
if (attrs[OVS_NL_ATTR_SOCK_PID]) {
|
||||
pid = NlAttrGetU32(attrs[OVS_NL_ATTR_SOCK_PID]);
|
||||
if (pid != instance->pid) {
|
||||
OVS_LOG_ERROR("Received invalid pid:%d expected:%d",
|
||||
pid, instance->pid);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
/* Prepare the output */
|
||||
NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength);
|
||||
if(!NlFillOvsMsg(&nlBuf, msgIn->nlMsg.nlmsgType, NLM_F_MULTI,
|
||||
msgIn->nlMsg.nlmsgSeq, msgIn->nlMsg.nlmsgPid,
|
||||
msgIn->genlMsg.cmd, msgIn->genlMsg.version,
|
||||
gOvsSwitchContext->dpNo)){
|
||||
return STATUS_INVALID_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
if (!NlMsgPutTailU32(&nlBuf, OVS_NL_ATTR_SOCK_PID,
|
||||
instance->pid)) {
|
||||
return STATUS_INVALID_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
if (!NlMsgPutTailU32(&nlBuf, OVS_NL_ATTR_SOCK_PROTO,
|
||||
instance->protocol)) {
|
||||
return STATUS_INVALID_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuf, 0, 0);
|
||||
nlMsg->nlmsgLen = NlBufSize(&nlBuf);
|
||||
*replyLen = msgOut->nlMsg.nlmsgLen;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ typedef struct _OVS_OPEN_INSTANCE {
|
||||
PVOID eventQueue;
|
||||
POVS_USER_PACKET_QUEUE packetQueue;
|
||||
UINT32 pid;
|
||||
UINT32 protocol; /* Refers to NETLINK Family (eg. NETLINK_GENERIC)*/
|
||||
|
||||
struct {
|
||||
POVS_MESSAGE ovsMsg; /* OVS message passed during dump start. */
|
||||
|
||||
@@ -59,6 +59,7 @@ static void log_nlmsg(const char *function, int error,
|
||||
const void *message, size_t size, int protocol);
|
||||
#ifdef _WIN32
|
||||
static int get_sock_pid_from_kernel(struct nl_sock *sock);
|
||||
static int set_sock_property(struct nl_sock *sock);
|
||||
#endif
|
||||
|
||||
/* Netlink sockets. */
|
||||
@@ -165,6 +166,10 @@ nl_sock_create(int protocol, struct nl_sock **sockp)
|
||||
if (retval != 0) {
|
||||
goto error;
|
||||
}
|
||||
retval = set_sock_property(sock);
|
||||
if (retval != 0) {
|
||||
goto error;
|
||||
}
|
||||
#else
|
||||
if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUFFORCE,
|
||||
&rcvbuf, sizeof rcvbuf)) {
|
||||
@@ -284,6 +289,76 @@ get_sock_pid_from_kernel(struct nl_sock *sock)
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Used for setting and managing socket properties in userspace and kernel.
|
||||
* Currently two attributes are tracked - pid and protocol
|
||||
* protocol - supplied by userspace based on the netlink family. Windows uses
|
||||
* this property to set the value in kernel datapath.
|
||||
* eg: (NETLINK_GENERIC/ NETLINK_NETFILTER)
|
||||
* pid - generated by windows kernel and set in userspace. The property
|
||||
* is not modified.
|
||||
* Also verify if Protocol and PID in Kernel reflects the values in userspace
|
||||
* */
|
||||
static int
|
||||
set_sock_property(struct nl_sock *sock)
|
||||
{
|
||||
static const struct nl_policy ovs_socket_policy[] = {
|
||||
[OVS_NL_ATTR_SOCK_PROTO] = { .type = NL_A_BE32, .optional = true },
|
||||
[OVS_NL_ATTR_SOCK_PID] = { .type = NL_A_BE32, .optional = true }
|
||||
};
|
||||
|
||||
struct ofpbuf request, *reply;
|
||||
struct ovs_header *ovs_header;
|
||||
struct nlattr *attrs[ARRAY_SIZE(ovs_socket_policy)];
|
||||
int retval = 0;
|
||||
int error;
|
||||
|
||||
ofpbuf_init(&request, 0);
|
||||
nl_msg_put_genlmsghdr(&request, 0, OVS_WIN_NL_CTRL_FAMILY_ID, 0,
|
||||
OVS_CTRL_CMD_SOCK_PROP, OVS_WIN_CONTROL_VERSION);
|
||||
ovs_header = ofpbuf_put_uninit(&request, sizeof *ovs_header);
|
||||
ovs_header->dp_ifindex = 0;
|
||||
|
||||
nl_msg_put_be32(&request, OVS_NL_ATTR_SOCK_PROTO, sock->protocol);
|
||||
/* pid is already set as part of get_sock_pid_from_kernel()
|
||||
* This is added to maintain consistency
|
||||
*/
|
||||
nl_msg_put_be32(&request, OVS_NL_ATTR_SOCK_PID, sock->pid);
|
||||
|
||||
error = nl_sock_transact(sock, &request, &reply);
|
||||
ofpbuf_uninit(&request);
|
||||
if (error) {
|
||||
retval = EINVAL;
|
||||
}
|
||||
|
||||
if (!nl_policy_parse(reply,
|
||||
NLMSG_HDRLEN + GENL_HDRLEN + sizeof *ovs_header,
|
||||
ovs_socket_policy, attrs,
|
||||
ARRAY_SIZE(ovs_socket_policy))) {
|
||||
ofpbuf_delete(reply);
|
||||
retval = EINVAL;
|
||||
}
|
||||
/* Verify if the properties are setup properly */
|
||||
if (attrs[OVS_NL_ATTR_SOCK_PROTO]) {
|
||||
int protocol = nl_attr_get_be32(attrs[OVS_NL_ATTR_SOCK_PROTO]);
|
||||
if (protocol != sock->protocol) {
|
||||
VLOG_ERR("Invalid protocol returned:%d expected:%d",
|
||||
protocol, sock->protocol);
|
||||
retval = EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (attrs[OVS_NL_ATTR_SOCK_PID]) {
|
||||
int pid = nl_attr_get_be32(attrs[OVS_NL_ATTR_SOCK_PID]);
|
||||
if (pid != sock->pid) {
|
||||
VLOG_ERR("Invalid pid returned:%d expected:%d",
|
||||
pid, sock->pid);
|
||||
retval = EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
Reference in New Issue
Block a user