Please find comments inline. Thanks, Eitan -----Original Message----- From: dev [mailto:dev-boun...@openvswitch.org] On Behalf Of Ankur Sharma Sent: Wednesday, September 24, 2014 12:16 AM To: dev@openvswitch.org Subject: [ovs-dev] [PATCH v1 07/10] datapath-windows/Flow.c: FLOW_NEW command handler.
This patch covers the changes needed to support FLOW_NEW command. API _OvsFlowMapNlToFlowPutFlags has a bug, which will be fixed with the patches for FLOW_DEL. --- datapath-windows/include/OvsPub.h | 2 +- datapath-windows/ovsext/Flow.c | 384 +++++++++++++++++++++++++++++++++++--- datapath-windows/ovsext/Flow.h | 6 +- 3 files changed, 366 insertions(+), 26 deletions(-) diff --git a/datapath-windows/include/OvsPub.h b/datapath-windows/include/OvsPub.h index 36814c4..fa1d6d4 100644 --- a/datapath-windows/include/OvsPub.h +++ b/datapath-windows/include/OvsPub.h @@ -420,7 +420,7 @@ typedef struct OvsFlowPut { uint32_t actionsLen; OvsFlowKey key; uint32_t flags; - NL_ATTR actions[0]; /* Variable length indicated by actionsLen. */ + PNL_ATTR actions; } OvsFlowPut; #define OVS_MIN_PACKET_SIZE 60 diff --git a/datapath-windows/ovsext/Flow.c b/datapath-windows/ovsext/Flow.c index 25b39c1..e170de6 100644 --- a/datapath-windows/ovsext/Flow.c +++ b/datapath-windows/ovsext/Flow.c @@ -46,6 +46,20 @@ static VOID DeleteAllFlows(OVS_DATAPATH *datapath); static NTSTATUS AddFlow(OVS_DATAPATH *datapath, OvsFlow *flow); static VOID FreeFlow(OvsFlow *flow); static VOID __inline *GetStartAddrNBL(const NET_BUFFER_LIST *_pNB); +static NTSTATUS _OvsFlowMapNlToFlowPut(POVS_MESSAGE msgIn, PNL_ATTR keyAttr, + PNL_ATTR actionAttr, + PNL_ATTR flowAttrClear, + OvsFlowPut *mappedFlow); static +VOID _OvsFlowMapKeyAttrToFlowPut(PNL_ATTR *keyAttrs, + PNL_ATTR *tunnelAttrs, + OvsFlowPut *mappedFlow); + +static VOID _OvsFlowMapTunAttrToFlowPut(PNL_ATTR *keyAttrs, + PNL_ATTR *tunnelAttrs, + OvsFlowKey *destKey); static +VOID _OvsFlowMapNlToFlowPutFlags(PGENL_MSG_HDR genlMsgHdr, + PNL_ATTR flowAttrClear, + OvsFlowPut *mappedFlow); #define OVS_FLOW_TABLE_SIZE 2048 #define OVS_FLOW_TABLE_MASK (OVS_FLOW_TABLE_SIZE -1) @@ -191,20 +205,365 @@ static const NL_POLICY nlFlowActionPolicy[] = { * Netlink interface for flow commands. *---------------------------------------------------------------------------- */ + +/* + +*---------------------------------------------------------------------- +------ + * OvsFlowNlNewCmdHandler -- + * Handler for OVS_FLOW_CMD_NEW command. + +*---------------------------------------------------------------------- +------ + */ NTSTATUS OvsFlowNlNewCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx, UINT32 *replyLen) { NTSTATUS rc = STATUS_SUCCESS; + POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer; + POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer; + PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg); + PGENL_MSG_HDR genlMsgHdr = &(msgIn->genlMsg); + POVS_HDR ovsHdr = &(msgIn->ovsHdr); + PNL_ATTR nlAttrs[__OVS_FLOW_ATTR_MAX]; + UINT32 attrOffset = NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN; + POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE) + usrParamsCtx->ovsInstance; + OvsFlowPut mappedFlow; + OvsFlowStats stats; + struct ovs_flow_stats replyStats; + + NL_BUFFER nlBuf; + + UNREFERENCED_PARAMETER(genlMsgHdr); + UNREFERENCED_PARAMETER(ovsHdr); + UNREFERENCED_PARAMETER(instance); + + RtlZeroMemory(&mappedFlow, sizeof(OvsFlowPut)); + RtlZeroMemory(&stats, sizeof(stats)); + RtlZeroMemory(&replyStats, sizeof(replyStats)); + + *replyLen = 0; + + /* Get all the top level Flow attributes */ + if ((NlAttrParse(nlMsgHdr, attrOffset, NlMsgAttrLen(nlMsgHdr), + nlFlowPolicy, nlAttrs, ARRAY_SIZE(nlAttrs))) + != TRUE) { + OVS_LOG_ERROR("Attr Parsing failed for msg: %p", + nlMsgHdr); + rc = NDIS_STATUS_FAILURE; [EITAN] Please use nt status return code STATUS_UNSUCCESSFUL [EITAN] + goto done; + } + + if ((_OvsFlowMapNlToFlowPut(msgIn, nlAttrs[OVS_FLOW_ATTR_KEY], + nlAttrs[OVS_FLOW_ATTR_ACTIONS], nlAttrs[OVS_FLOW_ATTR_CLEAR], + &mappedFlow)) + != NDIS_STATUS_SUCCESS) { [EITAN] Please use nt status return code STATUS_UNSUCCESSFUL [EITAN] + OVS_LOG_ERROR("Conversion to OvsFlowPut failed"); + goto done; + } + + rc = OvsPutFlowIoctl(&mappedFlow, sizeof (struct OvsFlowPut), + &stats); + if (rc != STATUS_SUCCESS) { + OVS_LOG_ERROR("OvsFlowPut failed."); + goto done; + } + + if (!(usrParamsCtx->outputBuffer)) { + /* No output buffer */ + OVS_LOG_ERROR("outputBuffer NULL."); + goto done; + } + + replyStats.n_packets = stats.packetCount; + replyStats.n_bytes = stats.byteCount; + + /* So far so good. Prepare the reply for userspace */ + NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, + usrParamsCtx->outputLength); + + /* Prepare nl Msg headers */ + rc = NlFillOvsMsg(msgOut, &nlBuf, nlMsgHdr->nlmsgType, 0, + nlMsgHdr->nlmsgSeq, nlMsgHdr->nlmsgPid, + genlMsgHdr->cmd, OVS_FLOW_VERSION, + ovsHdr->dp_ifindex); + ASSERT(rc); + + /* Append OVS_FLOW_ATTR_STATS attribute */ + if (!NlMsgPutTailUnspec(&nlBuf, OVS_FLOW_ATTR_STATS, + (PCHAR)(&replyStats), sizeof(replyStats))) { + OVS_LOG_ERROR("Adding OVS_FLOW_ATTR_STATS attribute failed."); + rc = NDIS_STATUS_FAILURE; [EITAN] Please use nt status return code STATUS_UNSUCCESSFUL [EITAN] + } + + *replyLen = msgOut->nlMsg.nlmsgLen; + +done: + return rc; +} + +/* + +*---------------------------------------------------------------------- +------ + * _OvsFlowMapNlToFlowPut -- + * Maps input netlink message to OvsFlowPut. + +*---------------------------------------------------------------------- +------ + */ +static NTSTATUS +_OvsFlowMapNlToFlowPut(POVS_MESSAGE msgIn, PNL_ATTR keyAttr, + PNL_ATTR actionAttr, PNL_ATTR flowAttrClear, + OvsFlowPut *mappedFlow) { + NTSTATUS rc = NDIS_STATUS_SUCCESS; + PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg); + PGENL_MSG_HDR genlMsgHdr = &(msgIn->genlMsg); + POVS_HDR ovsHdr = &(msgIn->ovsHdr); + + UINT32 keyAttrOffset = (UINT32)((PCHAR)keyAttr - (PCHAR)nlMsgHdr); + UINT32 tunnelKeyAttrOffset; + + PNL_ATTR keyAttrs[__OVS_KEY_ATTR_MAX] = {NULL}; + PNL_ATTR tunnelAttrs[__OVS_TUNNEL_KEY_ATTR_MAX] = {NULL}; + + UNREFERENCED_PARAMETER(ovsHdr); + UNREFERENCED_PARAMETER(tunnelKeyAttrOffset); + + /* Get flow keys attributes */ + if ((NlAttrParseNested(nlMsgHdr, keyAttrOffset, NlAttrLen(keyAttr), + nlFlowKeyPolicy, keyAttrs, ARRAY_SIZE(keyAttrs))) + != TRUE) { + OVS_LOG_ERROR("Key Attr Parsing failed for msg: %p", + nlMsgHdr); + rc = NDIS_STATUS_FAILURE; [EITAN] Please use nt status return code STATUS_UNSUCCESSFUL [EITAN] + goto done; + } + + if (keyAttrs[OVS_KEY_ATTR_TUNNEL]) { + tunnelKeyAttrOffset = (UINT32)((PCHAR) + (keyAttrs[OVS_KEY_ATTR_TUNNEL]) + - (PCHAR)nlMsgHdr); + + OVS_LOG_ERROR("Parse Flow Tunnel Key Policy"); + + /* Get tunnel keys attributes */ + if ((NlAttrParseNested(nlMsgHdr, tunnelKeyAttrOffset, + NlAttrLen(keyAttr), nlFlowTunnelKeyPolicy, + tunnelAttrs, ARRAY_SIZE(tunnelAttrs))) + != TRUE) { + OVS_LOG_ERROR("Tunnel key Attr Parsing failed for msg: %p", + nlMsgHdr); + rc = NDIS_STATUS_FAILURE; [EITAN] Please use nt status return code STATUS_UNSUCCESSFUL [EITAN] + goto done; + } + } + + _OvsFlowMapKeyAttrToFlowPut(keyAttrs, tunnelAttrs, + mappedFlow); + + /* Map the action */ + mappedFlow->actionsLen = NlAttrGetSize(actionAttr); + mappedFlow->actions = NlAttrGet(actionAttr); + mappedFlow->dpNo = ovsHdr->dp_ifindex; - UNREFERENCED_PARAMETER(usrParamsCtx); - UNREFERENCED_PARAMETER(replyLen); + _OvsFlowMapNlToFlowPutFlags(genlMsgHdr, flowAttrClear, + mappedFlow); +done: return rc; } /* *---------------------------------------------------------------------------- + * _OvsFlowMapNlToFlowPutFlags -- + * Maps netlink message to OvsFlowPut->flags. + +*---------------------------------------------------------------------- +------ + */ +static VOID +_OvsFlowMapNlToFlowPutFlags(PGENL_MSG_HDR genlMsgHdr, PNL_ATTR flowAttrClear, + OvsFlowPut *mappedFlow) { + uint32_t flags = 0; + + switch (genlMsgHdr->cmd) { + case OVS_FLOW_CMD_NEW: + flags |= OVSWIN_FLOW_PUT_CREATE; [EITAN] Can we use just the assignment ? flags = OVSWIN_FLOW_PUT_CREATE; [EITAN] + break; + case OVS_FLOW_CMD_DEL: + flags |= OVSWIN_FLOW_PUT_DELETE; + break; + case OVS_FLOW_CMD_SET: + flags |= OVSWIN_FLOW_PUT_MODIFY; + break; + default: + ASSERT(0); + } + + if (flowAttrClear) { + flags |= OVSWIN_FLOW_PUT_CLEAR; + } + + mappedFlow->flags = flags; +} + +/* + +*---------------------------------------------------------------------- +------ + * _OvsFlowMapKeyAttrToFlowPut -- + * Converts FLOW_KEY attribute to OvsFlowPut->key. + +*---------------------------------------------------------------------- +------ + */ +static VOID +_OvsFlowMapKeyAttrToFlowPut(PNL_ATTR *keyAttrs, + PNL_ATTR *tunnelAttrs, + OvsFlowPut *mappedFlow) { + const struct ovs_key_ethernet *eth_key; + OvsFlowKey *destKey = &(mappedFlow->key); + + _OvsFlowMapTunAttrToFlowPut(keyAttrs, tunnelAttrs, destKey); + + /* ===== L2 headers ===== */ + destKey->l2.inPort = NlAttrGetU32(keyAttrs[OVS_KEY_ATTR_IN_PORT]); + eth_key = NlAttrGet(keyAttrs[OVS_KEY_ATTR_ETHERNET]); + memcpy(destKey->l2.dlSrc, eth_key->eth_src, ETH_ADDR_LEN); + memcpy(destKey->l2.dlDst, eth_key->eth_dst, ETH_ADDR_LEN); + + destKey->l2.dlType = ntohs((NlAttrGetU16(keyAttrs + [OVS_KEY_ATTR_ETHERTYPE]))); + + if (keyAttrs[OVS_KEY_ATTR_VLAN]) { + destKey->l2.vlanTci = NlAttrGetU16(keyAttrs + [OVS_KEY_ATTR_VLAN]); + } + + /* ==== L3 + L4. ==== */ + destKey->l2.keyLen = OVS_WIN_TUNNEL_KEY_SIZE + OVS_L2_KEY_SIZE + - destKey->l2.offset; + + switch (destKey->l2.dlType) { + case ETH_TYPE_IPV4: { + const struct ovs_key_ipv4 *ipv4Key; + const struct ovs_key_tcp *tcpKey; + + ipv4Key = NlAttrGet(keyAttrs[OVS_KEY_ATTR_IPV4]); + + IpKey *ipv4FlowPutKey = &(destKey->ipKey); + + ipv4FlowPutKey->nwSrc = ipv4Key->ipv4_src; + ipv4FlowPutKey->nwDst = ipv4Key->ipv4_dst; + ipv4FlowPutKey->nwProto = ipv4Key->ipv4_proto; + ipv4FlowPutKey->nwTos = ipv4Key->ipv4_tos; + ipv4FlowPutKey->nwTtl = ipv4Key->ipv4_ttl; + ipv4FlowPutKey->nwFrag = ipv4Key->ipv4_frag; + + if (keyAttrs[OVS_KEY_ATTR_TCP]) { + tcpKey = NlAttrGet(keyAttrs[OVS_KEY_ATTR_TCP]); + ipv4FlowPutKey->l4.tpSrc = tcpKey->tcp_src; + ipv4FlowPutKey->l4.tpDst = tcpKey->tcp_dst; + } + + destKey->l2.keyLen += OVS_IP_KEY_SIZE; + break; + } + case ETH_TYPE_IPV6: { + const struct ovs_key_ipv6 *ipv6Key; + const struct ovs_key_tcp *tcpKey; + + ipv6Key = NlAttrGet(keyAttrs[OVS_KEY_ATTR_IPV6]); + + Ipv6Key *ipv6FlowPutKey = &(destKey->ipv6Key); + + memcpy(&ipv6FlowPutKey->ipv6Src, ipv6Key->ipv6_src, sizeof ipv6Key->ipv6_src); + memcpy(&ipv6FlowPutKey->ipv6Dst, ipv6Key->ipv6_dst, sizeof ipv6Key->ipv6_dst); + ipv6FlowPutKey->ipv6Label = ipv6Key->ipv6_label; + ipv6FlowPutKey->nwProto = ipv6Key->ipv6_proto; + ipv6FlowPutKey->nwTos = ipv6Key->ipv6_tclass; + ipv6FlowPutKey->nwTtl = ipv6Key->ipv6_hlimit; + + ipv6FlowPutKey->nwFrag = ipv6Key->ipv6_frag; + + if (keyAttrs[OVS_KEY_ATTR_TCP]) { + tcpKey = NlAttrGet(keyAttrs[OVS_KEY_ATTR_TCP]); + ipv6FlowPutKey->l4.tpSrc = tcpKey->tcp_src; + ipv6FlowPutKey->l4.tpDst = tcpKey->tcp_dst; + } + + ipv6FlowPutKey->pad = 0; + + if (ipv6Key->ipv6_proto == IPPROTO_ICMPV6) { + const struct ovs_key_nd *ndKey; + Icmp6Key *icmp6FlowPutKey= &(destKey->icmp6Key); + + ndKey = NlAttrGet(keyAttrs[OVS_KEY_ATTR_ND]); + + memcpy(&icmp6FlowPutKey->ndTarget, ndKey->nd_target, + sizeof (icmp6FlowPutKey->ndTarget)); + memcpy(icmp6FlowPutKey->arpSha, ndKey->nd_sll, ETH_ADDR_LEN); + memcpy(icmp6FlowPutKey->arpTha, ndKey->nd_tll, + ETH_ADDR_LEN); + + destKey->l2.keyLen += OVS_ICMPV6_KEY_SIZE; + } else { + destKey->l2.keyLen += OVS_IPV6_KEY_SIZE; + } + break; + } + case ETH_TYPE_ARP: + case ETH_TYPE_RARP: { + ArpKey *arpFlowPutKey = &destKey->arpKey; + const struct ovs_key_arp *arpKey; + + arpKey = NlAttrGet(keyAttrs[OVS_KEY_ATTR_ARP]); + + arpFlowPutKey->nwSrc = arpKey->arp_sip; + arpFlowPutKey->nwDst = arpKey->arp_tip; + + memcpy(arpFlowPutKey->arpSha, arpKey->arp_sha, ETH_ADDR_LEN); + memcpy(arpFlowPutKey->arpTha, arpKey->arp_tha, ETH_ADDR_LEN); + arpFlowPutKey->nwProto = (UINT8)(arpKey->arp_op); + arpFlowPutKey->pad[0] = 0; + arpFlowPutKey->pad[1] = 0; + arpFlowPutKey->pad[2] = 0; + destKey->l2.keyLen += OVS_ARP_KEY_SIZE; + break; + } + } +} + +/* + +*---------------------------------------------------------------------- +------ + * _OvsFlowMapTunAttrToFlowPut -- + * Converts FLOW_TUNNEL_KEY attribute to OvsFlowKey->tunKey. + +*---------------------------------------------------------------------- +------ + */ +static VOID +_OvsFlowMapTunAttrToFlowPut(PNL_ATTR *keyAttrs, + PNL_ATTR *tunAttrs, + OvsFlowKey *destKey) { + if (keyAttrs[OVS_KEY_ATTR_TUNNEL]) { + destKey->tunKey.tunnelId = NlAttrGetU64 + (tunAttrs[OVS_TUNNEL_KEY_ATTR_ID]); + destKey->tunKey.dst = NlAttrGetU32 + (tunAttrs[OVS_TUNNEL_KEY_ATTR_IPV4_DST]); + destKey->tunKey.src = NlAttrGetU32 + (tunAttrs[OVS_TUNNEL_KEY_ATTR_IPV4_SRC]); + + /* XXX: There are no attributes to specify tunnel flags. + * Also, i do not see these flags being used anywhere in + * flowPut code. */ + destKey->tunKey.flags = 0; + destKey->tunKey.tos = NlAttrGetU8 + (tunAttrs[OVS_TUNNEL_KEY_ATTR_TOS]); + destKey->tunKey.ttl = NlAttrGetU8 + (tunAttrs[OVS_TUNNEL_KEY_ATTR_TTL]); + destKey->tunKey.pad = 0; + destKey->l2.offset = 0; + } else { + destKey->tunKey.attr[0] = 0; + destKey->tunKey.attr[1] = 0; + destKey->tunKey.attr[2] = 0; + destKey->l2.offset = sizeof destKey->tunKey; + } +} + +/* + +*---------------------------------------------------------------------- +------ * OvsDeleteFlowTable -- * Results: * NDIS_STATUS_SUCCESS always. @@ -837,13 +1196,10 @@ ReportFlowInfo(OvsFlow *flow, NTSTATUS OvsPutFlowIoctl(PVOID inputBuffer, UINT32 inputLength, - PVOID outputBuffer, - UINT32 outputLength, - UINT32 *replyLen) + struct OvsFlowStats *stats) { NTSTATUS status = STATUS_SUCCESS; OVS_DATAPATH *datapath = NULL; - struct OvsFlowStats stats; ULONG actionsLen; OvsFlowPut *put; UINT32 dpNo; @@ -853,19 +1209,12 @@ OvsPutFlowIoctl(PVOID inputBuffer, return STATUS_INFO_LENGTH_MISMATCH; } - if ((outputLength != sizeof(stats)) || (outputBuffer == NULL)) { - return STATUS_INFO_LENGTH_MISMATCH; - } - put = (OvsFlowPut *)inputBuffer; if (put->actionsLen > 0) { actionsLen = put->actionsLen; } else { actionsLen = 0; } - if (inputLength != actionsLen + sizeof(*put)) { - return STATUS_INFO_LENGTH_MISMATCH; - } dpNo = put->dpNo; NdisAcquireSpinLock(gOvsCtrlLock); @@ -877,17 +1226,10 @@ OvsPutFlowIoctl(PVOID inputBuffer, datapath = &gOvsSwitchContext->datapath; ASSERT(datapath); - RtlZeroMemory(&stats, sizeof(stats)); OvsAcquireDatapathWrite(datapath, &dpLockState, FALSE); - status = HandleFlowPut(put, datapath, &stats); + status = HandleFlowPut(put, datapath, stats); OvsReleaseDatapath(datapath, &dpLockState); - if (status == STATUS_SUCCESS) { - // Copy stats to User mode app - NdisMoveMemory(outputBuffer, (PVOID)&stats, sizeof(stats)); - *replyLen = sizeof stats; - } - unlock: NdisReleaseSpinLock(gOvsCtrlLock); return status; diff --git a/datapath-windows/ovsext/Flow.h b/datapath-windows/ovsext/Flow.h index 602e567..e62ba40 100644 --- a/datapath-windows/ovsext/Flow.h +++ b/datapath-windows/ovsext/Flow.h @@ -64,16 +64,14 @@ NTSTATUS OvsDumpFlowIoctl(PVOID inputBuffer, UINT32 inputLength, PVOID outputBuffer, UINT32 outputLength, UINT32 *replyLen); NTSTATUS OvsPutFlowIoctl(PVOID inputBuffer, UINT32 inputLength, - PVOID outputBuffer, UINT32 outputLength, - UINT32 *replyLen); + struct OvsFlowStats *stats); NTSTATUS OvsGetFlowIoctl(PVOID inputBuffer, UINT32 inputLength, PVOID outputBuffer, UINT32 outputLength, UINT32 *replyLen); NTSTATUS OvsFlushFlowIoctl(PVOID inputBuffer, UINT32 inputLength); NTSTATUS OvsFlowNlNewCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx, - UINT32 *replyLen); - + UINT32 *replyLen); /* Flags for tunneling */ #define OVS_TNL_F_DONT_FRAGMENT (1 << 0) -- 1.9.1 _______________________________________________ dev mailing list dev@openvswitch.org https://urldefense.proofpoint.com/v1/url?u=http://openvswitch.org/mailman/listinfo/dev&k=oIvRg1%2BdGAgOoM1BIlLLqw%3D%3D%0A&r=yTvML8OxA42Jb6ViHe7fUXbvPVOYDPVq87w43doxtlY%3D%0A&m=onRzZAcTog7vmdZ17oWpXWJqMvOA%2FHmSHhdE6yiKZ1Q%3D%0A&s=c50545cc1c74277f9672ffc5277fed56f34e96fa0a19ab11e9d2bbc468852ea0 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev