static BOOLEAN _CreateInPortArgInList(const OVS_OFPACKET_INFO* pPacketInfo, const OVS_OFPACKET_INFO* pMask, OVS_ARGUMENT_SLIST_ENTRY** ppArgList) { UINT32 inputPortValue = 0; if (pPacketInfo->physical.ovsInPort == OVS_INVALID_PORT_NUMBER) { if (pMask) { if (pMask->physical.ovsInPort == OVS_PI_MASK_MATCH_EXACT(UINT16)) { inputPortValue = OVS_PI_MASK_MATCH_EXACT(UINT32); } else { OVS_CHECK(__UNEXPECTED__); return TRUE; } } else { OVS_CHECK(__UNEXPECTED__); return TRUE; } } else { UINT16 highBits = 0; UINT16 ovsPortNumber = 0; if (pMask) { highBits = OVS_PI_MASK_MATCH_EXACT(UINT16); ovsPortNumber = pMask->physical.ovsInPort; } else { highBits = 0; ovsPortNumber = pPacketInfo->physical.ovsInPort; } inputPortValue = ovsPortNumber | (highBits << 16); } if (!CreateArgInList(OVS_ARGTYPE_PI_DP_INPUT_PORT, &inputPortValue, ppArgList)) { return FALSE; } return TRUE; }
static BOOLEAN _MasksFromArgs_HandleEncap(_In_ const OVS_ARGUMENT_GROUP* pMaskGroup, _Inout_ OVS_ARGUMENT* pEncapArg, _Inout_ OVS_ARGUMENT* pEtherTypeArg) { BE16 ethType = 0; BE16 vlanTci = 0; BOOLEAN ok = TRUE; OVS_ARGUMENT* pVlanTciArg = NULL; OVS_CHECK(pEncapArg); pEncapArg->isDisabled = TRUE; if (pEtherTypeArg) { ethType = GET_ARG_DATA(pEtherTypeArg, BE16); } else { DEBUGP(LOG_ERROR, "The eth type argument was not found\n"); return FALSE; } if (ethType == OVS_PI_MASK_MATCH_EXACT(UINT16)) { pEtherTypeArg->isDisabled = TRUE; } else { DEBUGP(LOG_ERROR, "The vlan frame must have an exact match for ethType. Mask value: %x.\n", RtlUshortByteSwap(ethType)); return FALSE; } pVlanTciArg = FindArgument(pMaskGroup, OVS_ARGTYPE_PI_VLAN_TCI); if (pVlanTciArg) { vlanTci = GET_ARG_DATA(pVlanTciArg, BE16); } else { DEBUGP(LOG_ERROR, "vlan tci arg not given"); return FALSE; } if (!(vlanTci & RtlUshortByteSwap(OVS_VLAN_TAG_PRESENT))) { DEBUGP(LOG_ERROR, "The vlan field 'tag present' bit must be exact match! Mask value: %x.\n", RtlUshortByteSwap(vlanTci)); return FALSE; } return ok; }
static BOOLEAN _GetPIFromArg_EthType(_Inout_ OVS_OFPACKET_INFO* pPacketInfo, _Inout_ OVS_PI_RANGE* pPiRange, _In_ const OVS_ARGUMENT* pEthTypeArg, _In_ BOOLEAN isMask) { BE16 ethType = GET_ARG_DATA(pEthTypeArg, BE16); if (isMask) { ethType = OVS_PI_MASK_MATCH_EXACT(UINT16); } if (!isMask) { EXPECT(RtlUshortByteSwap(ethType) >= OVS_ETHERTYPE_802_3_MIN); } OVS_PI_UPDATE_ETHINFO_FIELD(pPacketInfo, pPiRange, pEthTypeArg, BE16, type); return TRUE; }
static BOOLEAN _PIFromArg_DatapathInPort(_Inout_ OVS_OFPACKET_INFO* pPacketInfo, _Inout_ OVS_PI_RANGE* pPiRange, _In_ const OVS_ARGUMENT* pArg, BOOLEAN isMask) { UINT16 inPort = (UINT16)GET_ARG_DATA(pArg, UINT32); if (isMask) { inPort = OVS_PI_MASK_MATCH_EXACT(UINT16); } if (!isMask) { EXPECT(inPort < OVS_MAX_PORTS); } OVS_PI_UPDATE_PHYSICAL_FIELD_VALUE(pPacketInfo, pPiRange, ofInPort, inPort); return TRUE; }
BOOLEAN GetFlowMatchFromArguments(_Inout_ OVS_FLOW_MATCH* pFlowMatch, _In_ const OVS_ARGUMENT_GROUP* pPIGroup, const OVS_ARGUMENT_GROUP* pPIMaskGroup) { BOOLEAN encapIsValid = FALSE; BOOLEAN ok = TRUE; OVS_ARGUMENT* pEthTypeArg = NULL, *pEthAddrArg = NULL; OVS_PI_RANGE* pPiRange = NULL; OVS_OFPACKET_INFO* pPacketInfo = NULL; OVS_CHECK(pFlowMatch); if (!pFlowMatch) { return FALSE; } pEthTypeArg = FindArgument(pPIGroup, OVS_ARGTYPE_PI_ETH_TYPE); #if OVS_VERSION == OVS_VERSION_1_11 EXPECT(pEthAddrArg); #endif pEthAddrArg = FindArgument(pPIGroup, OVS_ARGTYPE_PI_ETH_ADDRESS); EXPECT(pEthAddrArg); if (pEthTypeArg && RtlUshortByteSwap(OVS_ETHERTYPE_QTAG) == GET_ARG_DATA(pEthTypeArg, BE16)) { if (!_PIFromArgs_HandleEncap(pPIGroup, pEthAddrArg, &encapIsValid)) { return FALSE; } } pPiRange = &pFlowMatch->piRange; pPacketInfo = pFlowMatch->pPacketInfo; ok = GetPacketInfoFromArguments(pPacketInfo, pPiRange, pPIGroup, /*isMask*/ FALSE); if (!ok) { return FALSE; } if (!pPIMaskGroup) { if (pFlowMatch->pFlowMask) { UINT8* pStart = (UINT8*)&pFlowMatch->pFlowMask->packetInfo + pPiRange->startRange; UINT16 range = (UINT16)(pPiRange->endRange - pPiRange->startRange); pFlowMatch->pFlowMask->piRange = *pPiRange; memset(pStart, OVS_PI_MASK_MATCH_EXACT(UINT8), range); } } else { OVS_ARGUMENT* pEncapArg = NULL; pEncapArg = FindArgument(pPIMaskGroup, OVS_ARGTYPE_PI_ENCAP_GROUP); if (pEncapArg) { if (!encapIsValid) { DEBUGP(LOG_ERROR, "Tryed to set encapsulation to non-vlan frame!\n"); return FALSE; } if (!pEthTypeArg || !_MasksFromArgs_HandleEncap(pPIMaskGroup, pEncapArg, pEthTypeArg)) { return FALSE; } } OVS_CHECK(pFlowMatch->pFlowMask); pPiRange = &pFlowMatch->pFlowMask->piRange; pPacketInfo = &pFlowMatch->pFlowMask->packetInfo; ok = GetPacketInfoFromArguments(pPacketInfo, pPiRange, pPIMaskGroup, /*is mask*/TRUE); if (!ok) { return FALSE; } } //if the userspace gives us bad / unexpected args, we cannot simply deny the flow: //a) this might not be a bug (i.e. the userspace intends to set flows like this) //b) if it is a bug, we can do little in the kernel to help it. #if __VERIFY_MASKS if (!_VerifyMasks(pFlowMatch, pPIGroup, pPIMaskGroup)) { return FALSE; } #endif return TRUE; }
static BOOLEAN _CreateEthernetArgsInList(const OVS_OFPACKET_INFO* pPacketInfo, const OVS_OFPACKET_INFO* pMask, OVS_ARGUMENT_SLIST_ENTRY** ppArgList, BOOLEAN* pEncapsulated) { OVS_PI_ETH_ADDRESS ethAddrPI = { 0 }; OVS_ETH_INFO ethInfo = { 0 }; OVS_CHECK(pEncapsulated); *pEncapsulated = FALSE; ethInfo = (pMask ? pMask->ethInfo : pPacketInfo->ethInfo); RtlCopyMemory(ethAddrPI.source, ethInfo.source, OVS_ETHERNET_ADDRESS_LENGTH); RtlCopyMemory(ethAddrPI.destination, ethInfo.destination, OVS_ETHERNET_ADDRESS_LENGTH); //ETH ADDRESS if (!CreateArgInList(OVS_ARGTYPE_PI_ETH_ADDRESS, ðAddrPI, ppArgList)) { DEBUGP(LOG_ERROR, __FUNCTION__ " failed appending eth addr key\n"); return FALSE; } if (pPacketInfo->ethInfo.type == RtlUshortByteSwap(OVS_ETHERTYPE_QTAG) || pPacketInfo->ethInfo.tci != 0) { BE16 ethType = 0; DEBUGP(LOG_INFO, "using encapsulation!\n"); *pEncapsulated = TRUE; if (!pMask) { ethType = RtlUshortByteSwap(OVS_ETHERTYPE_QTAG); } else { ethType = OVS_PI_MASK_MATCH_EXACT(UINT16); } //ETH TYPE if (!CreateArgInList(OVS_ARGTYPE_PI_ETH_TYPE, ðType, ppArgList)) //BE16 { DEBUGP(LOG_ERROR, __FUNCTION__ " failed appending vlan eth type\n"); return FALSE; } //VLAN TCI if (!CreateArgInList(OVS_ARGTYPE_PI_VLAN_TCI, ðInfo.tci, ppArgList)) //UINT16 { DEBUGP(LOG_ERROR, __FUNCTION__ " failed appending vlan tci\n"); return FALSE; } if (!pPacketInfo->ethInfo.tci) { DEBUGP(LOG_ERROR, __FUNCTION__ " -- have vlan tci but it is 0\n"); return FALSE; } if (!_CreateEncapsulationGroupToList(pPacketInfo, pMask, ppArgList)) { DEBUGP(LOG_ERROR, __FUNCTION__ " failed appending encapsulation group\n"); return FALSE; } return TRUE; } OVS_CHECK(pPacketInfo->ethInfo.type != RtlUshortByteSwap(OVS_ETHERTYPE_802_2)); if (!CreateArgInList(OVS_ARGTYPE_PI_ETH_TYPE, ðInfo.type, ppArgList)) //UINT16 { DEBUGP(LOG_ERROR, __FUNCTION__ " failed appending non-encaps eth type\n"); return FALSE; } return TRUE; }
static OVS_ARGUMENT* _CreateEncapsulationArg(const OVS_OFPACKET_INFO* pPacketInfo, const OVS_OFPACKET_INFO* pMask) { OVS_ARGUMENT_GROUP* pEncapsGroup = NULL; OVS_ARGUMENT* argArray = NULL, *pEncapsArg = NULL; OVS_ARGUMENT_SLIST_ENTRY* pArgListCur = NULL; OVS_ARGUMENT_SLIST_ENTRY* pArgHead = NULL; BOOLEAN ok = TRUE; UINT16 countArgs = 0; UINT totalSize = 0; BE16 ethType = 0; ethType = (pMask ? pMask->ethInfo.type : pPacketInfo->ethInfo.type); pEncapsGroup = KZAlloc(sizeof(OVS_ARGUMENT_GROUP)); if (!pEncapsGroup) { DEBUGP(LOG_ERROR, __FUNCTION__ " failed allocating group\n"); return FALSE; } pEncapsArg = KZAlloc(sizeof(OVS_ARGUMENT)); if (!pEncapsArg) { ok = FALSE; DEBUGP(LOG_ERROR, __FUNCTION__ " failed allocating encaps arg\n"); goto Cleanup; } pArgListCur = KZAlloc(sizeof(OVS_ARGUMENT_SLIST_ENTRY)); if (!pArgListCur) { ok = FALSE; DEBUGP(LOG_ERROR, __FUNCTION__ " failed allocating arg list item\n"); goto Cleanup; } pArgHead = pArgListCur; pArgHead->pArg = NULL; //NOTE: 802.2 frames are represented in ovs messages as: //packet info eth type = missing (=> filled by us) //mask eth info = exact match if (pPacketInfo->ethInfo.type == RtlUshortByteSwap(OVS_ETHERTYPE_802_2) && pMask && pMask->ethInfo.type) { if (pMask->ethInfo.type != OVS_PI_MASK_MATCH_EXACT(BE16)) { DEBUGP(LOG_ERROR, __FUNCTION__ " expected 802.2 mask to be exact!\n"); ok = FALSE; goto Cleanup; } } if (!CreateArgInList(OVS_ARGTYPE_PI_ETH_TYPE, ðType, &pArgListCur)) //UINT16 { DEBUGP(LOG_ERROR, __FUNCTION__ " failed appending enc eth type\n"); ok = FALSE; goto Cleanup; } if (!_CreateArgsFromLayer3And4InList(pPacketInfo, pMask, &pArgListCur)) { DEBUGP(LOG_ERROR, __FUNCTION__ " failed appending layer 4 / 4 to list\n"); ok = FALSE; goto Cleanup; } argArray = ArgumentListToArray(pArgHead, &countArgs, &totalSize); if (!argArray) { DEBUGP(LOG_ERROR, __FUNCTION__ " failed converting list to array\n"); ok = FALSE; goto Cleanup; } pEncapsGroup->args = argArray; pEncapsGroup->count = countArgs; pEncapsGroup->groupSize = (UINT16)totalSize; pEncapsArg->data = pEncapsGroup; pEncapsArg->length = (UINT16)totalSize + OVS_ARGUMENT_GROUP_HEADER_SIZE; pEncapsArg->type = OVS_ARGTYPE_PI_ENCAP_GROUP; VerifyGroup_Size_Recursive(pEncapsArg->data); Cleanup: if (ok) { DestroyOrFreeArgList(&pArgHead, /*destroy*/ FALSE); return pEncapsArg; } DestroyOrFreeArgList(&pArgHead, /*destroy*/ TRUE); KFree(argArray); KFree(pEncapsGroup); KFree(pEncapsArg); return NULL; }
BOOLEAN GetPacketInfoFromArguments(_Inout_ OVS_OFPACKET_INFO* pPacketInfo, _Inout_ OVS_PI_RANGE* pPiRange, _In_ const OVS_ARGUMENT_GROUP* pPIGroup, _In_ BOOLEAN isMask) { BOOLEAN haveIpv4 = FALSE; OVS_ARGUMENT* pVlanTciArg = NULL, *pEthTypeArg = NULL, *pDatapathInPortArg = NULL; OVS_CHECK(pPacketInfo); OVS_CHECK(pPiRange); for (UINT i = 0; i < pPIGroup->count; ++i) { OVS_ARGUMENT* pArg = pPIGroup->args + i; OVS_ARGTYPE argType = pArg->type; switch (argType) { case OVS_ARGTYPE_PI_DATAPATH_HASH: OVS_PI_UPDATE_MAIN_FIELD(pPacketInfo, pPiRange, pArg, UINT32, flowHash); break; case OVS_ARGTYPE_PI_DATAPATH_RECIRCULATION_ID: OVS_PI_UPDATE_MAIN_FIELD(pPacketInfo, pPiRange, pArg, UINT32, recirculationId); break; case OVS_ARGTYPE_PI_PACKET_PRIORITY: OVS_PI_UPDATE_PHYSICAL_FIELD(pPacketInfo, pPiRange, pArg, UINT32, packetPriority); break; case OVS_ARGTYPE_PI_DP_INPUT_PORT: pDatapathInPortArg = pArg; EXPECT(_PIFromArg_DatapathInPort(pPacketInfo, pPiRange, pArg, isMask)); break; case OVS_ARGTYPE_PI_PACKET_MARK: OVS_PI_UPDATE_PHYSICAL_FIELD(pPacketInfo, pPiRange, pArg, UINT32, packetMark); break; case OVS_ARGTYPE_PI_TUNNEL_GROUP: OVS_CHECK(IsArgTypeGroup(pArg->type)); EXPECT(_PIFromArg_Tunnel(pArg->data, pPacketInfo, pPiRange, isMask)); break; case OVS_ARGTYPE_PI_ETH_ADDRESS: { const OVS_PI_ETH_ADDRESS* pEthAddressPI = pArg->data; OVS_PI_UPDATE_ETHINFO_ADDRESS(pPacketInfo, pPiRange, source, pEthAddressPI->source); OVS_PI_UPDATE_ETHINFO_ADDRESS(pPacketInfo, pPiRange, destination, pEthAddressPI->destination); } break; case OVS_ARGTYPE_PI_VLAN_TCI: pVlanTciArg = pArg; { BE16 tci = GET_ARG_DATA(pVlanTciArg, BE16); EXPECT(tci & RtlUshortByteSwap(OVS_VLAN_TAG_PRESENT)); OVS_PI_UPDATE_ETHINFO_FIELD(pPacketInfo, pPiRange, pVlanTciArg, BE16, tci); } break; case OVS_ARGTYPE_PI_ETH_TYPE: pEthTypeArg = pArg; EXPECT(_GetPIFromArg_EthType(pPacketInfo, pPiRange, pArg, isMask)); break; case OVS_ARGTYPE_PI_IPV4: haveIpv4 = TRUE; EXPECT(_GetPIFromArg_Ipv4(pPacketInfo, pPiRange, pArg, isMask)); break; case OVS_ARGTYPE_PI_IPV6: EXPECT(_GetPIFromArg_Ipv6(pPacketInfo, pPiRange, pArg, isMask)); break; case OVS_ARGTYPE_PI_ARP: EXPECT(_GetPIFromArg_Arp(pPacketInfo, pPiRange, pArg, isMask)); break; case OVS_ARGTYPE_PI_MPLS: { const OVS_PI_MPLS* pMplsPI = pArg->data; OVS_PI_UPDATE_NETINFO_FIELD_VALUE(pPacketInfo, pPiRange, mplsTopLabelStackEntry, pMplsPI->mplsLse); } break; case OVS_ARGTYPE_PI_TCP: { const OVS_PI_TCP* pTcpPI = pArg->data; OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, sourcePort, pTcpPI->source); OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, destinationPort, pTcpPI->destination); } break; case OVS_ARGTYPE_PI_TCP_FLAGS: OVS_PI_UPDATE_TPINFO_FIELD(pPacketInfo, pPiRange, pArg, BE16, tcpFlags); break; case OVS_ARGTYPE_PI_UDP: { const OVS_PI_UDP* pUdpPI = pArg->data; OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, sourcePort, pUdpPI->source); OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, destinationPort, pUdpPI->destination); } break; case OVS_ARGTYPE_PI_SCTP: { const OVS_PI_SCTP* pSctpPI = pArg->data; OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, sourcePort, pSctpPI->source); OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, destinationPort, pSctpPI->destination); } break; case OVS_ARGTYPE_PI_ICMP: { const OVS_PI_ICMP* pIcmpPI = pArg->data; OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, sourcePort, RtlUshortByteSwap(pIcmpPI->type)); OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, destinationPort, RtlUshortByteSwap(pIcmpPI->code)); } break; case OVS_ARGTYPE_PI_ICMP6: { const OVS_PI_ICMP6* pIcmpv6PI = pArg->data; OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, sourcePort, RtlUshortByteSwap(pIcmpv6PI->type)); OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, destinationPort, RtlUshortByteSwap(pIcmpv6PI->code)); } break; case OVS_ARGTYPE_PI_NEIGHBOR_DISCOVERY: _GetPIFromArg_NeighborDiscovery(pPacketInfo, pPiRange, pArg); break; default: DEBUGP(LOG_ERROR, __FUNCTION__ " unexpected key / mask arg type: %u\n", pArg->type); return FALSE; } } if (!pDatapathInPortArg && !isMask) { OVS_PI_UPDATE_PHYSICAL_FIELD_VALUE(pPacketInfo, pPiRange, packetMark, OVS_INVALID_PORT_NUMBER); } if (!pVlanTciArg) { if (!isMask) { //TODO: we should normally set vlan tci to 0xFFFF in this case. //but it used to work with 0 only OVS_PI_UPDATE_ETHINFO_FIELD_VALUE(pPacketInfo, pPiRange, tci, 0); } } if (!pEthTypeArg) { if (isMask) { OVS_PI_UPDATE_ETHINFO_FIELD_VALUE(pPacketInfo, pPiRange, type, OVS_PI_MASK_MATCH_EXACT(UINT16)); } else { OVS_PI_UPDATE_ETHINFO_FIELD_VALUE(pPacketInfo, pPiRange, type, RtlUshortByteSwap(OVS_ETHERTYPE_802_2)); } } return TRUE; }