56 TypeId(
"q2ns::SwapApp")
57 .SetParent<Application>()
59 .AddTraceSource(
"RoundStart",
"Session round begins (sid,time).",
61 "ns3::TracedCallback::Uint64Time")
62 .AddTraceSource(
"BSMDone",
"Repeater BSM complete (sid,time,m1,m2).",
64 "ns3::TracedCallback::Uint64TimeTimeUint8Uint8")
65 .AddTraceSource(
"CtrlSent",
"Repeater sent ctrl bits (sid,time,m1,m2).",
67 "ns3::TracedCallback::Uint64TimeTimeUint8Uint8")
68 .AddTraceSource(
"FrameResolved",
"Endpoint accumulated all BSMs (sid,time,M1,M2).",
70 "ns3::TracedCallback::Uint64TimeTimeUint8Uint8")
71 .AddTraceSource(
"CorrectionApplied",
72 "Emitted when the sink applies final Pauli corrections for a session.",
74 "ns3::TracedCallback<uint64_t, ns3::Time>")
75 .AddTraceSource(
"VerifyFidelity",
"Endpoint Bell fidelity check (sid,time,value,stderr).",
77 "ns3::TracedCallback::Uint64TimeDoubleDouble");
84 if (
auto qnode = ns3::DynamicCast<q2ns::QNode>(GetNode())) {
85 qnode->SetRecvCallback([
this](std::shared_ptr<q2ns::Qubit> q) {
88 const std::string& L = q->GetLabel();
89 constexpr const char* PFX_LIN =
"swap_in_from_prev_s";
90 constexpr const char* PFX_RIN =
"swap_in_from_next_s";
92 if (L.rfind(PFX_LIN, 0) == 0) {
93 uint64_t sid = std::strtoull(L.c_str() + std::strlen(PFX_LIN), nullptr, 10);
94 auto it = m_sessions.find(sid);
95 if (it != m_sessions.end()) {
98 s.qPrev = std::move(q);
101 if ((s.cfg.role == Role::Repeater) && s.qNext && !s.haveBSM) {
102 MaybeDoBsmAndAnnounce(s);
106 if (s.cfg.role != Role::Repeater && !s.haveQ) {
107 s.targetQubit = s.qPrev;
113 }
else if (L.rfind(PFX_RIN, 0) == 0) {
114 uint64_t sid = std::strtoull(L.c_str() + std::strlen(PFX_RIN), nullptr, 10);
115 auto it = m_sessions.find(sid);
116 if (it != m_sessions.end()) {
117 auto& s = it->second;
119 s.qNext = std::move(q);
122 if ((s.cfg.role == Role::Repeater) && s.qPrev && !s.haveBSM) {
123 MaybeDoBsmAndAnnounce(s);
127 if (s.cfg.role != Role::Repeater && !s.haveQ) {
128 s.targetQubit = s.qNext;
138 for (
auto& kv : m_sessions) {
139 ScheduleSession(kv.second);
174 auto it = m_sessions.find(sid);
175 if (it == m_sessions.end())
177 m_traceRoundStart(sid, ns3::Simulator::Now());
179 auto& st = it->second;
181 switch (st.cfg.role) {
195 auto qnode = ns3::DynamicCast<q2ns::QNode>(GetNode());
196 NS_ASSERT_MSG(qnode,
"SwapApp(repeater) must run on a QNode");
200 auto bellR = qnode->CreateBellPair();
201 s.
qNext = bellR.first;
202 auto rRemote = bellR.second;
203 rRemote->SetLabel(std::string(
"swap_in_from_prev_s") + std::to_string(s.
cfg.
sid));
205 NS_ASSERT_MSG(okR,
"Send(next) failed");
210 auto bellL = qnode->CreateBellPair();
211 s.
qPrev = bellL.first;
212 auto lRemote = bellL.second;
213 lRemote->SetLabel(std::string(
"swap_in_from_next_s") + std::to_string(s.
cfg.
sid));
215 NS_ASSERT_MSG(okL,
"Send(prev) failed");
219 MaybeDoBsmAndAnnounce(s);
243void SwapApp::EnsureSink(uint16_t port,
const std::string& proto) {
244 if (m_sinksByPort.count(port))
248 const std::string factory =
249 (proto ==
"tcp" || proto ==
"TCP") ?
"ns3::TcpSocketFactory" :
"ns3::UdpSocketFactory";
250 ApplicationContainer apps;
252 PacketSinkHelper sinkHelper(factory, Inet6SocketAddress(Ipv6Address::GetAny(), port));
253 apps = sinkHelper.Install(GetNode());
255 PacketSinkHelper sinkHelper(factory, InetSocketAddress(Ipv4Address::GetAny(), port));
256 apps = sinkHelper.Install(GetNode());
259 auto sink = ns3::DynamicCast<ns3::PacketSink>(apps.Get(0));
264 m_sinksByPort.emplace(port, sink);
268void SwapApp::OnCtrlRx(ns3::Ptr<const ns3::Packet> pkt,
const ns3::Address& from) {
271 NS_LOG_WARN(
"In OnCtrlRx. pkt is nullptr.");
275 if (pkt->GetSize() <
sizeof(hdr)) {
276 NS_LOG_WARN(
"In OnCtrlRx. pkt is too small.");
279 pkt->CopyData(
reinterpret_cast<uint8_t*
>(&hdr),
sizeof(hdr));
281 auto it = m_sessions.find(hdr.sid);
282 if (it == m_sessions.end())
284 auto& s = it->second;
290 NS_LOG_INFO(
"EP sid=" << s.cfg.sid <<
" recv=" << s.recv <<
" expect=" << s.cfg.expectedMsgs
291 <<
" M=(" <<
int(s.accumM1) <<
"," <<
int(s.accumM2) <<
")");
292 if (s.recv >= s.cfg.expectedMsgs) {
295 m_traceFrameResolved(s.cfg.sid, ns3::Simulator::Now(), s.accumM1, s.accumM2);
303 auto qnode = ns3::DynamicCast<q2ns::QNode>(GetNode());
307 auto bits = qnode->MeasureBell(s.
qPrev, s.
qNext);
310 uint8_t
m1 =
static_cast<uint8_t
>(bits.first);
311 uint8_t
m2 =
static_cast<uint8_t
>(bits.second);
312 m_traceBSMDone(s.
cfg.
sid, ns3::Simulator::Now(),
m1,
m2);
316 std::vector<uint8_t> buf(std::max<uint32_t>(
sizeof(
CtrlHeader), m_payloadBytes), 0);
317 std::memcpy(buf.data(), &hdr,
sizeof(
CtrlHeader));
318 ns3::Ptr<ns3::Packet> pkt = ns3::Create<ns3::Packet>(buf.data(), buf.size());
321 auto sendV4 = [&](
const ns3::Ipv4Address& dst) {
322 if (dst == ns3::Ipv4Address(
"0.0.0.0"))
325 auto sock = GetOrCreateUdpSender(s.
cfg.
ctrlPort,
false);
326 sock->SendTo(pkt->Copy(), 0, ns3::InetSocketAddress(dst, s.
cfg.
ctrlPort));
328 ns3::Address a = ns3::InetSocketAddress(dst, s.
cfg.
ctrlPort);
329 auto sock = GetOrCreateTcpSender(a,
false, s.
cfg.
ctrlPort);
330 auto id =
reinterpret_cast<uintptr_t
>(PeekPointer(sock));
332 int sent = sock->Send(pkt->Copy());
333 if (sent < 0 && sock->GetErrno() == ns3::Socket::ERROR_NOTCONN) {
334 m_tcpPendingOnce[id] = pkt->Copy();
339 auto sendV6 = [&](
const ns3::Ipv6Address& dst6) {
340 if (dst6 == ns3::Ipv6Address::GetAny())
343 ns3::Ptr<ns3::Socket> sock =
344 ns3::Socket::CreateSocket(GetNode(), ns3::UdpSocketFactory::GetTypeId());
346 sock->Connect(ns3::Inet6SocketAddress(dst6, s.
cfg.
ctrlPort));
347 sock->Send(pkt->Copy());
350 ns3::Address a = ns3::Inet6SocketAddress(dst6, s.
cfg.
ctrlPort);
351 auto sock = GetOrCreateTcpSender(a,
true, s.
cfg.
ctrlPort);
352 auto id =
reinterpret_cast<uintptr_t
>(PeekPointer(sock));
353 int sent = sock->Send(pkt->Copy());
354 if (sent < 0 && sock->GetErrno() == ns3::Socket::ERROR_NOTCONN) {
355 m_tcpPendingOnce[id] = pkt->Copy();
371 m_traceCtrlSent(s.
cfg.
sid, ns3::Simulator::Now(),
m1,
m2);
383 auto qnode = ns3::DynamicCast<q2ns::QNode>(GetNode());
397 auto qnode = ns3::DynamicCast<q2ns::QNode>(GetNode());
401 if (actual && actual->NumQubits() == 2) {
403 auto refBell = qnode->CreateBellPair();
404 auto ref = m_nc->GetState(refBell.first);
408 m_traceVerifyFidelity(s.
cfg.
sid, ns3::Simulator::Now(), f);
410 NS_LOG_INFO(
"Final State:\n" << actual);
413 NS_LOG_WARN(
"Swap fidelity check FAILED for sid=" << s.
cfg.
sid <<
" value=" << f
424 m_traceCorrectionApplied(s.
cfg.
sid, ns3::Simulator::Now());
446ns3::Ptr<ns3::Socket> SwapApp::GetOrCreateUdpSender(uint16_t port,
bool v6) {
448 auto& map = v6 ? m_udp6 : m_udp4;
449 auto it = map.find(port);
453 Ptr<Socket> s = Socket::CreateSocket(GetNode(), UdpSocketFactory::GetTypeId());
456 s->Bind(Inet6SocketAddress(Ipv6Address::GetAny(), 0));
458 s->Bind(InetSocketAddress(Ipv4Address::GetAny(), 0));
459 map.emplace(port, s);
463ns3::Ptr<ns3::Socket> SwapApp::GetOrCreateTcpSender(
const ns3::Address& dst,
bool v6,
467 std::ostringstream oss;
469 Inet6SocketAddress a = Inet6SocketAddress::ConvertFrom(dst);
472 InetSocketAddress a = InetSocketAddress::ConvertFrom(dst);
475 TcpKey key{v6, port, oss.str()};
476 auto it = m_tcp.find(key);
477 if (it != m_tcp.end())
480 Ptr<Socket> sock = Socket::CreateSocket(GetNode(), TcpSocketFactory::GetTypeId());
481 sock->SetConnectCallback(MakeCallback(&SwapApp::OnTcpConnected,
this),
482 MakeCallback(&SwapApp::OnTcpConnectFail,
this));
486 m_tcp.emplace(key, sock);
491ns3::Ptr<ns3::Socket> SwapApp::GetOrCreateUdpV6Connected(
const ns3::Ipv6Address& dst,
495 std::ostringstream oss;
497 TcpKey key{
true, port, oss.str()};
498 auto it = m_udp6_conn.find(key);
499 if (it != m_udp6_conn.end())
502 Ptr<Socket> s = Socket::CreateSocket(GetNode(), UdpSocketFactory::GetTypeId());
504 s->Connect(Inet6SocketAddress(dst, port));
505 m_udp6_conn.emplace(key, s);