PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/verify/src/Checked/Libraries/NetStack2/Nic/Nic.cs

https://bitbucket.org/MpDzik/singularity-bus-drivers
C# | 574 lines | 439 code | 63 blank | 72 comment | 26 complexity | 1284dada1256ea4538cb0fe341d9bfc0 MD5 | raw file
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Microsoft Research Singularity
  4. //
  5. // Copyright (c) Microsoft Corporation. All rights reserved.
  6. //
  7. // File: NicManager.sg
  8. //
  9. // Note:
  10. //
  11. // When a network device comes up, it registers with the
  12. // NicManager, who places it in the namespace under
  13. // /dev/nicX and advertises its existence with the netstack
  14. // runtime core. The netstack runtime core will be responsible
  15. // for notifying the NicManager when the device has gone away.
  16. //
  17. // This is a lot of jiggery-pokery just so users can see the device names
  18. // under /dev and the names are sequential.
  19. //
  20. //#define DEBUG_NIC
  21. using System;
  22. using System.Collections;
  23. using System.Diagnostics;
  24. using System.Threading;
  25. using Microsoft.SingSharp;
  26. using Microsoft.Singularity;
  27. using Microsoft.Singularity.Channels;
  28. using Microsoft.Singularity.Io;
  29. using Microsoft.Singularity.Io.Net;
  30. using Microsoft.Singularity.Directory;
  31. using Microsoft.Singularity.NetStack;
  32. using Drivers.Net;
  33. //using Microsoft.Singularity.NetStack2.NetDrivers;
  34. namespace Microsoft.Singularity.NetStack2.Channels.Nic
  35. {
  36. class ExRefPacketFifo
  37. {
  38. MonitorLock thisLock = new MonitorLock();
  39. PacketFifo o;
  40. internal ExRefPacketFifo(PacketFifo o, bool dummy)
  41. {
  42. VTable.Assert(o != null);
  43. this.o = o;
  44. }
  45. public PacketFifo Acquire() {
  46. thisLock.Acquire();
  47. return o;
  48. }
  49. public void Release(PacketFifo v) {
  50. o = v;
  51. thisLock.Release();
  52. }
  53. }
  54. public class Nic : NicDeviceEventContract, IAdapter, IThreadStart
  55. {
  56. // Upper bounds computed for 10Gbps with maximum sized
  57. // packets to give a small number of I/O requests per
  58. // second and be a power of 2.
  59. private const int MaxTxPacketsInDevice = 128 * 1024;
  60. private const int MaxRxPacketsInDevice = 128 * 1024;
  61. private TRef/*NicDeviceContract.Imp*/ nicChannel;
  62. string driverName;
  63. string driverVersion;
  64. EthernetAddress macAddress;
  65. string nicName;
  66. int mtu;
  67. int maxTxPacketsInDevice;
  68. int maxRxPacketsInDevice;
  69. int maxTxFragmentsPerPacket;
  70. int maxRxFragmentsPerPacket;
  71. private ExRefPacketFifo rxFifo;
  72. private ExRefPacketFifo txFifo;
  73. private ExRefPacketFifo txFreeFifo;
  74. private ExRefPacketFifo txCoalesceFifo;
  75. private AutoResetEvent muxEvent;
  76. private ulong txRequests = 0;
  77. private ulong txComplete = 0;
  78. private ulong rxTotal = 0;
  79. //FilterAdapter filterAdapter;
  80. [Microsoft.Contracts.NotDelayed]
  81. public Nic(NicDeviceContract/*.Imp*/ nicImp,
  82. NicDeviceProperties np,
  83. string nicName)
  84. {
  85. this.nicChannel = new TRef(nicImp);
  86. //assume np.DriverName != null;
  87. //assume np.MacAddress != null;
  88. this.driverName = np.DriverName;
  89. this.driverVersion = np.DriverName;
  90. this.macAddress = np.MacAddress;
  91. this.nicName = nicName;
  92. this.mtu = np.MtuBytes;
  93. this.maxTxPacketsInDevice = np.MaxTxPacketsInDevice;
  94. this.maxRxPacketsInDevice = np.MaxRxPacketsInDevice;
  95. this.maxTxFragmentsPerPacket = np.MaxTxFragmentsPerPacket;
  96. this.maxRxFragmentsPerPacket = np.MaxRxFragmentsPerPacket;
  97. this.muxEvent = new AutoResetEvent(false);
  98. // The following attributes are both integers yet
  99. // sgc is complaining it doesn't know to use
  100. // Math.Min(sbyte, sbyte) or Math.Min(byte, byte).
  101. int rxFifoSize = Math.Min(np.MaxRxPacketsInDevice,
  102. (int)Nic.MaxRxPacketsInDevice);
  103. this.rxFifo =
  104. new ExRefPacketFifo(
  105. new PacketFifo(rxFifoSize),
  106. false
  107. );
  108. // The following attributes are both integers yet
  109. // sgc is complaining it doesn't know to use
  110. // Math.Min(sbyte, sbyte) or Math.Min(byte, byte).
  111. int txFifoSize = Math.Min(np.MaxTxPacketsInDevice,
  112. (int)Nic.MaxTxPacketsInDevice);
  113. this.txFifo =
  114. new ExRefPacketFifo(
  115. new PacketFifo(txFifoSize),
  116. true
  117. );
  118. this.txFreeFifo =
  119. new ExRefPacketFifo(
  120. new PacketFifo(txFifoSize),
  121. true
  122. );
  123. this.txCoalesceFifo =
  124. new ExRefPacketFifo(
  125. new PacketFifo(txFifoSize),
  126. true
  127. );
  128. TxProvision();
  129. RxProvision();
  130. }
  131. int MaxRxPackets { get { return this.maxRxPacketsInDevice; } }
  132. public void NicDeviceEvent(NicEventType eventType)
  133. {
  134. if ((eventType & NicEventType.ReceiveEvent) != 0) {
  135. DeMuxReceivedPackets();
  136. }
  137. else {
  138. if ((eventType & NicEventType.TransmitEvent) != 0) {
  139. this.muxEvent.Set();
  140. //DebugStub.Print("Received transmit event\n");
  141. }
  142. if ((eventType & NicEventType.LinkEvent) != 0) {
  143. //DebugStub.Print("UNHANDLED link event!...acking anyway\n");
  144. }
  145. }
  146. }
  147. //
  148. // IAdapter interface
  149. //
  150. string IAdapter.DriverName
  151. {
  152. get { return this.driverName; }
  153. }
  154. string IAdapter.NicName
  155. {
  156. get { return this.nicName; }
  157. }
  158. string IAdapter.DriverVersion
  159. {
  160. get { return this.driverVersion; }
  161. }
  162. uint IAdapter.LinkSpeed { get { return 100000000; } }
  163. EthernetAddress IAdapter.HardwareAddress
  164. {
  165. get { return this.macAddress; }
  166. }
  167. [Conditional("DEBUG_NIC")]
  168. internal static void DebugPrint(string format,
  169. params object [] arguments)
  170. {
  171. DebugStub.Print("Nic {0}",
  172. DebugStub.ArgList(
  173. string.Format(format, arguments))
  174. );
  175. }
  176. //XXX On the first exchange we receive an empty fifo from the Nic
  177. //We fill it here...this should be special cased in the startio
  178. //routine...
  179. private void RxExchangeInternal(NicDeviceContract/*.Imp*/ imp)
  180. {
  181. int toCount, fromCount;
  182. PacketFifo exFifo = this.rxFifo.Acquire();
  183. toCount = exFifo.Count;
  184. try {
  185. exFifo = imp.GiveRxPacketsToDevice(exFifo);
  186. fromCount = exFifo.Count;
  187. }
  188. finally {
  189. this.rxFifo.Release(exFifo);
  190. }
  191. DebugPrint("RxExchange out: {0} in: {1}\n",
  192. toCount, fromCount);
  193. }
  194. private void RxExchange()
  195. {
  196. NicDeviceContract/*.Imp*/ imp = (NicDeviceContract)nicChannel.Acquire();
  197. try {
  198. RxExchangeInternal(imp);
  199. }
  200. finally {
  201. this.nicChannel.Release(imp);
  202. }
  203. }
  204. // Get the received packets from the adapter
  205. void DeMuxReceivedPackets()
  206. {
  207. //Grab the latest set of packets
  208. RxExchange();
  209. PacketFifo newPackets = this.rxFifo.Acquire();
  210. try {
  211. int count = newPackets.Count;
  212. for (int i = 0; i < count; i++) {
  213. Packet packet = newPackets.Pop();
  214. // If packet from device has an error
  215. // recycle it right away.
  216. FromDeviceFlags fromFlags = packet.FromDeviceFlags;
  217. if ((fromFlags & FromDeviceFlags.ReceiveError) != 0) {
  218. DebugStub.Print("Packet had error???\n");
  219. newPackets.Push(packet);
  220. continue;
  221. }
  222. Bytes data = packet.ReleaseFragment(0);
  223. Ethernet.ProcessIncomingPacket(data, this);
  224. #if false
  225. if (filterAdapter == null ||
  226. filterAdapter.ProcessIncomingPacket(data)) {
  227. Ethernet.ProcessIncomingPacket(data, this);
  228. }
  229. else {
  230. //delete data;
  231. }
  232. #endif
  233. //XXX Totally inefficient first try immediately replaces
  234. //the lost data.
  235. Bytes nxtPacket = new Bytes(new byte[this.mtu]);
  236. packet.SetFragment(0, nxtPacket);
  237. newPackets.Push(packet);
  238. }
  239. }
  240. finally {
  241. this.rxFifo.Release(newPackets);
  242. }
  243. }
  244. private void TxExchange()
  245. {
  246. int toCount = 0;
  247. int fromCount = 0;
  248. NicDeviceContract/*.Imp*/ imp = (NicDeviceContract)nicChannel.Acquire();
  249. try {
  250. PacketFifo src = this.txFifo.Acquire();
  251. PacketFifo free = this.txFreeFifo.Acquire();
  252. toCount = src.Count;
  253. try {
  254. src = imp.GiveTxPacketsToDevice(src);
  255. fromCount = src.Count;
  256. free.Push(src);
  257. }
  258. finally {
  259. this.txFreeFifo.Release(free);
  260. this.txFifo.Release(src);
  261. }
  262. }
  263. catch (Exception e) {
  264. DebugStub.Print("TxExchange FAILED arg {0}\n", DebugStub.ArgList(e.ToString()));
  265. DebugStub.Break();
  266. }
  267. finally {
  268. nicChannel.Release(imp);
  269. }
  270. DebugPrint("TxExchange out: {0} in: {1}\n",
  271. toCount, fromCount);
  272. }
  273. public void Run()
  274. {
  275. System.DebugStub.Print("Nic@" + Kernel.CurrentThread + ". ");
  276. while(true) {
  277. this.muxEvent.WaitOne();
  278. PacketFifo txCoalesce = this.txCoalesceFifo.Acquire();
  279. PacketFifo txToDevice = this.txFifo.Acquire();
  280. try {
  281. DebugPrint("coalescing {0} packets\n", txCoalesce.Count);
  282. txToDevice.Push(txCoalesce);
  283. }
  284. catch (Exception e) {
  285. DebugStub.Print("Mux FAILED! arg {0}\n", DebugStub.ArgList(e.ToString()));
  286. DebugStub.Break();
  287. }
  288. finally {
  289. this.txCoalesceFifo.Release(txCoalesce);
  290. this.txFifo.Release(txToDevice);
  291. TxExchange();
  292. }
  293. }
  294. }
  295. //push a single packet onto the ring
  296. void IAdapter.PopulateTxRing(Bytes header, Bytes data)
  297. {
  298. try {
  299. PacketFifo txFree = this.txFreeFifo.Acquire();
  300. PacketFifo txCoalesce = this.txCoalesceFifo.Acquire();
  301. try {
  302. DebugStub.Assert(txFree.Count > 0);
  303. int cnt = 0;
  304. while (txFree.Count <= 0) {
  305. //try again...
  306. //this happens when we're hammering the outgoing connection
  307. this.txCoalesceFifo.Release(txCoalesce);
  308. this.txFreeFifo.Release(txFree);
  309. this.muxEvent.Set();
  310. Thread.Yield();
  311. txFree = this.txFreeFifo.Acquire();
  312. txCoalesce = this.txCoalesceFifo.Acquire();
  313. if (cnt > 100) {
  314. DebugStub.Print("txFree empty???\n");
  315. //DebugStub.Break();
  316. }
  317. cnt++;
  318. }
  319. Packet packet = txFree.Pop();
  320. packet.SetFragment(0, header);
  321. packet.SetFragment(1, data);
  322. if ((txCoalesce.Count + 1) > txCoalesce.Capacity) {
  323. DebugStub.Break();
  324. }
  325. DebugStub.Assert((txCoalesce.Count + 1) <= txCoalesce.Capacity);
  326. txCoalesce.Push(packet);
  327. }
  328. catch {
  329. DebugStub.Print("failure in populate tx ring\n");
  330. DebugStub.Break();
  331. DebugStub.Assert(false);
  332. }
  333. finally {
  334. this.txCoalesceFifo.Release(txCoalesce);
  335. this.txFreeFifo.Release(txFree);
  336. //notify the mux that there are waiting packets
  337. this.muxEvent.Set();
  338. }
  339. }
  340. catch (Exception e) {
  341. DebugStub.Print("Populate tx ring failed?? {0}\n", DebugStub.ArgList(e));
  342. DebugStub.Break();
  343. }
  344. }
  345. #if false
  346. //push a single packet onto the ring
  347. void IAdapter.PopulateTxRing(Bytes header, Bytes data)
  348. {
  349. try {
  350. PacketFifo txFree = this.txFreeFifo.Acquire();
  351. PacketFifo txToDevice = this.txFifo.Acquire();
  352. DebugPrint("populate tx ring\n");
  353. try {
  354. Packet packet = txFree.Pop();
  355. packet.SetFragment(0, header);
  356. packet.SetFragment(1, data);
  357. txToDevice.Push(packet);
  358. }
  359. finally {
  360. this.txFreeFifo.Release(txFree);
  361. this.txFifo.Release(txToDevice);
  362. }
  363. }
  364. catch (Exception e) {
  365. DebugStub.Print("Populate tx ring failed?? {0}\n", DebugStub.ArgList(e));
  366. DebugStub.Break();
  367. }
  368. //When to exchange?
  369. //how do we best manage the tradeoff of throughput and latency?
  370. //to begin let's just send one at a time.
  371. //I think i'd rather have another thread....
  372. using (thisLock.Lock()) {
  373. TxExchange();
  374. }
  375. }
  376. #endif
  377. private bool
  378. ConfigureEventChannel(NicDeviceContract nicImp)
  379. {
  380. nicImp.RegisterForEvents(this);
  381. return true;
  382. }
  383. private bool
  384. ConfigureChecksumProperties(NicDeviceContract/*.Imp*/ nicImp)
  385. {
  386. nicImp.SetChecksumProperties(0);
  387. return true;
  388. }
  389. private bool Configure()
  390. {
  391. NicDeviceContract/*.Imp*/ nicImp = (NicDeviceContract)nicChannel.Acquire();
  392. try {
  393. nicImp.ConfigureIO();
  394. if (ConfigureEventChannel(nicImp) == true &&
  395. ConfigureChecksumProperties(nicImp) == true) {
  396. return true;
  397. }
  398. }
  399. catch (SystemException e) {
  400. DebugStub.WriteLine("System exception occurred in Nic.Configure().");
  401. DebugStub.WriteLine(e.ToString());
  402. DebugStub.Break();
  403. }
  404. finally {
  405. nicChannel.Release(nicImp);
  406. }
  407. DebugStub.Break();
  408. return false;
  409. }
  410. private void RxProvisionInternal(PacketFifo toDevice)
  411. {
  412. for (int i = 0; i < toDevice.Capacity; i++) {
  413. toDevice.Push(
  414. new Packet(
  415. new Bytes(new byte[this.mtu])
  416. )
  417. );
  418. }
  419. }
  420. private void RxProvision()
  421. {
  422. PacketFifo toDevice = this.rxFifo.Acquire();
  423. RxProvisionInternal(toDevice);
  424. this.rxFifo.Release(toDevice);
  425. }
  426. //since data comes from the user, the packets are empty shells
  427. //with a default of two fragments; one for the header and one for
  428. //the packet body
  429. private void TxProvision()
  430. {
  431. PacketFifo txFree = this.txFreeFifo.Acquire();
  432. for (int i = 0; i < txFree.Capacity; i++) {
  433. txFree.Push(
  434. new Packet(2)
  435. );
  436. }
  437. this.txFreeFifo.Release(txFree);
  438. }
  439. private bool StartIO()
  440. {
  441. NicDeviceContract/*.Imp*/ imp = (NicDeviceContract)nicChannel.Acquire();
  442. try {
  443. imp.StartIO();
  444. RxExchangeInternal(imp);
  445. return true;
  446. }
  447. finally {
  448. nicChannel.Release(imp);
  449. }
  450. //DebugStub.Break();
  451. //return false;
  452. }
  453. private bool StopIO()
  454. {
  455. NicDeviceContract/*.Imp*/ imp = (NicDeviceContract)nicChannel.Acquire();
  456. try {
  457. imp.StopIO();
  458. return true;
  459. }
  460. finally {
  461. nicChannel.Release(imp);
  462. }
  463. //return false;
  464. }
  465. //
  466. // Factory methods
  467. //
  468. internal static NicDeviceProperties
  469. GetNicProperties(NicDeviceContract/*.Imp*/ imp)
  470. {
  471. return imp.GetDeviceProperties();
  472. }
  473. public static bool
  474. CreateAndRegister(NicDeviceContract/*.Imp*/ imp,
  475. string nicName)
  476. {
  477. Nic nic = null;
  478. try {
  479. //imp.RecvSuccess();
  480. DebugPrint("Nic channel transition\n");
  481. NicDeviceProperties np = GetNicProperties(imp);
  482. if (np == null) {
  483. //delete imp;
  484. return false;
  485. }
  486. nic = new Nic(imp, np, nicName);
  487. //delete np;
  488. if (nic.Configure() == false) {
  489. return false;
  490. }
  491. DebugPrint("Nic.cs: Register adapter\n");
  492. HostConfiguration hostConfiguration = IP.GetHostConfiguration();
  493. // nic.filterAdapter= null;
  494. #if false
  495. nic.filterAdapter = new FilterAdapter(nic);
  496. hostConfiguration.RegisterAdapter(nic.filterAdapter);
  497. #endif
  498. hostConfiguration.RegisterAdapter(nic);
  499. nic.StartIO();
  500. Thread muxThread = new Thread(nic);
  501. muxThread.Start();
  502. return true;
  503. }
  504. catch {
  505. //delete imp;
  506. DebugStub.Break();
  507. return false;
  508. }
  509. }
  510. }
  511. }