Thanks for doing this. Looks good but for a few cosmetic comments. Also, remember to flip the protocol for nf sockets in userspace to NETLINK_NETFILTER. IIRC, we use NETLINK_GENERIC.
Acked-by: Nithin Raju <nit...@vmware.com> -----Original Message----- From: dev <dev-boun...@openvswitch.org> on behalf of Sairam Venugopal <vsai...@vmware.com> Date: Thursday, July 7, 2016 at 6:14 PM To: "dev@openvswitch.org" <dev@openvswitch.org> Subject: [ovs-dev] [PATCH] 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 <vsai...@vmware.com> >--- > datapath-windows/include/OvsDpInterfaceExt.h | 15 +++- > datapath-windows/ovsext/Datapath.c | 102 >++++++++++++++++++++++++++- > datapath-windows/ovsext/Datapath.h | 1 + > lib/netlink-socket.c | 75 ++++++++++++++++++++ > 4 files changed, 191 insertions(+), 2 deletions(-) > >diff --git a/datapath-windows/include/OvsDpInterfaceExt.h >b/datapath-windows/include/OvsDpInterfaceExt.h >index 8850535..e75ce28 100644 >--- a/datapath-windows/include/OvsDpInterfaceExt.h >+++ b/datapath-windows/include/OvsDpInterfaceExt.h >@@ -94,7 +94,10 @@ enum ovs_win_control_cmd { > > /* This command is logically belong to the Vport family */ minor: ³is logically belong² => ³logically belongs² (not your code) > 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_ */ >diff --git a/datapath-windows/ovsext/Datapath.c >b/datapath-windows/ovsext/Datapath.c >index 16d58ef..210184d 100644 >--- a/datapath-windows/ovsext/Datapath.c >+++ b/datapath-windows/ovsext/Datapath.c >@@ -87,7 +87,8 @@ static NetlinkCmdHandler OvsPendEventCmdHandler, > OvsReadEventCmdHandler, > OvsNewDpCmdHandler, > OvsGetDpCmdHandler, >- OvsSetDpCmdHandler; >+ OvsSetDpCmdHandler, >+ OvsManageSocketProperty; Minor: All NL handlers are called: *CmdHandler. So, maybe 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 = OvsManageSocketProperty, >+ .supportedDevOp = OVS_TRANSACTION_DEV_OP, >+ .validateDpIndex = FALSE, > } > }; > >@@ -1685,3 +1691,97 @@ 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 >+OvsManageSocketProperty(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; >+ } minor: align arg #2 onwards either 4 spaces to the right or along the same level as arg #1. >+ >+ /* 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; >+} >diff --git a/datapath-windows/ovsext/Datapath.h >b/datapath-windows/ovsext/Datapath.h >index 09e233f..2b41d82 100644 >--- a/datapath-windows/ovsext/Datapath.h >+++ b/datapath-windows/ovsext/Datapath.h >@@ -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. >*/ >diff --git a/lib/netlink-socket.c b/lib/netlink-socket.c >index 32b0cc3..51375d4 100644 >--- a/lib/netlink-socket.c >+++ b/lib/netlink-socket.c >@@ -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]) { minor: whitespace needed after Œif' >+ int protocol = nl_attr_get_be32(attrs[OVS_NL_ATTR_SOCK_PROTO]); >+ if(protocol != sock->protocol) { minor: whitespace needed after Œif' >+ VLOG_ERR("Invalid protocol returned:%d expected:%d", >+ protocol, sock->protocol); >+ retval = EINVAL; >+ } >+ } >+ >+ if(attrs[OVS_NL_ATTR_SOCK_PID]) { minor: whitespace needed after Œif' >+ int pid = nl_attr_get_be32(attrs[OVS_NL_ATTR_SOCK_PID]); >+ if(pid != sock->pid) { minor: whitespace needed after Œif' >+ VLOG_ERR("Invalid pid returned:%d expected:%d", >+ pid, sock->pid); >+ retval = EINVAL; >+ } >+ } >+ >+ return retval; >+} > #endif /* _WIN32 */ > > #ifdef _WIN32 >-- >2.9.0.windows.1 > >_______________________________________________ >dev mailing list >dev@openvswitch.org >https://urldefense.proofpoint.com/v2/url?u=http-3A__openvswitch.org_mailma >n_listinfo_dev&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=pN >HQcdr7B40b4h6Yb7FIedI1dnBsxdDuTLBYD3JqV80&m=5RKcCre7K3WdKv0m8O_a7zgr-B9prf >gWhRJcc2afLps&s=hSVROJkjb846dj_5qSkSX-nXy_aghVtbqHu1cF40KjM&e= _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev