Changeset 82826 in vbox for trunk/src/VBox
- Timestamp:
- Jan 22, 2020 1:20:42 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Network/DevVirtioNet_1_0.cpp
r82780 r82826 60 60 #include "VBoxDD.h" 61 61 62 /*63 * GSO = Generic Segmentation Offload64 * TSO = TCP Segmentation Offload */65 62 66 63 #define VIRTIONET_SAVED_STATE_VERSION UINT32_C(1) … … 70 67 #define VIRTIONET_MAC_FILTER_LEN 32 71 68 #define VIRTIONET_MAX_VLAN_ID (1 << 12) 72 #define VIRTIONET_PREALLOCATE_RX_SEG_COUNT 3269 #define VIRTIONET_PREALLOCATE_RX_SEG_COUNT 32 73 70 74 71 #define QUEUE_NAME(a_pVirtio, a_idxQueue) ((a_pVirtio)->virtqState[(a_idxQueue)].szVirtqName) … … 77 74 #define FEATURE_ENABLED(feature) (pThis->fNegotiatedFeatures & VIRTIONET_F_##feature) 78 75 #define FEATURE_DISABLED(feature) (!FEATURE_ENABLED(feature)) 76 #define FEATURE_OFFERED(feature) (VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_##feature) 77 #define INSTANCE(pState) pState->szInstanceName; 78 79 #define SET_LINK_UP(pState) \ 80 pState->virtioNetConfig.uStatus |= VIRTIONET_F_LINK_UP; \ 81 virtioCoreNotifyConfigChanged(&pThis->Virtio) 82 83 #define SET_LINK_DOWN(pState) \ 84 pState->virtioNetConfig.uStatus &= !VIRTIONET_F_LINK_UP; \ 85 virtioCoreNotifyConfigChanged(&pThis->Virtio) 86 87 #define IS_LINK_UP(pState) (pState->virtioNetConfig.uStatus & VIRTIONET_F_LINK_UP) 88 #define IS_LINK_DOWN(pState) !IS_LINK_UP(pState) 79 89 80 90 /* Macros to calculate queue specific index number VirtIO 1.0, 5.1.2 */ … … 161 171 * MMIO accesses to device-specific configuration parameters. 162 172 */ 173 174 #pragma pack(1) 163 175 typedef struct virtio_net_config 164 176 { 165 uint8_t uMacAddress[6];/**< mac */166 #if VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_STATUS177 RTMAC uMacAddress; /**< mac */ 178 #if FEATURE_OFFERED(STATUS) 167 179 uint16_t uStatus; /**< status */ 168 180 #endif 169 #if VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_MQ181 #if FEATURE_OFFERED(MQ) 170 182 uint16_t uMaxVirtqPairs; /**< max_virtq_pairs */ 171 183 #endif 172 184 } VIRTIONET_CONFIG_T, PVIRTIONET_CONFIG_T; 185 #pragma pack() 173 186 174 187 #define VIRTIONET_F_LINK_UP RT_BIT_16(1) /**< config status: Link is up */ … … 881 894 static void virtioNetR3QuiesceDevice(PPDMDEVINS pDevIns, VIRTIOVMSTATECHANGED enmQuiescingFor) 882 895 { 883 PVIRTIONET 884 PVIRTIONETCC 896 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 897 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 885 898 886 899 RT_NOREF(pThis); … … 902 915 static DECLCALLBACK(void) virtioNetR3Reset(PPDMDEVINS pDevIns) 903 916 { 917 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 904 918 LogFunc(("\n")); 905 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);906 919 pThis->fResetting = true; 907 920 virtioNetR3QuiesceDevice(pDevIns, kvirtIoVmStateChangedReset); … … 915 928 LogFunc(("\n")); 916 929 917 PVIRTIONET 918 PVIRTIONETCC 930 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 931 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 919 932 920 933 RT_NOREF2(pThis, pThisCC); … … 953 966 static DECLCALLBACK(void) virtioNetR3Resume(PPDMDEVINS pDevIns) 954 967 { 955 PVIRTIONET 956 PVIRTIONETCC 968 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 969 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 957 970 LogFunc(("\n")); 958 971 … … 978 991 } 979 992 980 /* Device operation: Net header packet (VirtIO 1.0, 5.1.6) */ 981 #pragma pack(1) 982 struct virtio_net_hdr { 983 uint8_t uFlags; /**< flags */ 984 uint8_t uGsoType; /**< gso_type */ 985 uint16_t uHdrLen; /**< hdr_len */ 986 uint16_t uGsoSize; /**< gso_size */ 987 uint16_t uChksumStart; /**< csum_start */ 988 uint16_t uChksumOffset; /**< csum_offset */ 989 uint16_t uNumBuffers; /**< num_buffers */ 990 }; 991 #pragma pack() 992 typedef virtio_net_hdr VIRTIONET_PKT_HDR_T, *PVIRTIONET_PKT_HDR_T; 993 AssertCompileSize(VIRTIONET_PKT_HDR_T, 12); 994 993 /** 994 * @callback_method_impl{FNIOMIOPORTNEWIN} 995 */ 996 static DECLCALLBACK(VBOXSTRICTRC) vnetIOPortIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb) 997 { 998 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 999 RT_NOREF(pvUser); 1000 return vpciIOPortIn(pDevIns, &pThis->VPCI, offPort, pu32, cb, &g_IOCallbacks); 1001 } 1002 1003 1004 /** 1005 * @callback_method_impl{FNIOMIOPORTNEWOUT} 1006 */ 1007 static DECLCALLBACK(VBOXSTRICTRC) vnetIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb) 1008 { 1009 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1010 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 1011 RT_NOREF(pvUser); 1012 return vpciIOPortOut(pDevIns, &pThis->VPCI, &pThisCC->VPCI, offPort, u32, cb, &g_IOCallbacks); 1013 } 1014 1015 1016 #ifdef IN_RING3 1017 /** 1018 * @interface_method_impl{PDMIBASE,pfnQueryInterface, 1019 * For VNETSTATECC::VPCI.IBase} 1020 */ 1021 static DECLCALLBACK(void *) virtioNetQueryInterface(struct PDMIBASE *pInterface, const char *pszIID) 1022 { 1023 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, PVIRTIONETCC, VPCI.IBase); 1024 1025 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThisCC->INetworkDown); 1026 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThisCC->INetworkConfig); 1027 1028 return vpciR3QueryInterface(&pThisCC->VPCI, pszIID); 1029 } 1030 1031 /** 1032 * @interface_method_impl{PDMINETWORKDOWN,pfnWaitReceiveAvail} 1033 */ 1034 static DECLCALLBACK(int) virtioNetR3NetworkDown_WaitReceiveAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies) 1035 { 1036 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1037 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, PVIRTIONETCC, INetworkDown); 1038 PPDMDEVINS pDevIns = pThisCC->pDevIns; 1039 1040 LogFlowFunc(("%s: cMillies=%u\n", INSTANCE(pThis), cMillies)); 1041 1042 int rc = virtioNetR3CanReceive(pDevIns, pThis, pThisCC); 1043 if (RT_SUCCESS(rc)) 1044 return VINF_SUCCESS; 1045 1046 if (cMillies == 0) 1047 return VERR_NET_NO_BUFFER_SPACE; 1048 1049 rc = VERR_INTERRUPTED; 1050 ASMAtomicXchgBool(&pThis->fMaybeOutOfSpace, true); 1051 STAM_PROFILE_START(&pThis->StatRxOverflow, a); 1052 1053 VMSTATE enmVMState; 1054 while (RT_LIKELY( (enmVMState = PDMDevHlpVMState(pDevIns)) == VMSTATE_RUNNING 1055 || enmVMState == VMSTATE_RUNNING_LS)) 1056 { 1057 int rc2 = virtioNetR3CanReceive(pDevIns, pThis, pThisCC); 1058 if (RT_SUCCESS(rc2)) 1059 { 1060 rc = VINF_SUCCESS; 1061 break; 1062 } 1063 LogFunc(("%s: waiting cMillies=%u...\n", INSTANCE(pThis), cMillies)); 1064 rc2 = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEventMoreRxDescAvail, cMillies); 1065 if (RT_FAILURE(rc2) && rc2 != VERR_TIMEOUT && rc2 != VERR_INTERRUPTED) 1066 RTThreadSleep(1); 1067 } 1068 STAM_PROFILE_STOP(&pThis->StatRxOverflow, a); 1069 ASMAtomicXchgBool(&pThis->fMaybeOutOfSpace, false); 1070 1071 LogFlowFunc(("%s: -> %d\n", INSTANCE(pThis), rc)); 1072 return rc; 1073 } 1074 /** 1075 * Check if the device can receive data now. 1076 * This must be called before the pfnRecieve() method is called. 1077 * 1078 * @remarks As a side effect this function enables queue notification 1079 * if it cannot receive because the queue is empty. 1080 * It disables notification if it can receive. 1081 * 1082 * @returns VERR_NET_NO_BUFFER_SPACE if it cannot. 1083 * @thread RX 1084 */ 1085 static int virtioNetR3CanReceive(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC) 1086 { 1087 int rc = virtioNetCsRxEnter(pThis, VERR_SEM_BUSY); 1088 AssertRCReturn(rc, rc); 1089 1090 LogFlowFunc(("%s:\n", INSTANCE(pThis))); 1091 1092 if (!pThis->fVirtioReady) 1093 rc = VERR_NET_NO_BUFFER_SPACE; 1094 1095 else if (!virtioCoreIsQueueEnabled(&pThis->Virtio, RXQIDX(0))) 1096 rc = VERR_NET_NO_BUFFER_SPACE; 1097 1098 else if (virtioCoreQueueIsEmpty(pDevIns, pThis->Virtio, RXQIDX(0))) 1099 { 1100 virtioCoreQueueSetNotify(&pThis->pVirtio, RXQIDX(0), true); 1101 rc = VERR_NET_NO_BUFFER_SPACE; 1102 } 1103 else 1104 { 1105 virtioCoreQueueSetNotify(&pThis->pVirtio, RXQIDX(0), false); 1106 rc = VINF_SUCCESS; 1107 } 1108 1109 LogFlowFunc(("%s: -> %Rrc\n", INSTANCE(pThis), rc)); 1110 virtioNetCsRxLeave(pThis); 1111 return rc; 1112 } 1113 /** 1114 * @callback_method_impl{FNTMTIMERDEV, Link Up Timer handler.} 1115 */ 1116 static DECLCALLBACK(void) virtioNetR3LinkUpTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 1117 { 1118 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1119 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 1120 RT_NOREF(pTimer, pvUser); 1121 1122 int rc = virtioNetR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY); 1123 AssertRCReturnVoid(rc); 1124 1125 SET_LINK_UP(pThis); 1126 1127 virtioNetWakeupReceive(pDevIns); 1128 1129 virtioNetR3CsLeave(pDevIns, pThis); 1130 1131 LogFunc(("%s: Link is up\n", INSTANCE(pThis))); 1132 if (pThisCC->pDrv) 1133 pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, PDMNETWORKLINKSTATE_UP); 1134 } 1135 1136 1137 /** 1138 * Takes down the link temporarily if it's current status is up. 1139 * 1140 * This is used during restore and when replumbing the network link. 1141 * 1142 * The temporary link outage is supposed to indicate to the OS that all network 1143 * connections have been lost and that it for instance is appropriate to 1144 * renegotiate any DHCP lease. 1145 * 1146 * @param pDevIns The device instance. 1147 * @param pThis The virtio-net shared instance data. 1148 * @param pThisCC The virtio-net ring-3 instance data. 1149 */ 1150 static void virtioNetR3TempLinkDown(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC) 1151 { 1152 if (IS_LINK_UP(pThis)) 1153 { 1154 SET_LINK_DOWN(pThis); 1155 1156 /* Restore the link back in 5 seconds. */ 1157 int rc = PDMDevHlpTimerSetMillies(pDevIns, pThisCC->hLinkUpTimer, pThis->cMsLinkUpDelay); 1158 AssertRC(rc); 1159 1160 LogFunc(("%s: Link is down temporarily\n", INSTANCE(pThis))); 1161 } 1162 } 1163 1164 /** 1165 * @interface_method_impl{PDMINETWORKCONFIG,pfnGetLinkState} 1166 */ 1167 static DECLCALLBACK(PDMNETWORKLINKSTATE) virtioNetR3NetworkConfig_GetLinkState(PPDMINETWORKCONFIG pInterface) 1168 { 1169 PVIRTIONET pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVIRTIONET); 1170 1171 return IS_LINK_UP(pThis) ? PDMNETWORKLINKSTATE_UP : PDMNETWORKLINKSTATE_DOWN; 1172 } 1173 1174 /** 1175 * @interface_method_impl{PDMINETWORKCONFIG,pfnSetLinkState} 1176 */ 1177 static DECLCALLBACK(int) virtioNetR3NetworkConfig_SetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState) 1178 { 1179 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, PVIRTIONETCC, INetworkConfig); 1180 PPDMDEVINS pDevIns = pThisCC->pDevIns; 1181 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1182 1183 bool fOldUp = !!(pThis->virtioNetConfig.uStatus & VIRTIONET_F_LINK_UP); 1184 bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP; 1185 1186 Log(("%s virtioNetR3NetworkConfig_SetLinkState: enmState=%d\n", INSTANCE(pThis), enmState)); 1187 if (enmState == PDMNETWORKLINKSTATE_DOWN_RESUME) 1188 { 1189 if (fOldUp) 1190 { 1191 /* 1192 * We bother to bring the link down only if it was up previously. The UP link state 1193 * notification will be sent when the link actually goes up in virtioNetR3LinkUpTimer(). 1194 */ 1195 virtioNetR3TempLinkDown(pDevIns, pThis, pThisCC); 1196 if (pThisCC->pDrv) 1197 pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, enmState); 1198 } 1199 } 1200 else if (fNewUp != fOldUp) 1201 { 1202 if (fNewUp) 1203 { 1204 Log(("%s Link is up\n", INSTANCE(pThis))); 1205 pThis->fCableConnected = true; 1206 pThis->virtioNetConfig.uStatus |= VIRTIONET_F_LINK_UP; 1207 virtioCoreNotifyConfigChanged(&pThis->Virtio); 1208 } 1209 else 1210 { 1211 /* The link was brought down explicitly, make sure it won't come up by timer. */ 1212 PDMDevHlpTimerStop(pDevIns, pThisCC->hLinkUpTimer); 1213 Log(("%s Link is down\n", INSTANCE(pThis))); 1214 pThis->fCableConnected = false; 1215 pThis->virtioNetConfig.uStatus &= ~VIRTIONET_F_LINK_UP; 1216 virtioCoreNotifyConfigChanged(&pThis->Virtio); 1217 } 1218 if (pThisCC->pDrv) 1219 pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, enmState); 1220 } 1221 return VINF_SUCCESS; 1222 } 1223 1224 /** 1225 * @callback_method_impl{FNVPCIQUEUECALLBACK, The RX queue} 1226 */ 1227 static DECLCALLBACK(void) virtioNetR3QueueReceive(PPDMDEVINS pDevIns, PVQUEUE pQueue) 1228 { 1229 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1230 RT_NOREF(pThis, pQueue); 1231 LogFunc(("%s Receive buffers has been added, waking up receive thread.\n", INSTANCE(pThis))); 1232 virtioNetWakeupReceive(pDevIns); 1233 } 1234 1235 /** 1236 * Sets up the GSO context according to the Virtio header. 1237 * 1238 * @param pGso The GSO context to setup. 1239 * @param pCtx The context descriptor. 1240 */ 1241 DECLINLINE(PPDMNETWORKGSO) virtioNetR3SetupGsoCtx(PPDMNETWORKGSO pGso, VNETHDR const *pHdr) 1242 { 1243 pGso->u8Type = PDMNETWORKGSOTYPE_INVALID; 1244 1245 if (pHdr->u8GSOType & VNETHDR_GSO_ECN) 1246 { 1247 AssertMsgFailed(("Unsupported flag in virtio header: ECN\n")); 1248 return NULL; 1249 } 1250 switch (pHdr->u8GSOType & ~VNETHDR_GSO_ECN) 1251 { 1252 case VNETHDR_GSO_TCPV4: 1253 pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_TCP; 1254 pGso->cbHdrsSeg = pHdr->u16HdrLen; 1255 break; 1256 case VNETHDR_GSO_TCPV6: 1257 pGso->u8Type = PDMNETWORKGSOTYPE_IPV6_TCP; 1258 pGso->cbHdrsSeg = pHdr->u16HdrLen; 1259 break; 1260 case VNETHDR_GSO_UDP: 1261 pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_UDP; 1262 pGso->cbHdrsSeg = pHdr->u16CSumStart; 1263 break; 1264 default: 1265 return NULL; 1266 } 1267 if (pHdr->u8Flags & VNETHDR_F_NEEDS_CSUM) 1268 pGso->offHdr2 = pHdr->u16CSumStart; 1269 else 1270 { 1271 AssertMsgFailed(("GSO without checksum offloading!\n")); 1272 return NULL; 1273 } 1274 pGso->offHdr1 = sizeof(RTNETETHERHDR); 1275 pGso->cbHdrsTotal = pHdr->u16HdrLen; 1276 pGso->cbMaxSeg = pHdr->u16GSOSize; 1277 return pGso; 1278 } 1279 1280 1281 /** 1282 * @interface_method_impl{PDMINETWORKDOWN,pfnReceive} 1283 */ 1284 static DECLCALLBACK(int) virtioNetR3NetworkDown_Receive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb) 1285 { 1286 return virtioNetR3NetworkDown_ReceiveGso(pInterface, pvBuf, cb, NULL); 1287 } 1288 1289 /** 1290 * @interface_method_impl{PDMINETWORKCONFIG,pfnGetMac} 1291 */ 1292 static DECLCALLBACK(int) virtioNetR3NetworkConfig_GetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac) 1293 { 1294 PVNETSTATECC pThisCC = RT_FROM_MEMBER(pInterface, VNETSTATECC, INetworkConfig); 1295 PVIRTIONET pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVNETSTATE); 1296 memcpy(pMac, pThis->virtioNetConfig.uMacAddress.au8, sizeof(RTMAC)); 1297 return VINF_SUCCESS; 1298 } 1299 #endif 1300 1301 /** 1302 * Returns true if it is a broadcast packet. 1303 * 1304 * @returns true if destination address indicates broadcast. 1305 * @param pvBuf The ethernet packet. 1306 */ 1307 DECLINLINE(bool) virtioNetR3IsBroadcast(const void *pvBuf) 1308 { 1309 static const uint8_t s_abBcastAddr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 1310 return memcmp(pvBuf, s_abBcastAddr, sizeof(s_abBcastAddr)) == 0; 1311 } 1312 1313 /** 1314 * Returns true if it is a multicast packet. 1315 * 1316 * @remarks returns true for broadcast packets as well. 1317 * @returns true if destination address indicates multicast. 1318 * @param pvBuf The ethernet packet. 1319 */ 1320 DECLINLINE(bool) virtioNetR3IsMulticast(const void *pvBuf) 1321 { 1322 return (*(char*)pvBuf) & 1; 1323 } 995 1324 /** 996 1325 * Determines if the packet is to be delivered to upper layer. … … 998 1327 * @returns true if packet is intended for this node. 999 1328 * @param pThis Pointer to the state structure. 1000 * @param pvBuf 1001 * @param cb 1002 */ 1003 static bool v netR3AddressFilter(PVNETSTATEpThis, const void *pvBuf, size_t cb)1329 * @param pvBuf The ethernet packet. 1330 * @param cb Number of bytes available in the packet. 1331 */ 1332 static bool virtioNetR3AddressFilter(PVIRTIONET pThis, const void *pvBuf, size_t cb) 1004 1333 { 1005 1334 if (pThis->fPromiscuous) … … 1007 1336 1008 1337 /* Ignore everything outside of our VLANs */ 1009 uint16_t *uPtr = (uint16_t*)pvBuf; 1338 uint16_t *uPtr = (uint16_t *)pvBuf; 1339 1010 1340 /* Compare TPID with VLAN Ether Type */ 1011 1341 if ( uPtr[6] == RT_H2BE_u(0x8100) 1012 1342 && !ASMBitTest(pThis->aVlanFilter, RT_BE2H_u(uPtr[7]) & 0xFFF)) 1013 1343 { 1014 Log4 (("%s vnetR3AddressFilter: not our VLAN, returning false\n", INSTANCE(pThis)));1344 Log4func(("%s: not our VLAN, returning false\n", INSTANCE(pThis)))); 1015 1345 return false; 1016 1346 } 1017 1347 1018 if (v netR3IsBroadcast(pvBuf))1348 if (virtioNetR3IsBroadcast(pvBuf)) 1019 1349 return true; 1020 1350 1021 if (pThis->fAllMulti && vnetR3IsMulticast(pvBuf))1351 if (pThis->fAllMulticast && virtioNetR3IsMulticast(pvBuf)) 1022 1352 return true; 1023 1353 1024 if (!memcmp(pThis-> config.mac.au, pvBuf, sizeof(RTMAC)))1354 if (!memcmp(pThis->virtioNetConfig.uMacAddress.au8, pvBuf, sizeof(RTMAC))) 1025 1355 return true; 1026 Log4(("%s vnetR3AddressFilter: %RTmac (conf) != %RTmac (dest)\n", INSTANCE(pThis), pThis->config.mac.au, pvBuf)); 1027 1028 for (unsigned i = 0; i < pThis->cMacFilterEntries; i++) 1029 if (!memcmp(&pThis->aMacFilter[i], pvBuf, sizeof(RTMAC))) 1356 1357 Log4func(("%s : %RTmac (conf) != %RTmac (dest)\n", 1358 INSTANCE(pThis), pThis->virtioNetConfig.uMacAddress.au8, pvBuf)); 1359 1360 for (uint16_t i = 0; i < pThis->cMulticastFilterMacs; i++) 1361 if (!memcmp(&pThis->aMacMulticastFilter[i], pvBuf, sizeof(RTMAC))) 1030 1362 return true; 1031 1363 1032 Log2(("%s vnetR3AddressFilter: failed all tests, returning false, packet dump follows:\n", INSTANCE(pThis))); 1033 vnetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming"); 1364 /* @todo Original combined unicast & multicast into one table. Should we distinguish? */ 1365 1366 for (uint16_t i = 0; i < pThis->cUnicastFilterMacs; i++) 1367 if (!memcmp(&pThis->aMacUnicastFilter[i], pvBuf, sizeof(RTMAC))) 1368 return true; 1369 1370 Log2Func(("%s: failed all tests, returning false, packet dump follows:\n", 1371 INSTANCE(pThis)))); 1372 1373 virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming"); 1034 1374 1035 1375 return false; 1036 1376 } 1377 1378 1379 1037 1380 1038 1381 /** … … 1057 1400 { 1058 1401 Log2Func(("%s gso type=%x cbPktHdrsTotal=%u cbPktHdrsSeg=%u mss=%u off1=0x%x off2=0x%x\n", 1059 pThis->szInstanceName, pGso->uType, pGso->cbHdrsTotal,1402 INSTANCE(pThis), pGso->uType, pGso->cbHdrsTotal, 1060 1403 pGso->cbHdrsSeg, pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2)); 1061 1404 … … 1096 1439 RTSgBufInit(pSegsBuf, paSegs, cSegs); 1097 1440 1098 uint16_t *pPhysPktHdrNumBufs, cDescs = 0;1099 1100 uint8_t f FirstIteration= true;1101 for (uint32_t uOffset = 0; uOffset < cb; fFirstIteration = false)1441 RTGCPHYS physPktHdrNumBufs, cDescs = 0; 1442 1443 uint8_t fAddPktHdr = true; 1444 for (uint32_t uOffset = 0; uOffset < cb; ) 1102 1445 { 1103 1446 PVIRTIO_DESC_CHAIN_T pDescChain; … … 1108 1451 /** @todo Find a better way to deal with this */ 1109 1452 1110 AssertMsgReturn(rc == VINF_SUCCESS && pDescChain->cbPhys Send,1453 AssertMsgReturn(rc == VINF_SUCCESS && pDescChain->cbPhysReturn, 1111 1454 ("Not enough Rx buffers in queue to accomodate ethernet packet\n"), 1112 1455 VERR_INTERNAL_ERROR); 1113 1456 1114 AssertMsgReturn(pDescChain->cbPhysReturn >= sizeof(VIRTIONET_PKT_HDR_T), 1457 /* It's almost inconceivable that the first segment of the guest Rx s/g buf is smaller 1458 * than 12 bytes (i.e. size of virtio_net_hdr). Smaller hasn't been seen in practice. 1459 * To simplify the code, that constraint is implemented here. If a guest OS ever violates 1460 * this assumption, the algorithm can be adapted handle the more complex corner case. */ 1461 1462 AssertMsgReturn(pDescChain->pSgPhysReturn->paSegs[0].cbSeg >= sizeof(VIRTIONET_PKT_HDR_T), 1115 1463 ("Desc chain's phys segs have insufficient space for pkt header!\n"), 1116 1464 VERR_INTERNAL_ERROR); … … 1119 1467 1120 1468 uint16_t cSegs = 0; 1121 if (f FirstIteration)1469 if (fAddPktHdr) 1122 1470 { 1123 1471 /* Lead with packet header */ … … 1125 1473 paSegs[cSegs].pvSeg = RTMemAlloc(paSegs[0].cb); 1126 1474 AssertReturn(paSegs[0].pvSeg, VERR_NO_MEMORY); 1127 cbDescChainLeft -= paReqSegs[0].cb; 1128 *pPhysPktHdrNumBufs = ((uint8_t *)paSegs[cSegs].pvSeg) 1129 + RT_UOFFSETOF(VIRTIONET_PKT_HDR_T, uNumBuffers); 1475 1476 gcPhysPktHdrNumBuffers = pDescChain->pSgPhysReturn->paSegs[0] 1477 + RT_UOFFSETOF(VIRTIONET_PKT_HDR_T, uNumBuffers); 1478 1130 1479 cSegs++; 1480 fAddPktHdr = false; 1481 cbDescChainLeft -= sizeof(VIRTIONET_PKT_HDR_T); 1131 1482 } 1132 1483 … … 1146 1497 /* Fix up pkt hdr (already in guest phys. memory) with number of descriptors to send */ 1147 1498 1148 int rc = PDMDevHlpPCIPhysWrite(pDevIns, pPhysPktHdrNumBuffers, cDescs, sizeof(cDescs));1499 int rc = PDMDevHlpPCIPhysWrite(pDevIns, gcPhysPktHdrNumBuffers, cDescs, sizeof(cDescs)); 1149 1500 AssertMsgRCReturn(rc, "Failure updating descriptor count in pkt hdr in guest physical memory\n"); 1150 1501 … … 1153 1504 for (int i = 0; i < 2; i++) 1154 1505 RTMemFree(paSegs[i].pvSeg); 1506 1155 1507 RTMemFree(paSegs); 1156 1508 RTMemFree(pSegsBuf); … … 1158 1510 if (uOffset < cb) 1159 1511 { 1160 Log(("%s v netR3HandleRxPacket: Packet did not fit into RX queue (packet size=%u)!\n", INSTANCE(pThis), cb));1512 Log(("%s virtioNetR3HandleRxPacket: Packet did not fit into RX queue (packet size=%u)!\n", INSTANCE(pThis), cb)); 1161 1513 return VERR_TOO_MUCH_DATA; 1162 1514 } … … 1197 1549 if (!uFeatures) 1198 1550 { 1199 Log2Func((GSO type (0x%x) not supported\n", pThis->szInstanceName, pGso->uType));1551 Log2Func((GSO type (0x%x) not supported\n", INSTANCE(pThis), pGso->uType)); 1200 1552 return VERR_NOT_SUPPORTED; 1201 1553 } 1202 1554 } 1203 1555 1204 Log2Func(("pvBuf=%p cb=%u pGso=%p\n", pThis->szInstanceName, pvBuf, cb, pGso));1556 Log2Func(("pvBuf=%p cb=%u pGso=%p\n", INSTANCE(pThis), pvBuf, cb, pGso)); 1205 1557 1206 1558 int rc = virtioR3CanReceive(pDevIns, pThis, pThisCC); … … 1254 1606 AssertReturnVoid(uStart < cbSize); 1255 1607 AssertReturnVoid(uStart + uOffset + sizeof(uint16_t) <= cbSize); 1256 *(uint16_t *)(pBuf + uStart + uOffset) = v netR3Chksum16(pBuf + uStart, cbSize - uStart);1608 *(uint16_t *)(pBuf + uStart + uOffset) = virtioNetR3Chksum16(pBuf + uStart, cbSize - uStart); 1257 1609 } 1258 1610 … … 1270 1622 } 1271 1623 } 1272 static bool virtioNetR3ReadHeader(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PVIRTIONET_PKT_HDR_T pPktHdr, uint32_t cbMax) 1273 { 1274 int rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pPktHdr, sizeof(*pPktHdr)); 1275 if (RT_FAILURE(rc)) 1276 return false; 1277 1278 Log4(("virtio-net: header flags=%x gso-type=%x len=%x gso-size=%x Chksum-start=%x Chksum-offset=%x cb=%x\n", 1279 pPktHdr->uFlags, pPktHdr->uGsoType, pPktHdr->uHdrLen, pPktHdr->uGSOSize, pPktHdr->uChksumStart, pPktHdr->uChksumOffset, cbMax)); 1280 1281 if (pPktHdr->uGsoType) 1282 { 1283 uint32_t uMinHdrSize; 1284 1285 /* Segmentation offloading cannot be done without checksumming, and we do not support ECN */ 1286 if ( RT_UNLIKELY(!(pPktHdr->uFlags & VIRTIONET_HDR_F_NEEDS_CSUM)) 1287 | RT_UNLIKELY(pPktHdr->uGsoType & VIRTIONET_HDR_GSO_ECN))) 1288 return false; 1289 1290 switch (pPktHdr->uGsoType) 1291 { 1292 case VIRTIONET_HDR_GSO_TCPV4: 1293 case VIRTIONET_HDR_GSO_TCPV6: 1294 uMinHdrSize = sizeof(RTNETTCP); 1295 break; 1296 case VIRTIONET_HDR_GSO_UDP: 1297 uMinHdrSize = 0; 1298 break; 1299 default: 1300 return false; 1301 } 1302 /* Header + MSS must not exceed the packet size. */ 1303 if (RT_UNLIKELY(uMinHdrSize + pPktHdr->uChksumStart + pPktHdr->uGSOSize > cbMax)) 1304 return false; 1305 } 1306 /* Checksum must fit into the frame (validating both checksum fields). */ 1307 if (( pPktHdr->uFlags & VIRTIONET_HDR_F_NEEDS_CSUM) 1308 && sizeof(uint16_t) + pPktHdr->uChksumStart + pPktHdr->uChksumOffset > cbMax) 1309 return false; 1310 Log4func(("returning true\n")); 1311 return true; 1312 } 1624 1313 1625 1314 1626 static uint8_t virtioNetR3CtrlRx(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, … … 1425 1737 1426 1738 #ifdef LOG_ENABLED 1427 LogFunc(("%s: unicast MACs:\n", pThis->szInstanceName)));1739 LogFunc(("%s: unicast MACs:\n", INSTANCE(pThis)))); 1428 1740 for(unsigned i = 0; i < nMacs; i++) 1429 1741 LogFunc((" %RTmac\n", &pThis->aMacUnicastFilter[i])); 1430 1742 1431 LogFunc(("%s: multicast MACs:\n", pThis->szInstanceName)));1743 LogFunc(("%s: multicast MACs:\n", INSTANCE(pThis)))); 1432 1744 for(unsigned i = 0; i < nMacs; i++) 1433 1745 LogFunc((" %RTmac\n", &pThis->aMacUnicastFilter[i])); … … 1448 1760 virtioNetR3PullChain(pDescChain, &uVlanId, sizeof(uVlanId)); 1449 1761 AssertMsgReturn(uVlanId > VIRTIONET_MAX_VLAN_ID, 1450 ("%s VLAN ID out of range (VLAN ID=%u)\n", pThis->szInstanceName, uVlanId), VIRTIONET_ERROR);1451 LogFunc(("%s: uCommand=%u VLAN ID=%u\n", pThis->szInstanceName, pCtrlPktHdr->uCmd, uVlanId));1762 ("%s VLAN ID out of range (VLAN ID=%u)\n", INSTANCE(pThis), uVlanId), VIRTIONET_ERROR); 1763 LogFunc(("%s: uCommand=%u VLAN ID=%u\n", INSTANCE(pThis), pCtrlPktHdr->uCmd, uVlanId)); 1452 1764 switch (pCtrlPktHdr->uCmd) 1453 1765 { … … 1507 1819 } 1508 1820 1509 PRTSGSEG paReqSegs = (PRTSGSEG)RTMemAllocZ(sizeof(RTSGSEG) * 2); 1510 AssertReturn(paReqSegs, VERR_NO_MEMORY); 1821 /* Return CTRL packet Ack byte (result code) to guest driver */ 1822 PRTSGSEG paSegs = (PRTSGSEG)RTMemAllocZ(sizeof(RTSGSEG) * 2); 1823 AssertReturn(paSegs, VERR_NO_MEMORY); 1511 1824 1512 1825 RTSGSEG aSegs[] = { { &uAck, sizeof(uAck) } }; 1513 memcpy(pa ReqSegs, aSegs, sizeof(aSegs));1514 1515 PRTSGBUF p ReqSegBuf = (PRTSGBUF)RTMemAllocZ(sizeof(RTSGBUF));1516 AssertReturn(p ReqSegBuf, VERR_NO_MEMORY);1826 memcpy(paSegs, aSegs, sizeof(aSegs)); 1827 1828 PRTSGBUF pSegBuf = (PRTSGBUF)RTMemAllocZ(sizeof(RTSGBUF)); 1829 AssertReturn(pSegBuf, VERR_NO_MEMORY); 1517 1830 1518 1831 /* Copy segment data to malloc'd memory to avoid stack out-of-scope errors sanitizer doesn't detect */ 1519 1832 for (int i = 0; i < cSegs; i++) 1520 1833 { 1521 void *pv = pa ReqSegs[i].pvSeg;1522 pa ReqSegs[i].pvSeg = RTMemAlloc(paReqSegs[i].cbSeg);1523 AssertReturn(pa ReqSegs[i].pvSeg, VERR_NO_MEMORY);1524 memcpy(pa ReqSegs[i].pvSeg, pv, paReqSegs[i].cbSeg);1525 } 1526 1527 RTSgBufInit(p ReqSegBuf, paReqSegs, cSegs);1528 1529 virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, qIdx, p ReqSegBuf, pDescChain, true);1834 void *pv = paSegs[i].pvSeg; 1835 paSegs[i].pvSeg = RTMemAlloc(paSegs[i].cbSeg); 1836 AssertReturn(paSegs[i].pvSeg, VERR_NO_MEMORY); 1837 memcpy(paSegs[i].pvSeg, pv, paSegs[i].cbSeg); 1838 } 1839 1840 RTSgBufInit(pSegBuf, paSegs, cSegs); 1841 1842 virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, qIdx, pSegBuf, pDescChain, true); 1530 1843 virtioCoreQueueSync(pDevIns, &pThis->Virtio, qIdx); 1531 1844 1532 1845 for (int i = 0; i < cSegs; i++) 1533 RTMemFree(pa ReqSegs[i].pvSeg);1534 1535 RTMemFree(pa ReqSegs);1536 RTMemFree(p ReqSegBuf);1846 RTMemFree(paSegs[i].pvSeg); 1847 1848 RTMemFree(paSegs); 1849 RTMemFree(pSegBuf); 1537 1850 1538 1851 LogFunc(("Processed ctrl message class/cmd/subcmd = %u/%u/%u. Ack=%u.\n", 1539 pCtrlPktHdr.uClass, pCtrlPktHdr.uCmd, pCtrlPktHdr.uCmdSpecific, uAck); 1540 1541 } 1542 1543 1852 pCtrlPktHdr.uClass, pCtrlPktHdr.uCmd, pCtrlPktHdr.uCmdSpecific, uAck); 1853 1854 } 1855 1856 static bool virtioNetR3ReadHeader(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PVIRTIONET_PKT_HDR_T pPktHdr, uint32_t cbMax) 1857 { 1858 int rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pPktHdr, sizeof(*pPktHdr)); 1859 if (RT_FAILURE(rc)) 1860 return false; 1861 1862 Log4(("virtio-net: header flags=%x gso-type=%x len=%x gso-size=%x Chksum-start=%x Chksum-offset=%x cb=%x\n", 1863 pPktHdr->uFlags, pPktHdr->uGsoType, pPktHdr->uHdrLen, pPktHdr->uGSOSize, pPktHdr->uChksumStart, pPktHdr->uChksumOffset, cbMax)); 1864 1865 if (pPktHdr->uGsoType) 1866 { 1867 uint32_t uMinHdrSize; 1868 1869 /* Segmentation offloading cannot be done without checksumming, and we do not support ECN */ 1870 if ( RT_UNLIKELY(!(pPktHdr->uFlags & VIRTIONET_HDR_F_NEEDS_CSUM)) 1871 | RT_UNLIKELY(pPktHdr->uGsoType & VIRTIONET_HDR_GSO_ECN))) 1872 return false; 1873 1874 switch (pPktHdr->uGsoType) 1875 { 1876 case VIRTIONET_HDR_GSO_TCPV4: 1877 case VIRTIONET_HDR_GSO_TCPV6: 1878 uMinHdrSize = sizeof(RTNETTCP); 1879 break; 1880 case VIRTIONET_HDR_GSO_UDP: 1881 uMinHdrSize = 0; 1882 break; 1883 default: 1884 return false; 1885 } 1886 /* Header + MSS must not exceed the packet size. */ 1887 if (RT_UNLIKELY(uMinHdrSize + pPktHdr->uChksumStart + pPktHdr->uGSOSize > cbMax)) 1888 return false; 1889 } 1890 /* Checksum must fit into the frame (validating both checksum fields). */ 1891 if (( pPktHdr->uFlags & VIRTIONET_HDR_F_NEEDS_CSUM) 1892 && sizeof(uint16_t) + pPktHdr->uChksumStart + pPktHdr->uChksumOffset > cbMax) 1893 return false; 1894 Log4func(("returning true\n")); 1895 return true; 1896 } 1897 1898 static int virtioNetR3TransmitFrame(PVIRTIONET pThis, PVIRTIONETCC pThisCC, PPDMSCATTERGATHER pSgBuf, 1899 PPDMNETWORKGSO pGso, PVNETHDR pHdr) 1900 { 1901 virtioNetR3PacketDump(pThis, (uint8_t *)pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, "--> Outgoing"); 1902 if (pGso) 1903 { 1904 /* Some guests (RHEL) may report HdrLen excluding transport layer header! */ 1905 /* 1906 * We cannot use cdHdrs provided by the guest because of different ways 1907 * it gets filled out by different versions of kernels. 1908 */ 1909 //if (pGso->cbHdrs < pHdr->uCSumStart + pHdr->uCSumOffset + 2) 1910 { 1911 Log4Func(("%s: HdrLen before adjustment %d.\n", 1912 INSTANCE(pThis), pGso->cbHdrsTotal)); 1913 switch (pGso->u8Type) 1914 { 1915 case PDMNETWORKGSOTYPE_IPV4_TCP: 1916 case PDMNETWORKGSOTYPE_IPV6_TCP: 1917 pGso->cbHdrsTotal = pHdr->uChkumStart + 1918 ((PRTNETTCP)(((uint8_t*)pSgBuf->aSegs[0].pvSeg) + pHdr->uChkumStart))->th_off * 4; 1919 pGso->cbHdrsSeg = pGso->cbHdrsTotal; 1920 break; 1921 case PDMNETWORKGSOTYPE_IPV4_UDP: 1922 pGso->cbHdrsTotal = (uint8_t)(pHdr->uCSumStart + sizeof(RTNETUDP)); 1923 pGso->cbHdrsSeg = pHdr->u16CSumStart; 1924 break; 1925 } 1926 /* Update GSO structure embedded into the frame */ 1927 ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsTotal = pGso->cbHdrsTotal; 1928 ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsSeg = pGso->cbHdrsSeg; 1929 Log4(("%s vnetR3TransmitPendingPackets: adjusted HdrLen to %d.\n", 1930 INSTANCE(pThis), pGso->cbHdrsTotal)); 1931 } 1932 Log2Func(("%s: gso type=%x cbHdrsTotal=%u cbHdrsSeg=%u mss=%u off1=0x%x off2=0x%x\n", 1933 INSTANCE(pThis), pGso->u8Type, pGso->cbHdrsTotal, pGso->cbHdrsSeg, 1934 pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2)); 1935 STAM_REL_COUNTER_INC(&pThis->StatTransmitGSO); 1936 } 1937 else if (pHdr->u8Flags & VNETHDR_F_NEEDS_CSUM) 1938 { 1939 STAM_REL_COUNTER_INC(&pThis->StatTransmitCSum); 1940 /* 1941 * This is not GSO frame but checksum offloading is requested. 1942 */ 1943 virtioNetR3CompleteChecksum((uint8_t*)pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, 1944 pHdr->uChkumStart, pHdr->uCSumOffset); 1945 } 1946 1947 return pThisCC->pDrv->pfnSendBuf(pThisCC->pDrv, pSgBuf, false); 1948 } 1949 1950 static void virtioNetR3TransmitPendingPackets(PPDMDEVINS pDevIns, PVNETSTATE pThis, PVNETSTATECC pThisCC, 1951 uint16_t qIdx, bool fOnWorkerThread) 1952 { 1953 PVIRTIOCORE pVirtio = pThis->pVirtio; 1954 1955 /* 1956 * Only one thread is allowed to transmit at a time, others should skip 1957 * transmission as the packets will be picked up by the transmitting 1958 * thread. 1959 */ 1960 if (!ASMAtomicCmpXchgU32(&pThis->uIsTransmitting, 1, 0)) 1961 return; 1962 1963 if (!fVirtioReady) 1964 { 1965 LogFunc(("%s Ignoring transmit requests. VirtIO not ready (status=0x%x).\n", 1966 INSTANCE(pThis), pThis->virtioNetConfig.uStatus)); 1967 return; 1968 } 1969 1970 if (!pThis->fCableConnected) 1971 { 1972 Log(("%s Ignoring transmit requests while cable is disconnected.\n", INSTANCE(pThis))); 1973 return; 1974 } 1975 1976 PPDMINETWORKUP pDrv = pThisCC->pDrv; 1977 if (pDrv) 1978 { 1979 int rc = pDrv->pfnBeginXmit(pDrv, fOnWorkerThread); 1980 Assert(rc == VINF_SUCCESS || rc == VERR_TRY_AGAIN); 1981 if (rc == VERR_TRY_AGAIN) 1982 { 1983 ASMAtomicWriteU32(&pThis->uIsTransmitting, 0); 1984 return; 1985 } 1986 } 1987 1988 unsigned int cbPktHdr = sizeof(VIRTIONET_PKT_HDR_T); 1989 1990 Log3func(("%s: About to transmit %d pending packets\n", 1991 INSTANCE(pThis), virtioCoreR3QueuePendingCount(pVirtio->pDevIndx, pVirtio, TXQIDX(0)); 1992 1993 virtioNetR3SetWriteLed(&pThisCC, true); 1994 1995 PVIRTIO_DESC_CHAIN_T pDescChain; 1996 while (virtioCoreR3QueuePeek(pVirtio->pDevIns, pVirtio, TXQIDX(0), &pDescChain) { 1997 { 1998 unsigned uOffset = 0; 1999 uint32_t cVirtioSegs = pDescChain->pSgPhysSend->cSegs; 2000 PVIRTIOSGSEG paVirtioSegs = pDescChain->pSgPhysSend->paSegs; 2001 2002 if (cVirtioSegs < 2 || paVirtioSegs[0].cbSeg != cbPktHdr) 2003 { 2004 /* This check could be made more complex, because in theory (but not likely nor 2005 * seen in practice) the first segment could contain header and data. */ 2006 LogFunc(("%s: The first segment is not the header! (%u < 2 || %u != %u).\n", 2007 INSTANCE(pThis), cVirtioSegs, paVirtioSegs[0].cbSeg, cbPktHdr)); 2008 break; 2009 } 2010 2011 VIRTIONET_PKT_HDR_T PktHdr; 2012 uint32_t uSize = 0; 2013 2014 /* Compute total frame size. */ 2015 for (unsigned i = 1; i < cVirtioSegs && uSize < VIRTIONET_MAX_FRAME_SIZE; i++) 2016 uSize += paVirtioSegs[i].cbSeg; 2017 2018 Log5func(("%s: complete frame is %u bytes.\n", INSTANCE(pThis), uSize)); 2019 Assert(uSize <= VIRTIONET_MAX_FRAME_SIZE); 2020 2021 /* Truncate oversized frames. */ 2022 if (uSize > VIRTIONET_MAX_FRAME_SIZE) 2023 uSize = VIRTIONET_MAX_FRAME_SIZE; 2024 2025 if (pThisCC->pDrv && virtioNetR3ReadHeader(pDevIns, paVirtioSegs[0].gcPhys, &PktHdr, uSize)) 2026 { 2027 PDMNETWORKGSO Gso, *pGso = virtioNetR3SetupGsoCtx(&Gso, &PktHdr); 2028 2029 /** @todo Optimize away the extra copying! (lazy bird) */ 2030 PPDMSCATTERGATHER pPdmSgBuf; 2031 int rc = pThisCC->pDrv->pfnAllocBuf(pThisCC->pDrv, uSize, pGso, &pPdmSgBuf); 2032 if (RT_SUCCESS(rc)) 2033 { 2034 pPdmSgBuf->cbUsed = uSize; 2035 2036 /* Assemble a complete frame. */ 2037 for (unsigned i = 1; i < cVirtioSegs && uSize > 0; i++) 2038 { 2039 unsigned uOffset; 2040 unsigned cbSeg = RT_MIN(uSize, paVirtioSegs[i].cbSeg); 2041 2042 PDMDevHlpPCIPhysRead(pDevIns, paVirtioSegs[i].gcPhys; 2043 ((uint8_t *)pPdmSgBuf->aSegs[0].pvSeg) + uOffset, 2044 cbSeg); 2045 uOffset += cbSeg; 2046 uSize -= cbSeg; 2047 } 2048 rc = virtioNetR3TransmitFrame(pThis, pThisCC, pPdmSgBuf, pGso, &PktHdr); 2049 } 2050 else 2051 { 2052 Log4func(("Failed to allocate SG buffer: size=%u rc=%Rrc\n", uSize, rc)); 2053 /* Stop trying to fetch TX descriptors until we get more bandwidth. */ 2054 break; 2055 } 2056 } 2057 2058 /* Remove this descriptor chain from the available ring */ 2059 virtioCoreR3QueueSkip(pVirtio, TXQIDX(0)); 2060 2061 /* No data to return to guest, but call is needed put elem (e.g. desc chain) on used ring */ 2062 virtioCoreR3QueuePut(pVirtio->pDevIns, pVirtio, TXQIDX(0), NULL, pDescChain, false); 2063 2064 virtioCoreQueueSync(pVirtio->pDevIns, pVirtio, TXQIDX(0)); 2065 } 2066 virtioNetR3SetWriteLed(pThisCC, false); 2067 2068 if (pDrv) 2069 pDrv->pfnEndXmit(pDrv); 2070 ASMAtomicWriteU32(&pThis->uIsTransmitting, 0); 2071 } 2072 2073 /** 2074 * @interface_method_impl{PDMINETWORKDOWN,pfnXmitPending} 2075 */ 2076 static DECLCALLBACK(void) vnetR3NetworkDown_XmitPending(PPDMINETWORKDOWN pInterface) 2077 { 2078 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkDown); 2079 PPDMDEVINS pDevIns = pThisCC->pDevIns; 2080 PVIRTIONET pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVIRTIONET); 2081 vnetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, TXQIDX(0), false /*fOnWorkerThread*/); 2082 } 2083 2084 # ifdef VNET_TX_DELAY 2085 2086 /** 2087 * @callback_method_impl{FNVPCIQUEUECALLBACK, The TX queue} 2088 */ 2089 static DECLCALLBACK(void) virtioNetR3QueueTransmit(PPDMDEVINS pDevIns, PVQUEUE pQueue) 2090 { 2091 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 2092 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 2093 2094 if (PDMDevHlpTimerIsActive(pDevIns, pThis->hTxTimer)) 2095 { 2096 PDMDevHlpTimerStop(pDevIns, pThis->hTxTimer); 2097 Log3Func(("%: Got kicked with notification disabled, re-enable notification and flush TX queue\n", INSTANCE(pThis))); 2098 virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, TXQIDX(0), false /*fOnWorkerThread*/); 2099 if (RT_FAILURE(virtioNettR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY))) 2100 LogRelFunc(("Failed to enter critical section!/n")); 2101 else 2102 { 2103 virtioCoreQueueSetNotify(&pThis->Virtio, TXQIDX(0), true); 2104 virtioNetR3CsLeave(pDevIns, pThis); 2105 } 2106 } 2107 else 2108 { 2109 if (RT_FAILURE(virtioNetR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY))) 2110 LogRelFunc(("Failed to enter critical section!/n")); 2111 else 2112 { 2113 virtioCoreQueueSetNotify(&pThis->Virtio, TXQIDX(0), false); 2114 PDMDevHlpTimerSetMicro(pDevIns, pThis->hTxTimer, VNET_TX_DELAY); 2115 pThis->u64NanoTS = RTTimeNanoTS(); 2116 virtioNetR3CsLeave(pDevIns, pThis); 2117 } 2118 } 2119 } 2120 2121 /** 2122 * @callback_method_impl{FNTMTIMERDEV, Transmit Delay Timer handler.} 2123 */ 2124 static DECLCALLBACK(void) virtioNetR3TxTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 2125 { 2126 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 2127 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 2128 RT_NOREF(pTimer, pvUser); 2129 2130 uint32_t u32MicroDiff = (uint32_t)((RTTimeNanoTS() - pThis->u64NanoTS) / 1000); 2131 if (u32MicroDiff < pThis->u32MinDiff) 2132 pThis->u32MinDiff = u32MicroDiff; 2133 if (u32MicroDiff > pThis->u32MaxDiff) 2134 pThis->u32MaxDiff = u32MicroDiff; 2135 pThis->u32AvgDiff = (pThis->u32AvgDiff * pThis->u32i + u32MicroDiff) / (pThis->u32i + 1); 2136 pThis->u32i++; 2137 Log3Func(("Expired, diff %9d usec, avg %9d usec, min %9d usec, max %9d usec\n", 2138 u32MicroDiff, pThis->u32AvgDiff, pThis->u32MinDiff, pThis->u32MaxDiff)); 2139 2140 // Log3Func(("%s Expired\n", INSTANCE(pThis))); 2141 virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, TXQIDX(0), false /*fOnWorkerThread*/); 2142 if (RT_FAILURE(virtioNettR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY))) 2143 { 2144 LogRelFunc(("Failed to enter critical section!/n")); 2145 return; 2146 } 2147 virtioCoreQueueSetNotify(&pThis->Virtio, TXQIDX(0), true); 2148 virtioNetR3CsLeave(pDevIns, pThis); 2149 } 2150 2151 DECLINLINE(int) virtioNetR3CreateTxThreadAndEvent(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC) 2152 { 2153 RT_NOREF(pDevIns, pThis, pThisCC); 2154 return VINF_SUCCESS; 2155 } 2156 2157 DECLINLINE(void) virtioNetR3DestroyTxThreadAndEvent(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC) 2158 { 2159 RT_NOREF(pDevIns, pThis, pThisCC); 2160 } 2161 2162 # else /* !VNET_TX_DELAY */ 2163 2164 /** 2165 * @callback_method_impl{FNPDMTHREADDEV} 2166 */ 2167 static DECLCALLBACK(int) vnetR3TxThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 2168 { 2169 PVNETSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVNETSTATE); 2170 PVNETSTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVNETSTATECC); 2171 2172 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 2173 return VINF_SUCCESS; 2174 2175 int rc = VINF_SUCCESS; 2176 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 2177 { 2178 rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hTxEvent, RT_INDEFINITE_WAIT); 2179 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING)) 2180 break; 2181 while (true) 2182 { 2183 virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, TXQIDX(0), false /*fOnWorkerThread*/); /// @todo shouldn't it be true instead? 2184 LogFunc(("Enable kicking and get to sleep\n")); 2185 virtioCoreQueueSetNotify(&pThis->Virtio, TXQIDX(0), true); 2186 if (virtioCoreQueueIsEmpty(pDevIns, &pThis->Virtio, TXQIDX(0))) 2187 break; 2188 virtioCoreQueueSetNotify(&pThis->Virtio, TXQIDX(0), false); 2189 } 2190 } 2191 2192 return rc; 2193 } 2194 2195 /** 2196 * @callback_method_impl{FNPDMTHREADWAKEUPDEV} 2197 */ 2198 static DECLCALLBACK(int) virtioNetR3TxThreadWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 2199 { 2200 PVNETSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVNETSTATE); 2201 RT_NOREF(pThread); 2202 return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hTxEvent); 2203 } 2204 2205 static int vnetR3CreateTxThreadAndEvent(PPDMDEVINS pDevIns, PVNETSTATE pThis, PVNETSTATECC pThisCC) 2206 { 2207 int rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->hTxEvent); 2208 if (RT_SUCCESS(rc)) 2209 { 2210 rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->pTxThread, NULL, vnetR3TxThread, 2211 vnetR3TxThreadWakeUp, 0, RTTHREADTYPE_IO, INSTANCE(pThis)); 2212 if (RT_FAILURE(rc)) 2213 PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("VNET: Failed to create worker thread %s"), INSTANCE(pThis)); 2214 } 2215 else 2216 PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("VNET: Failed to create SUP event semaphore")); 2217 return rc; 2218 } 2219 2220 static void vnetR3DestroyTxThreadAndEvent(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC) 2221 { 2222 if (pThisCC->pTxThread) 2223 { 2224 /* Destroy the thread. */ 2225 int rcThread; 2226 int rc = PDMDevHlpThreadDestroy(pDevIns, pThisCC->pTxThread, &rcThread); 2227 if (RT_FAILURE(rc) || RT_FAILURE(rcThread)) 2228 AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread)); 2229 pThisCC->pTxThread = NULL; 2230 } 2231 2232 if (pThis->hTxEvent != NIL_SUPSEMEVENT) 2233 { 2234 PDMDevHlpSUPSemEventClose(pDevIns, pThis->hTxEvent); 2235 pThis->hTxEvent = NIL_SUPSEMEVENT; 2236 } 2237 } 2238 2239 /** 2240 * @callback_method_impl{FNVPCIQUEUECALLBACK, The TX queue} 2241 */ 2242 static DECLCALLBACK(void) virtioNetR3QueueTransmit(PPDMDEVINS pDevIns, uint16_t qIdx) 2243 { 2244 PVNETSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVNETSTATE); 2245 2246 LogFunc(("Disable kicking and wake up TX thread\n")); 2247 virtioCoreQueueSetNotify(&pThis->Virtio, qIdx, false); 2248 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hTxEvent); 2249 AssertRC(rc); 2250 } 2251 2252 # endif /* !VNET_TX_DELAY */ 1544 2253 static void virtioNetR3Transmit(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, uint16_t qIdx, PVIRTIO_DESC_CHAIN_T pDescChain) 1545 2254 { … … 1671 2380 1672 2381 pThis->virtioNetConfig.status = pThis->fCableConnected ? VIRTIONET_S_LINK_UP : 0; 1673 LogFunc(("%s Link is %s\n", pThis->szInstanceName, pThis->fCableConnected ? "up" : "down"));2382 LogFunc(("%s Link is %s\n", INSTANCE(pThis), pThis->fCableConnected ? "up" : "down")); 1674 2383 1675 2384 pThis->fPromiscuous = true; … … 1852 2561 */ 1853 2562 LogFunc(("PDM device instance: %d\n", iInstance)); 1854 RTStrPrintf( pThis->szInstanceName, sizeof(pThis->szInstanceName), "VIRTIONET%d", iInstance);2563 RTStrPrintf(INSTANCE(pThis), sizeof(INSTANCE(pThis)), "VIRTIONET%d", iInstance); 1855 2564 pThisCC->pDevIns = pDevIns; 1856 2565 … … 1886 2595 if (pThis->cMsLinkUpDelay > 5000 || pThis->cMsLinkUpDelay < 100) 1887 2596 LogRel(("%s WARNING! Link up delay is set to %u seconds!\n", 1888 pThis->szInstanceName, pThis->cMsLinkUpDelay / 1000));1889 1890 Log(("%s Link up delay is set to %u seconds\n", pThis->szInstanceName, pThis->cMsLinkUpDelay / 1000));2597 INSTANCE(pThis), pThis->cMsLinkUpDelay / 1000)); 2598 2599 Log(("%s Link up delay is set to %u seconds\n", INSTANCE(pThis), pThis->cMsLinkUpDelay / 1000)); 1891 2600 1892 2601 /* Copy the MAC address configured for the VM to the MMIO accessible Virtio dev-specific config area */ … … 1918 2627 VirtioPciParams.uInterruptPin = 0x01; 1919 2628 1920 rc = virtioCoreR3Init(pDevIns, &pThis->Virtio, &pThisCC->Virtio, &VirtioPciParams, pThis->szInstanceName,2629 rc = virtioCoreR3Init(pDevIns, &pThis->Virtio, &pThisCC->Virtio, &VirtioPciParams, INSTANCE(pThis), 1921 2630 VIRTIONET_HOST_FEATURES_OFFERED, 1922 2631 &pThis->virtioNetConfig /*pvDevSpecificCap*/, sizeof(pThis->virtioNetConfig));
Note:
See TracChangeset
for help on using the changeset viewer.