277667dc10f3ac7b9f050b251bce7344ff76c21c
[openwrt-packages.git] /
1 commit 3bb33335816c1c9549d21bcc14bed29519b938a3
2 Author: Emeric Brun <ebrun@haproxy.com>
3 Date:   Tue Apr 2 17:22:01 2019 +0200
4
5     BUG/MEDIUM: peers: fix a case where peer session is not cleanly reset on release.
6     
7     The deinit took place in only peer_session_release, but in the a case of a
8     previous call to peer_session_forceshutdown, the session cursors
9     won't be reset, resulting in a bad state for new session of the same
10     peer. For instance, a table definition message could be dropped and
11     so all update messages will be dropped by the remote peer.
12     
13     This patch move the deinit processing directly in the force shutdown
14     funtion. Killed session remains in "ST_END" state but ref on peer was
15     reset to NULL and deinit will be skipped on session release function.
16     
17     The session release continue to assure the deinit for "active" sessions.
18     
19     This patch should be backported on all stable version since proto
20     peers v2.
21     
22     (cherry picked from commit 9ef2ad7844e577b505019695c59284f4a439fc33)
23     Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
24     (cherry picked from commit 14831989a081f3944cf891afd56e6d9f6086c3ed)
25     [cf: global variabled connected_peers and active_peers don't exist in 1.8]
26     Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
27
28 diff --git a/src/peers.c b/src/peers.c
29 index 465ffe85..d7dc51d8 100644
30 --- a/src/peers.c
31 +++ b/src/peers.c
32 @@ -172,7 +172,7 @@ enum {
33  #define PEER_DWNGRD_MINOR_VER 0
34  
35  struct peers *cfg_peers = NULL;
36 -static void peer_session_forceshutdown(struct appctx *appctx);
37 +static void peer_session_forceshutdown(struct peer *peer);
38  
39  /* This function encode an uint64 to 'dynamic' length format.
40     The encoded value is written at address *str, and the
41 @@ -492,15 +492,53 @@ static int peer_prepare_ackmsg(struct shared_table *st, char *msg, size_t size)
42         return (cursor - msg) + datalen;
43  }
44  
45 +/*
46 + * Function to deinit connected peer
47 + */
48 +void __peer_session_deinit(struct peer *peer)
49 +{
50 +       struct stream_interface *si;
51 +       struct stream *s;
52 +       struct peers *peers;
53 +
54 +       if (!peer->appctx)
55 +               return;
56 +
57 +       si = peer->appctx->owner;
58 +       if (!si)
59 +               return;
60 +
61 +       s = si_strm(si);
62 +       if (!s)
63 +               return;
64 +
65 +       peers = strm_fe(s)->parent;
66 +       if (!peers)
67 +               return;
68 +
69 +       /* Re-init current table pointers to force announcement on re-connect */
70 +       peer->remote_table = peer->last_local_table = NULL;
71 +       peer->appctx = NULL;
72 +       if (peer->flags & PEER_F_LEARN_ASSIGN) {
73 +               /* unassign current peer for learning */
74 +               peer->flags &= ~(PEER_F_LEARN_ASSIGN);
75 +               peers->flags &= ~(PEERS_F_RESYNC_ASSIGN|PEERS_F_RESYNC_PROCESS);
76 +
77 +               /* reschedule a resync */
78 +               peers->resync_timeout = tick_add(now_ms, MS_TO_TICKS(5000));
79 +       }
80 +       /* reset teaching and learning flags to 0 */
81 +       peer->flags &= PEER_TEACH_RESET;
82 +       peer->flags &= PEER_LEARN_RESET;
83 +       task_wakeup(peers->sync_task, TASK_WOKEN_MSG);
84 +}
85 +
86  /*
87   * Callback to release a session with a peer
88   */
89  static void peer_session_release(struct appctx *appctx)
90  {
91 -       struct stream_interface *si = appctx->owner;
92 -       struct stream *s = si_strm(si);
93         struct peer *peer = appctx->ctx.peers.ptr;
94 -       struct peers *peers = strm_fe(s)->parent;
95  
96         /* appctx->ctx.peers.ptr is not a peer session */
97         if (appctx->st0 < PEER_SESS_ST_SENDSUCCESS)
98 @@ -509,24 +547,9 @@ static void peer_session_release(struct appctx *appctx)
99         /* peer session identified */
100         if (peer) {
101                 HA_SPIN_LOCK(PEER_LOCK, &peer->lock);
102 -               if (peer->appctx == appctx) {
103 -                       /* Re-init current table pointers to force announcement on re-connect */
104 -                       peer->remote_table = peer->last_local_table = NULL;
105 -                       peer->appctx = NULL;
106 -                       if (peer->flags & PEER_F_LEARN_ASSIGN) {
107 -                               /* unassign current peer for learning */
108 -                               peer->flags &= ~(PEER_F_LEARN_ASSIGN);
109 -                               peers->flags &= ~(PEERS_F_RESYNC_ASSIGN|PEERS_F_RESYNC_PROCESS);
110 -
111 -                               /* reschedule a resync */
112 -                               peers->resync_timeout = tick_add(now_ms, MS_TO_TICKS(5000));
113 -                       }
114 -                       /* reset teaching and learning flags to 0 */
115 -                       peer->flags &= PEER_TEACH_RESET;
116 -                       peer->flags &= PEER_LEARN_RESET;
117 -               }
118 +               if (peer->appctx == appctx)
119 +                       __peer_session_deinit(peer);
120                 HA_SPIN_UNLOCK(PEER_LOCK, &peer->lock);
121 -               task_wakeup(peers->sync_task, TASK_WOKEN_MSG);
122         }
123  }
124  
125 @@ -704,7 +727,7 @@ switchstate:
126                                          * for a while.
127                                          */
128                                         curpeer->reconnect = tick_add(now_ms, MS_TO_TICKS(50 + random() % 2000));
129 -                                       peer_session_forceshutdown(curpeer->appctx);
130 +                                       peer_session_forceshutdown(curpeer);
131                                 }
132                                 if (maj_ver != (unsigned int)-1 && min_ver != (unsigned int)-1) {
133                                         if (min_ver == PEER_DWNGRD_MINOR_VER) {
134 @@ -1832,11 +1855,14 @@ static struct applet peer_applet = {
135         .release = peer_session_release,
136  };
137  
138 +
139  /*
140   * Use this function to force a close of a peer session
141   */
142 -static void peer_session_forceshutdown(struct appctx *appctx)
143 +static void peer_session_forceshutdown(struct peer *peer)
144  {
145 +       struct appctx *appctx = peer->appctx;
146 +
147         /* Note that the peer sessions which have just been created
148          * (->st0 == PEER_SESS_ST_CONNECT) must not
149          * be shutdown, if not, the TCP session will never be closed
150 @@ -1849,6 +1875,8 @@ static void peer_session_forceshutdown(struct appctx *appctx)
151         if (appctx->applet != &peer_applet)
152                 return;
153  
154 +       __peer_session_deinit(peer);
155 +
156         appctx->st0 = PEER_SESS_ST_END;
157         appctx_wakeup(appctx);
158  }
159 @@ -2094,8 +2122,7 @@ static struct task *process_peer_sync(struct task * task)
160                                  */
161                                 ps->reconnect = tick_add(now_ms, MS_TO_TICKS(50 + random() % 2000));
162                                 if (ps->appctx) {
163 -                                       peer_session_forceshutdown(ps->appctx);
164 -                                       ps->appctx = NULL;
165 +                                       peer_session_forceshutdown(ps);
166                                 }
167                         }
168                 }
git clone https://git.99rst.org/PROJECT