You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit bc2c8ac
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: modules/clusterer_controller/README.md
+4-1Lines changed: 4 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -152,6 +152,7 @@ Each property is checked by the network-namespace suite (*test/netns_tests.sh*,
152
152
| Several nodes joining at once, and a whole cluster starting cold at once, get one master and distinct node ids | T31 | - |
153
153
| A JOIN_REJECT recorded and sent again does not stop a joining node; one it earns still does | T32 | - |
154
154
| A node's packets recorded and sent again from another address meet that node's replay window: its old GOODBYE removes nothing | T33 | - |
155
+
| A JOIN_REQ recorded and sent again from another address admits nobody again and draws no reply there | T34 | - |
155
156
156
157
Not tested yet: a full peer table; a static *clusterer* cluster beside controller clusters on one node.
157
158
@@ -188,6 +189,8 @@ The session key is generated once, when the first node bootstraps the cluster, a
188
189
189
190
Every JOIN_REJECT carries the nonce of the packet it refuses, and the joining side acts on it only if that nonce is one of its own last JOIN_REQs. Bootstrap packets have no replay window, so this is what keeps a refusal recorded once - say, while the node had a wrong password - from being sent again by anyone on the group to stop the node at a later start. A refusal from an older master, which carries no nonce, is still acted on for different settings or a different MTU, which the node checks against what it runs, but not for the bare refusal.
190
191
192
+
The two bootstrap packets that change state where they land are guarded the same way: a JOIN_REQ or beacon seen lately - by its header nonce, random per packet - is dropped as a repeat, and one from a previous life of a node whose current life is still heard (an incarnation lower than the one held, from a node heard within two query periods) is dropped too; a node that really restarted with a lower incarnation, its clock stepped back, is let in once its old life has fallen silent. A master's replies to a JOIN_REQ go to the joiner at its own address, and a MASTER_PROBE or RESYNC is answered only for a member and only at its own address - never to a datagram's source, which anyone can set.
193
+
191
194
On the joining side, a received JOIN_REJECT is acted on only if it is addressed to this node *and* this node currently has an admission request outstanding (*join_pending*). A member that is not asking to be admitted ignores JOIN_REJECT unconditionally, so a node with the correct password can never be evicted by a peer.
192
195
193
196
The guard is deliberately the pending request and not the *CL_CTR_NODE_NEW* state. After a simultaneous cold start both nodes can reach the join deadline and self-promote, and the loser then merges into the winner by sending a fresh JOIN_REQ *from the active state*. Keying on the state label would have that node discard the refusal of a join it had just made. It acts on the refusal, but differently from a joining node: a node still joining shuts down, while an established node abandons the merge and stays with its own partition (see *Split-brain handling*).
@@ -1638,7 +1641,7 @@ In all five failover tests (1–5): exactly one node held the active sharing tag
1638
1641
1639
1642
### Automated tests
1640
1643
1641
-
*test/netns_tests.sh* runs the module end to end on one host: four network namespaces on a private bridge, every node in two clusters that share one port. It covers cold start, consumer delivery, restart and node_id reuse, partition heal, refusal of a foreign or mismatched cluster, a pinned cluster identity, recorded traffic sent again (while the sender runs and after it restarts), a MEMBER_LIST that arrives after a newer one, the *tm* anycast Via cid before and after the node has an id, a member and the master paused past every timeout, a receive buffer overflowed by a flood, a member that alone stops hearing the master, maintenance (a backup and then the master taken out of election and tags, and back), cuts one-sided and both ways and the heals after them, a killed master (also one restarted at once), a lossy and jittery link, a stuttering member, a cut-off master releasing the active tag, another node put into full maintenance, a member on the previous build, the statistics and the events, datagrams that are not packets of the cluster (*test/malformed_test.py* sends them: without the password, and sealed with the bootstrap key it derives as the module does - every type byte, payloads at every field boundary - from addresses that are no member, a member's and the master's), several nodes, or all four, starting at once, a JOIN_REJECT recorded and sent again to a node that is joining, and a node's packets sent again from another address. It needs root, iproute2, iptables and python3:
1644
+
*test/netns_tests.sh* runs the module end to end on one host: four network namespaces on a private bridge, every node in two clusters that share one port. It covers cold start, consumer delivery, restart and node_id reuse, partition heal, refusal of a foreign or mismatched cluster, a pinned cluster identity, recorded traffic sent again (while the sender runs and after it restarts), a MEMBER_LIST that arrives after a newer one, the *tm* anycast Via cid before and after the node has an id, a member and the master paused past every timeout, a receive buffer overflowed by a flood, a member that alone stops hearing the master, maintenance (a backup and then the master taken out of election and tags, and back), cuts one-sided and both ways and the heals after them, a killed master (also one restarted at once), a lossy and jittery link, a stuttering member, a cut-off master releasing the active tag, another node put into full maintenance, a member on the previous build, the statistics and the events, datagrams that are not packets of the cluster (*test/malformed_test.py* sends them: without the password, and sealed with the bootstrap key it derives as the module does - every type byte, payloads at every field boundary - from addresses that are no member, a member's and the master's), several nodes, or all four, starting at once, a JOIN_REJECT recorded and sent again to a node that is joining, a node's packets sent again from another address, and a JOIN_REQ sent again from another address. It needs root, iproute2, iptables and python3:
0 commit comments