AntHocNet 2.0.0
Paper-faithful ant-colony ad hoc routing: the shared core and its adapters
Loading...
Searching...
No Matches
ant_router_logic.h
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright (C) 2026 Daniel Henrique Joppi
3
4/**
5 * AntRouterLogic: the shared, simulator-agnostic AntHocNet state machine.
6 *
7 * This is the former AntNest + the decision parts of the AntHocNet agent,
8 * with all NS-2 packet/scheduler coupling removed. It owns a node's routing
9 * state (pheromone table, dedup history, sequence counter) and turns received
10 * ants and local data demands into RouteDecisions for the adapter to execute.
11 *
12 * It is deliberately free of I/O: time and randomness come through ports, and
13 * outputs are returned as values. That makes the routing behaviour identical
14 * across NS-2 and NS-3 and testable on its own.
15 */
16#ifndef ANTHOCNET_CORE_ANT_ROUTER_LOGIC_H
17#define ANTHOCNET_CORE_ANT_ROUTER_LOGIC_H
18
19#include <map>
20#include <utility>
21#include <vector>
22
32
33namespace anthocnet {
34namespace core {
35
37public:
38 /// `metric` selects the pheromone formula (item 16); nullptr uses the
39 /// canonical ClassicMetric. `linkState` supplies MAC-layer congestion
40 /// signals for the item-10/A2 metric (nullptr => wall-clock per-hop time).
41 /// Both default to null, so existing adapter call sites are unchanged.
43 const ILinkMetric* metric = nullptr,
44 const ILinkState* linkState = nullptr);
45
46 NodeAddress address() const { return address_; }
47 const Config& config() const { return config_; }
48 PheromoneTable& table() { return table_; }
49 const PheromoneTable& table() const { return table_; }
50 PheromoneEngine& engine() { return engine_; }
51
52 // --- observability (item 15) -----------------------------------------
53 /// Attach an optional observer for ant/route events (nullptr to detach).
54 /// Zero-overhead when unset; the observer only reports, never decides.
55 void setObserver(IRouterObserver* observer) { observer_ = observer; }
56 /// Ants of `type` this node has put on the medium (origination + forward).
57 std::uint64_t antsSent(AntType type) const;
58 /// Non-duplicate ants of `type` this node has received and processed.
59 std::uint64_t antsReceived(AntType type) const;
60 /// Total ant control packets sent across all types (routing overhead).
61 std::uint64_t controlPacketsSent() const;
62 /// LinkFail notes this node re-broadcast on another reporter's behalf
63 /// (issue #20: origins = antsSent(LinkFail) − propagations).
64 std::uint64_t linkfailPropagations() const { return linkfailPropagations_; }
65 /// LinkFail propagations suppressed by an exhausted inherited
66 /// broadcastBudget — how often the depth bound actually bites (issue #20).
67 std::uint64_t linkfailBudgetDrops() const { return linkfailBudgetDrops_; }
68 /// Per-destination advertisements dropped by the origin cooldown
69 /// (config.linkfailNotifyInterval, issue #20).
70 std::uint64_t linkfailOriginsSuppressed() const { return linkfailOriginsSuppressed_; }
71 /// Reactive forward ants steered along the diffusion gradient instead of
72 /// being broadcast (config.enableDirectedReactive). This is the number that
73 /// says whether directed discovery is doing anything at all: zero means the
74 /// virtual table never held a hint where the regular one was empty, so the
75 /// gate is inert rather than harmful.
76 std::uint64_t directedSteers() const { return directedSteers_; }
77 /// Local repairs that expired without a backward ant and therefore released
78 /// the data buffered for their destination — the number of DiscardPending
79 /// decisions this node has emitted ([1] §3.5, D6; drop-cause breakdown,
80 /// issue #215). This is the *event* count: the adapter owns the pending
81 /// queue, so only it knows how many packets each discard released. Counted
82 /// here so the cause stays simulator-agnostic and both adapters get it.
83 std::uint64_t repairDiscards() const { return repairDiscards_; }
84
85 // --- neighbour learning ----------------------------------------------
86 /// Record that `neighbor` is reachable (link-layer detection / hello),
87 /// seeding an equal-weight regular pheromone entry as the legacy code did.
88 void learnNeighbor(NodeAddress neighbor);
89 void loseNeighbor(NodeAddress neighbor);
90
91 /// Periodic liveness/maintenance tick (driven by the adapter hello timer):
92 /// expire neighbours not heard from within helloInterval*allowedHelloLoss
93 /// (the portable, NS-3-mandatory detector — ADR-0008) and return any
94 /// link-failure notifications to broadcast. Also expires timed-out local
95 /// repairs ([1] §3.5, D6): a repair with no backward ant within its wait
96 /// window yields a DiscardPending for the destination's buffered packets
97 /// plus a LinkFail notification.
98 std::vector<RouteDecision> onMaintenanceTick();
99
100 /// Remove neighbour `n` and, for every destination whose best path it
101 /// carried, broadcast a LinkFail notification with the new best (0 if the
102 /// route is gone). Used by both the maintenance tick and an adapter's
103 /// MAC transmit-failure hook (ADR-0008 detectors A and D converge here).
104 std::vector<RouteDecision> reportNeighborLoss(NodeAddress n);
105
106 /// Adapter MAC transmit-failure hook (ADR-0008 detector D): a failed unicast
107 /// to `next` means the link is down. Prune the neighbour (emitting any
108 /// LinkFail notifications, exactly as detector A does) and, when the failed
109 /// packet was *data* (`dataDest` set), broadcast a bounded, counted local
110 /// repair ant toward it so the route is rebuilt immediately ([1] §3.5).
111 /// Mirrors the NS-2 `ahn_router` linkFailed path; both adapters call this.
112 std::vector<RouteDecision> reportTxFailure(NodeAddress next,
113 NodeAddress dataDest = kInvalidAddress);
114
115 // --- active sessions (proactive monitoring, item 04) ------------------
116 /// Record that this node just originated data for `dest`, making it an
117 /// active session that proactive ants will monitor (call from the adapter
118 /// data path when the packet is locally originated).
120 /// Destinations with data sent within `config_.sessionTtl` (const query).
121 std::vector<NodeAddress> activeDestinations() const;
122 /// One proactive forward ant per active destination (empty if none or if
123 /// `!config_.enableProactive`), subject to the thesis emission gate
124 /// `shouldSendProactive()`. Also prunes expired sessions.
125 std::vector<AntMessage> createProactiveAnts();
126 /// The thesis's emission gate, re-derived per-link (#180, ADR-0018): true
127 /// when some neighbour's virtual pheromone for `dest` beats the regular
128 /// pheromone ON THE SAME LINK by `config_.proactiveVirtualMargin`, or the
129 /// hint sits on an unsampled link (or the gate does not apply — see the
130 /// definition for the boundary cases). Exposed for tests/observability;
131 /// `createProactiveAnts()` calls it.
133
134 // --- ant construction -------------------------------------------------
136 AntMessage createHelloAnt(); // caps adverts at Config::maxHelloAdverts
137 AntMessage createHelloAnt(std::size_t maxAdverts);
138 /// Build the backward ant for a forward ant that reached this node
139 /// (this == dst). The returned message's `nextHop` is via firstBackHop().
141
142 // --- routing primitives ----------------------------------------------
143 /// Stochastic next hop for `dest` using the ant exponent betaAnts
144 /// (kInvalidAddress if no route). Serves reactive and proactive ants.
145 NodeAddress selectNextHop(NodeAddress dest, bool proactive);
146 /// Stochastic next hop for a *data* packet, using the greedier data
147 /// exponent betaData (kInvalidAddress if no route). `prevHop` is excluded
148 /// unless it is the only option, to suppress data loops (A1).
150 /// Pick a random known destination for a proactive ant (or kInvalidAddress).
152
153 /// Append this node to a forward ant's visited stack, recording this hop's
154 /// cost (congestion-aware MAC estimate when enabled, else wall-clock delta).
155 /// `nextHop` is the interface the ant leaves by, so the congestion signal
156 /// is read for the queue it will actually wait in; kInvalidAddress when
157 /// there is no single one (broadcast, or this node is the destination) —
158 /// the ILinkState then aggregates (#206). Bounded by Config::maxPathLength.
159 void stampForward(AntMessage& ant, NodeAddress nextHop) const;
160
161 /// Advance a backward ant by one hop: move this node from the visited stack
162 /// onto `history` and return the next hop (path management only; the deposit
163 /// state is reconstructed at the receiver from `history`, ADR-0009).
165
166 /// Pheromone this back ant would deposit at the current node, reconstructed
167 /// from its `history` (hops + summed per-hop times) via the link metric.
168 double backAntPheromone(const AntMessage& ant) const;
169
170 /// Update the regular pheromone table from a backward ant that arrived
171 /// here (reinforce the link it came from).
173
174 // --- consolidated receive --------------------------------------------
175 /// Process a received ant arriving from `prevHop`. Performs (src,seq)
176 /// dedup and neighbour learning, then dispatches by type/direction,
177 /// returning the actions the adapter must carry out. May return an empty
178 /// vector (nothing to do) or a single Drop.
179 std::vector<RouteDecision> onReceiveAnt(const AntMessage& ant, NodeAddress prevHop);
180
181 /// Decide what to do with a locally-originated or in-transit *data* packet
182 /// destined for `dest`: route it (Unicast), or (no route) request one and
183 /// Queue it. The adapter emits the returned reactive forward ant, if any.
184 std::vector<RouteDecision> onDataPacket(NodeAddress dest,
185 NodeAddress prevHop = kInvalidAddress);
186
187private:
188 std::uint32_t nextSeq() { return seqNum_++; }
189
190 /// Turn a forward/notification ant into a Broadcast decision, honouring its
191 /// broadcastBudget: an untracked ant (-1) always broadcasts; a budgeted ant
192 /// decrements and broadcasts while >0, and is Dropped once exhausted.
193 RouteDecision broadcastForward(AntMessage& ant);
194 /// Build a Unicast/Broadcast decision carrying `ant`, counting it as sent
195 /// and notifying the observer (the single choke point for ant emission).
196 RouteDecision sendAnt(RouteAction action, NodeAddress nextHop, const AntMessage& ant);
197 /// Apply a received LinkFail notification and, if it costs this node its own
198 /// best path, return a bounded propagated notification.
199 std::vector<RouteDecision> handleLinkFail(const AntMessage& note, NodeAddress reporter);
200
201 /// Fill the transient deposit state (prevHop/hops/pathTime/pheromone) of a
202 /// received backward ant from its `history`, before reinforcement.
203 void computeBackAntState(AntMessage& ant) const;
204
205 /// This node's contribution to a forward ant's path-time estimate: the
206 /// congestion-aware MAC cost (Q_mac+1)*T̂_mac toward `nextHop` when enabled
207 /// and available, else the ant's wall-clock transit delta since the
208 /// previous stamp.
209 double localHopCost(const AntMessage& ant, NodeAddress nextHop) const;
210
211 NodeAddress address_;
212 Config config_;
213 IClock& clock_;
214 IRng& rng_;
215 PheromoneTable table_;
216 PheromoneEngine engine_;
217 ClassicMetric defaultMetric_; ///< used when no metric is injected
218 const ILinkMetric* metric_; ///< pheromone strategy (item 16)
219 const ILinkState* linkState_; ///< MAC congestion signals (item 10/A2), optional
220 AntHistoryTracker history_;
221 GenerationTracker genQuality_; ///< multipath acceptance filter (#96)
222 std::uint32_t seqNum_ = 0;
223 std::map<NodeAddress, double> activeSessions_; ///< dest -> last data-send time
224 std::map<NodeAddress, double> lastSeen_; ///< neighbor -> last reception time
225 /// #185: smoothed hop count ĥ per (destination, next hop), the thesis's
226 /// eq. 4.2 state. Only populated when Config::hopCountAlpha > 0; entries for
227 /// a neighbour are erased with it (loseNeighbor), so it is bounded by the
228 /// same (dest, neighbour) set as the regular pheromone table.
229 std::map<std::pair<NodeAddress, NodeAddress>, double> hopEstimate_;
230 std::map<NodeAddress, double> lastReactive_; ///< dest -> last reactive-ant time
231 std::map<NodeAddress, double> lastRepair_; ///< dest -> last repair-ant time
232 std::map<NodeAddress, double> repairDeadline_; ///< dest -> repair wait expiry (D6)
233 std::map<NodeAddress, int> txFailures_; ///< next hop -> consecutive MAC tx-failures (detector D debounce)
234 double lastEvaporation_ = 0.0; ///< last evaporateAll time
235
236 IRouterObserver* observer_ = nullptr; ///< optional, item 15
237 std::map<AntType, std::uint64_t> antsSent_; ///< sent counters by type
238 std::map<AntType, std::uint64_t> antsReceived_; ///< received counters by type
239 std::uint64_t linkfailPropagations_ = 0; ///< re-broadcast LinkFails (issue #20)
240 std::uint64_t linkfailBudgetDrops_ = 0; ///< budget-suppressed propagations (issue #20)
241 std::uint64_t linkfailOriginsSuppressed_ = 0; ///< cooldown-suppressed advertisements (issue #20)
242 std::uint64_t repairDiscards_ = 0; ///< expired local repairs that discarded pending data (#215)
243 std::uint64_t directedSteers_ = 0; ///< reactive ants unicast along the diffusion gradient
244 std::map<NodeAddress, double> lastLinkfailNotify_; ///< dest -> last originated LinkFail time
245};
246
247} // namespace core
248} // namespace anthocnet
249
250#endif // ANTHOCNET_CORE_ANT_ROUTER_LOGIC_H
AntMessage createHelloAnt(std::size_t maxAdverts)
NodeAddress selectNextHop(NodeAddress dest, bool proactive)
Stochastic next hop for dest using the ant exponent betaAnts (kInvalidAddress if no route).
void stampForward(AntMessage &ant, NodeAddress nextHop) const
Append this node to a forward ant's visited stack, recording this hop's cost (congestion-aware MAC es...
void setObserver(IRouterObserver *observer)
Attach an optional observer for ant/route events (nullptr to detach).
AntMessage createBackAnt(const AntMessage &forward)
Build the backward ant for a forward ant that reached this node (this == dst).
std::uint64_t repairDiscards() const
Local repairs that expired without a backward ant and therefore released the data buffered for their ...
void reinforceFromBackAnt(const AntMessage &ant)
Update the regular pheromone table from a backward ant that arrived here (reinforce the link it came ...
std::vector< RouteDecision > reportTxFailure(NodeAddress next, NodeAddress dataDest=kInvalidAddress)
Adapter MAC transmit-failure hook (ADR-0008 detector D): a failed unicast to next means the link is d...
std::uint64_t antsSent(AntType type) const
Ants of type this node has put on the medium (origination + forward).
NodeAddress advanceBackAnt(AntMessage &ant) const
Advance a backward ant by one hop: move this node from the visited stack onto history and return the ...
std::vector< RouteDecision > reportNeighborLoss(NodeAddress n)
Remove neighbour n and, for every destination whose best path it carried, broadcast a LinkFail notifi...
const PheromoneTable & table() const
bool shouldSendProactive(NodeAddress dest) const
The thesis's emission gate, re-derived per-link (#180, ADR-0018): true when some neighbour's virtual ...
std::uint64_t controlPacketsSent() const
Total ant control packets sent across all types (routing overhead).
std::vector< NodeAddress > activeDestinations() const
Destinations with data sent within config_.sessionTtl (const query).
AntRouterLogic(NodeAddress address, const Config &config, IClock &clock, IRng &rng, const ILinkMetric *metric=nullptr, const ILinkState *linkState=nullptr)
metric selects the pheromone formula (item 16); nullptr uses the canonical ClassicMetric.
void learnNeighbor(NodeAddress neighbor)
Record that neighbor is reachable (link-layer detection / hello), seeding an equal-weight regular phe...
void noteDataSession(NodeAddress dest)
Record that this node just originated data for dest, making it an active session that proactive ants ...
void loseNeighbor(NodeAddress neighbor)
std::vector< RouteDecision > onReceiveAnt(const AntMessage &ant, NodeAddress prevHop)
Process a received ant arriving from prevHop.
std::uint64_t linkfailPropagations() const
LinkFail notes this node re-broadcast on another reporter's behalf (issue #20: origins = antsSent(Lin...
std::vector< RouteDecision > onDataPacket(NodeAddress dest, NodeAddress prevHop=kInvalidAddress)
Decide what to do with a locally-originated or in-transit data packet destined for dest: route it (Un...
const Config & config() const
double backAntPheromone(const AntMessage &ant) const
Pheromone this back ant would deposit at the current node, reconstructed from its history (hops + sum...
std::vector< AntMessage > createProactiveAnts()
One proactive forward ant per active destination (empty if none or if !config_.enableProactive),...
NodeAddress randomDestination()
Pick a random known destination for a proactive ant (or kInvalidAddress).
std::uint64_t linkfailBudgetDrops() const
LinkFail propagations suppressed by an exhausted inherited broadcastBudget — how often the depth boun...
AntMessage createForwardAnt(AntType type, NodeAddress dest)
std::vector< RouteDecision > onMaintenanceTick()
Periodic liveness/maintenance tick (driven by the adapter hello timer): expire neighbours not heard f...
std::uint64_t antsReceived(AntType type) const
Non-duplicate ants of type this node has received and processed.
std::uint64_t directedSteers() const
Reactive forward ants steered along the diffusion gradient instead of being broadcast (config....
std::uint64_t linkfailOriginsSuppressed() const
Per-destination advertisements dropped by the origin cooldown (config.linkfailNotifyInterval,...
NodeAddress nextHopForData(NodeAddress dest, NodeAddress prevHop=kInvalidAddress)
Stochastic next hop for a data packet, using the greedier data exponent betaData (kInvalidAddress if ...
Multipath acceptance filter for reactive forward ants ([1] §3.1, issue #96).
Definition ant_history.h:63
Source of simulation time (seconds).
Definition ports.h:24
Node-local MAC-layer signals for the congestion-aware per-hop metric (item 10/A2, [1] §3....
Definition ports.h:69
Source of randomness.
Definition ports.h:33
Optional observer the core notifies of routing events (item 15).
Definition ports.h:90
constexpr NodeAddress kInvalidAddress
"No such node / no route" sentinel, mirroring the legacy use of -1.
Definition types.h:27
std::int32_t NodeAddress
Network-layer node address.
Definition types.h:21
AntType
Ant role.
Definition ant_message.h:25
AntHistoryTracker: (src, seqNum) duplicate detection.
Definition ant_history.h:24
Complete, copyable description of an ant packet.
Definition ant_message.h:48
The canonical AntHocNet metric (Eq.2): blend the path-time estimate with the hop-count estimate and i...
Definition link_metric.h:40
Maps an observation to a pheromone (goodness; higher == better).
Definition link_metric.h:33