Print this page
Try versioning as a new state
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/varpd/svp/common/libvarpd_svp_remote.c
+++ new/usr/src/lib/varpd/svp/common/libvarpd_svp_remote.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 13 * Copyright 2018 Joyent, Inc.
14 14 */
15 15
16 16 /*
17 17 * Remote backend management
18 18 *
19 19 * For more information, see the big theory statement in
20 20 * lib/varpd/svp/common/libvarpd_svp.c.
21 21 */
22 22
23 23 #include <umem.h>
24 24 #include <strings.h>
25 25 #include <string.h>
26 26 #include <stddef.h>
27 27 #include <thread.h>
28 28 #include <synch.h>
29 29 #include <assert.h>
30 30 #include <sys/socket.h>
31 31 #include <netdb.h>
32 32 #include <errno.h>
33 33 #include <libidspace.h>
34 34
35 35 #include <libvarpd_provider.h>
36 36 #include <libvarpd_svp.h>
37 37
38 38 typedef struct svp_shoot_vl3 {
39 39 svp_query_t ssv_query;
40 40 struct sockaddr_in6 ssv_sock;
|
↓ open down ↓ |
40 lines elided |
↑ open up ↑ |
41 41 svp_log_vl3_t *ssv_vl3;
42 42 svp_sdlog_t *ssv_log;
43 43 } svp_shoot_vl3_t;
44 44
45 45 static mutex_t svp_remote_lock = ERRORCHECKMUTEX;
46 46 static avl_tree_t svp_remote_tree;
47 47 static svp_timer_t svp_dns_timer;
48 48 static id_space_t *svp_idspace;
49 49 static int svp_dns_timer_rate = 30; /* seconds */
50 50
51 +id_t
52 +svp_id_alloc(void)
53 +{
54 + return (id_alloc(svp_idspace));
55 +}
56 +
51 57 static void
52 58 svp_remote_mkfmamsg(svp_remote_t *srp, svp_degrade_state_t state, char *buf,
53 59 size_t buflen)
54 60 {
55 61 switch (state) {
56 62 case SVP_RD_DNS_FAIL:
57 63 (void) snprintf(buf, buflen, "failed to resolve or find "
58 64 "entries for hostname %s", srp->sr_hostname);
59 65 break;
60 66 case SVP_RD_REMOTE_FAIL:
61 67 (void) snprintf(buf, buflen, "cannot reach any remote peers");
62 68 break;
63 69 default:
64 70 (void) snprintf(buf, buflen, "unkonwn error state: %d", state);
65 71 }
66 72 }
67 73
68 74 static int
69 75 svp_remote_comparator(const void *l, const void *r)
70 76 {
71 77 int ret;
72 78 const svp_remote_t *lr = l, *rr = r;
73 79
74 80 ret = strcmp(lr->sr_hostname, rr->sr_hostname);
75 81 if (ret > 0)
76 82 return (1);
77 83 else if (ret < 0)
78 84 return (-1);
79 85
80 86 if (lr->sr_rport > rr->sr_rport)
81 87 return (1);
82 88 else if (lr->sr_rport < rr->sr_rport)
83 89 return (-1);
84 90
85 91 return (memcmp(&lr->sr_uip, &rr->sr_uip, sizeof (struct in6_addr)));
86 92 }
87 93
88 94 void
89 95 svp_query_release(svp_query_t *sqp)
90 96 {
91 97 id_free(svp_idspace, sqp->sq_header.svp_id);
92 98 }
93 99
94 100 static void
95 101 svp_remote_destroy(svp_remote_t *srp)
96 102 {
97 103 size_t len;
98 104
99 105 /*
100 106 * Clean up any unrelated DNS information. At this point we know that
101 107 * we're not in the remote tree. That means, that svp_remote_dns_timer
102 108 * cannot queue us. However, if any of our DNS related state flags are
103 109 * set, we have to hang out.
104 110 */
105 111 mutex_enter(&srp->sr_lock);
106 112 while (srp->sr_state &
107 113 (SVP_RS_LOOKUP_SCHEDULED | SVP_RS_LOOKUP_INPROGRESS)) {
108 114 (void) cond_wait(&srp->sr_cond, &srp->sr_lock);
109 115 }
110 116 mutex_exit(&srp->sr_lock);
111 117 svp_shootdown_fini(srp);
112 118
113 119 if (cond_destroy(&srp->sr_cond) != 0)
114 120 libvarpd_panic("failed to destroy cond sr_cond");
115 121
116 122 if (mutex_destroy(&srp->sr_lock) != 0)
117 123 libvarpd_panic("failed to destroy mutex sr_lock");
118 124
119 125 if (srp->sr_addrinfo != NULL)
120 126 freeaddrinfo(srp->sr_addrinfo);
121 127 len = strlen(srp->sr_hostname) + 1;
122 128 umem_free(srp->sr_hostname, len);
123 129 umem_free(srp, sizeof (svp_remote_t));
124 130 }
125 131
126 132 static int
127 133 svp_remote_create(const char *host, uint16_t port, struct in6_addr *uip,
128 134 svp_remote_t **outp)
129 135 {
130 136 size_t hlen;
131 137 svp_remote_t *remote;
132 138
133 139 assert(MUTEX_HELD(&svp_remote_lock));
134 140
135 141 remote = umem_zalloc(sizeof (svp_remote_t), UMEM_DEFAULT);
136 142 if (remote == NULL) {
137 143 mutex_exit(&svp_remote_lock);
138 144 return (ENOMEM);
139 145 }
140 146
141 147 if (svp_shootdown_init(remote) != 0) {
142 148 umem_free(remote, sizeof (svp_remote_t));
143 149 mutex_exit(&svp_remote_lock);
144 150 return (ENOMEM);
145 151 }
146 152
147 153 hlen = strlen(host) + 1;
148 154 remote->sr_hostname = umem_alloc(hlen, UMEM_DEFAULT);
149 155 if (remote->sr_hostname == NULL) {
150 156 svp_shootdown_fini(remote);
151 157 umem_free(remote, sizeof (svp_remote_t));
152 158 mutex_exit(&svp_remote_lock);
153 159 return (ENOMEM);
154 160 }
155 161 remote->sr_rport = port;
156 162 if (mutex_init(&remote->sr_lock,
157 163 USYNC_THREAD | LOCK_ERRORCHECK, NULL) != 0)
158 164 libvarpd_panic("failed to create mutex sr_lock");
159 165 if (cond_init(&remote->sr_cond, USYNC_PROCESS, NULL) != 0)
160 166 libvarpd_panic("failed to create cond sr_cond");
161 167 list_create(&remote->sr_conns, sizeof (svp_conn_t),
162 168 offsetof(svp_conn_t, sc_rlist));
163 169 avl_create(&remote->sr_tree, svp_comparator, sizeof (svp_t),
164 170 offsetof(svp_t, svp_rlink));
165 171 (void) strlcpy(remote->sr_hostname, host, hlen);
166 172 remote->sr_count = 1;
167 173 remote->sr_uip = *uip;
168 174
169 175 svp_shootdown_start(remote);
170 176
171 177 *outp = remote;
172 178 return (0);
173 179 }
174 180
175 181 int
176 182 svp_remote_find(char *host, uint16_t port, struct in6_addr *uip,
177 183 svp_remote_t **outp)
178 184 {
179 185 int ret;
180 186 svp_remote_t lookup, *remote;
181 187
182 188 lookup.sr_hostname = host;
183 189 lookup.sr_rport = port;
184 190 lookup.sr_uip = *uip;
185 191 mutex_enter(&svp_remote_lock);
186 192 remote = avl_find(&svp_remote_tree, &lookup, NULL);
187 193 if (remote != NULL) {
188 194 assert(remote->sr_count > 0);
189 195 remote->sr_count++;
190 196 *outp = remote;
191 197 mutex_exit(&svp_remote_lock);
192 198 return (0);
193 199 }
194 200
195 201 if ((ret = svp_remote_create(host, port, uip, outp)) != 0) {
196 202 mutex_exit(&svp_remote_lock);
197 203 return (ret);
198 204 }
199 205
200 206 avl_add(&svp_remote_tree, *outp);
201 207 mutex_exit(&svp_remote_lock);
202 208
203 209 /* Make sure DNS is up to date */
204 210 svp_host_queue(*outp);
205 211
206 212 return (0);
207 213 }
208 214
209 215 void
210 216 svp_remote_release(svp_remote_t *srp)
211 217 {
212 218 mutex_enter(&svp_remote_lock);
213 219 mutex_enter(&srp->sr_lock);
214 220 srp->sr_count--;
215 221 if (srp->sr_count != 0) {
216 222 mutex_exit(&srp->sr_lock);
217 223 mutex_exit(&svp_remote_lock);
218 224 return;
219 225 }
220 226 mutex_exit(&srp->sr_lock);
221 227
222 228 avl_remove(&svp_remote_tree, srp);
223 229 mutex_exit(&svp_remote_lock);
224 230 svp_remote_destroy(srp);
225 231 }
226 232
227 233 int
228 234 svp_remote_attach(svp_remote_t *srp, svp_t *svp)
229 235 {
230 236 svp_t check;
231 237 avl_index_t where;
232 238
233 239 mutex_enter(&srp->sr_lock);
234 240 if (svp->svp_remote != NULL)
235 241 libvarpd_panic("failed to create mutex sr_lock");
236 242
237 243 /*
238 244 * We require everything except shootdowns
239 245 */
240 246 if (svp->svp_cb.scb_vl2_lookup == NULL)
241 247 libvarpd_panic("missing callback scb_vl2_lookup");
242 248 if (svp->svp_cb.scb_vl3_lookup == NULL)
243 249 libvarpd_panic("missing callback scb_vl3_lookup");
244 250 if (svp->svp_cb.scb_vl2_invalidate == NULL)
245 251 libvarpd_panic("missing callback scb_vl2_invalidate");
246 252 if (svp->svp_cb.scb_vl3_inject == NULL)
247 253 libvarpd_panic("missing callback scb_vl3_inject");
248 254 if (svp->svp_cb.scb_route_lookup == NULL)
249 255 libvarpd_panic("missing callback scb_route_lookup");
250 256
251 257 check.svp_vid = svp->svp_vid;
252 258 if (avl_find(&srp->sr_tree, &check, &where) != NULL)
253 259 libvarpd_panic("found duplicate entry with vid %ld",
254 260 svp->svp_vid);
255 261 avl_insert(&srp->sr_tree, svp, where);
256 262 svp->svp_remote = srp;
257 263 mutex_exit(&srp->sr_lock);
258 264
259 265 return (0);
260 266 }
261 267
262 268 void
263 269 svp_remote_detach(svp_t *svp)
264 270 {
265 271 svp_t *lookup;
266 272 svp_remote_t *srp = svp->svp_remote;
267 273
268 274 if (srp == NULL)
269 275 libvarpd_panic("trying to detach remote when none exists");
270 276
271 277 mutex_enter(&srp->sr_lock);
272 278 lookup = avl_find(&srp->sr_tree, svp, NULL);
273 279 if (lookup == NULL || lookup != svp)
274 280 libvarpd_panic("inconsitent remote avl tree...");
275 281 avl_remove(&srp->sr_tree, svp);
276 282 svp->svp_remote = NULL;
277 283 mutex_exit(&srp->sr_lock);
278 284 svp_remote_release(srp);
279 285 }
280 286
281 287 /*
282 288 * See if the request can be sent over the connection's supported version.
283 289 * Scribble the version in the request itself. NOTE that we do not check the
284 290 * version that already exists in sqp->sq_header.svp_ver, as we may be called
285 291 * from svp_remote_reassign() (and change versions when arriving at a new
286 292 * connection).
287 293 */
288 294 static boolean_t
289 295 svp_outbound_version_check(int version, svp_query_t *sqp)
290 296 {
291 297 uint16_t op = htons(sqp->sq_header.svp_op);
292 298
293 299 /*
294 300 * As of v1 -> v2, we really only need to restrict SVP_R_ROUTE_REQ
295 301 * as v2-only. Reflect that here.
296 302 *
297 303 * NOTE that if any message semantics change between future versions,
298 304 * (e.g. "in v3 SVP_R_VL2_REQ takes on additional work"), we'll
299 305 * need to more-deeply inspect the query. It's possible that the
300 306 * svp_op space is big enough to just continue op-only inspections.
301 307 */
302 308
303 309 assert(version > 0 && version <= SVP_CURRENT_VERSION);
304 310
305 311 if (op != SVP_R_ROUTE_REQ || version >= SVP_VERSION_TWO) {
306 312 sqp->sq_header.svp_ver = htons(version);
307 313 return (B_TRUE);
308 314 }
309 315 return (B_FALSE);
310 316 }
311 317
312 318 /*
313 319 * Walk the list of connections and find the first one that's available AND
314 320 * version-appropriate for the message, then move the matched connection to
315 321 * the back of the list so it's less likely to be used again.
316 322 */
317 323 static boolean_t
318 324 svp_remote_conn_queue(svp_remote_t *srp, svp_query_t *sqp)
319 325 {
320 326 svp_conn_t *scp;
321 327
322 328 assert(MUTEX_HELD(&srp->sr_lock));
323 329 for (scp = list_head(&srp->sr_conns); scp != NULL;
324 330 scp = list_next(&srp->sr_conns, scp)) {
325 331 mutex_enter(&scp->sc_lock);
326 332 if (scp->sc_cstate != SVP_CS_ACTIVE ||
327 333 !svp_outbound_version_check(scp->sc_version, sqp)) {
328 334 mutex_exit(&scp->sc_lock);
329 335 continue;
330 336 }
331 337 svp_conn_queue(scp, sqp);
332 338 mutex_exit(&scp->sc_lock);
333 339 list_remove(&srp->sr_conns, scp);
334 340 list_insert_tail(&srp->sr_conns, scp);
335 341 return (B_TRUE);
336 342 }
337 343
338 344 return (B_FALSE);
339 345 }
340 346
341 347 static void
342 348 svp_remote_vl2_lookup_cb(svp_query_t *sqp, void *arg)
343 349 {
344 350 svp_t *svp = sqp->sq_svp;
345 351 svp_vl2_ack_t *vl2a = (svp_vl2_ack_t *)sqp->sq_wdata;
346 352
347 353 if (sqp->sq_status == SVP_S_OK)
348 354 svp->svp_cb.scb_vl2_lookup(svp, sqp->sq_status,
349 355 (struct in6_addr *)vl2a->sl2a_addr, ntohs(vl2a->sl2a_port),
350 356 arg);
351 357 else
352 358 svp->svp_cb.scb_vl2_lookup(svp, sqp->sq_status, NULL, 0, arg);
353 359 }
354 360
355 361 void
356 362 svp_remote_vl2_lookup(svp_t *svp, svp_query_t *sqp, const uint8_t *mac,
357 363 void *arg)
358 364 {
359 365 svp_remote_t *srp;
360 366 svp_vl2_req_t *vl2r = &sqp->sq_rdun.sqd_vl2r;
361 367
362 368 srp = svp->svp_remote;
363 369 sqp->sq_func = svp_remote_vl2_lookup_cb;
364 370 sqp->sq_arg = arg;
365 371 sqp->sq_svp = svp;
366 372 sqp->sq_state = SVP_QUERY_INIT;
367 373 sqp->sq_header.svp_op = htons(SVP_R_VL2_REQ);
368 374 sqp->sq_header.svp_size = htonl(sizeof (svp_vl2_req_t));
369 375 sqp->sq_header.svp_id = id_alloc(svp_idspace);
370 376 if (sqp->sq_header.svp_id == (id_t)-1)
371 377 libvarpd_panic("failed to allcoate from svp_idspace: %d",
372 378 errno);
373 379 sqp->sq_header.svp_crc32 = htonl(0);
374 380 sqp->sq_rdata = vl2r;
375 381 sqp->sq_rsize = sizeof (svp_vl2_req_t);
376 382 sqp->sq_wdata = NULL;
377 383 sqp->sq_wsize = 0;
378 384
379 385 bcopy(mac, vl2r->sl2r_mac, ETHERADDRL);
380 386 vl2r->sl2r_vnetid = ntohl(svp->svp_vid);
381 387
382 388 mutex_enter(&srp->sr_lock);
383 389 if (svp_remote_conn_queue(srp, sqp) == B_FALSE)
384 390 svp->svp_cb.scb_vl2_lookup(svp, SVP_S_FATAL, NULL, NULL, arg);
385 391 mutex_exit(&srp->sr_lock);
386 392 }
387 393
388 394 static void
389 395 svp_remote_route_lookup_cb(svp_query_t *sqp, void *arg)
390 396 {
391 397 svp_t *svp = sqp->sq_svp;
392 398 svp_route_ack_t *sra = (svp_route_ack_t *)sqp->sq_wdata;
393 399
394 400 if (sqp->sq_status == SVP_S_OK) {
395 401 svp->svp_cb.scb_route_lookup(svp, sqp->sq_status,
396 402 sra->sra_dcid, sra->sra_vnetid, sra->sra_vlan,
397 403 sra->sra_srcmac, sra->sra_dstmac, sra->sra_port,
398 404 sra->sra_ip, sra->sra_src_pfx, sra->sra_dst_pfx, arg);
399 405 } else {
400 406 svp->svp_cb.scb_route_lookup(svp, sqp->sq_status,
401 407 0, 0, 0, NULL, NULL, 0, NULL, 0, 0, arg);
402 408 }
403 409 }
404 410
405 411 void
406 412 svp_remote_route_lookup(svp_t *svp, svp_query_t *sqp,
407 413 const struct in6_addr *src, const struct in6_addr *dst, uint32_t vnetid,
408 414 uint16_t vlan, void *arg)
409 415 {
410 416 svp_remote_t *srp;
411 417 svp_route_req_t *srr = &sqp->sq_rdun.sqd_rr;
412 418
413 419 srp = svp->svp_remote;
414 420 sqp->sq_func = svp_remote_route_lookup_cb;
415 421 sqp->sq_arg = arg;
416 422 sqp->sq_svp = svp;
417 423 sqp->sq_state = SVP_QUERY_INIT;
418 424 sqp->sq_header.svp_op = htons(SVP_R_ROUTE_REQ);
419 425 sqp->sq_header.svp_size = htonl(sizeof (svp_route_req_t));
420 426 sqp->sq_header.svp_id = id_alloc(svp_idspace);
421 427 if (sqp->sq_header.svp_id == (id_t)-1)
422 428 libvarpd_panic("failed to allcoate from svp_idspace: %d",
423 429 errno);
424 430 sqp->sq_header.svp_crc32 = htonl(0);
425 431 sqp->sq_rdata = srr;
426 432
427 433 bcopy(src, srr->srr_srcip, sizeof (struct in6_addr));
428 434 bcopy(dst, srr->srr_dstip, sizeof (struct in6_addr));
429 435 /* Caller should've checked both are the same type... */
430 436 srr->srr_vnetid = vnetid;
431 437 srr->srr_vlan = vlan;
432 438 srr->srr_pad = 0;
433 439
434 440 mutex_enter(&srp->sr_lock);
435 441 if (!svp_remote_conn_queue(srp, sqp)) {
436 442 sqp->sq_status = SVP_S_FATAL;
437 443 sqp->sq_func(sqp, arg);
438 444 }
439 445 mutex_exit(&srp->sr_lock);
440 446 }
441 447
442 448 static void
443 449 svp_remote_vl3_lookup_cb(svp_query_t *sqp, void *arg)
444 450 {
445 451 svp_t *svp = sqp->sq_svp;
446 452 svp_vl3_ack_t *vl3a = (svp_vl3_ack_t *)sqp->sq_wdata;
447 453
448 454 if (sqp->sq_status == SVP_S_OK)
449 455 svp->svp_cb.scb_vl3_lookup(svp, sqp->sq_status, vl3a->sl3a_mac,
450 456 (struct in6_addr *)vl3a->sl3a_uip, ntohs(vl3a->sl3a_uport),
451 457 arg);
452 458 else
453 459 svp->svp_cb.scb_vl3_lookup(svp, sqp->sq_status, NULL, NULL, 0,
454 460 arg);
455 461 }
456 462
457 463 static void
458 464 svp_remote_vl3_common(svp_remote_t *srp, svp_query_t *sqp,
459 465 const struct sockaddr *addr, svp_query_f func, void *arg, uint32_t vid)
460 466 {
461 467 svp_vl3_req_t *vl3r = &sqp->sq_rdun.sdq_vl3r;
462 468
463 469 if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6)
464 470 libvarpd_panic("unexpected sa_family for the vl3 lookup");
465 471
466 472 sqp->sq_func = func;
467 473 sqp->sq_arg = arg;
468 474 sqp->sq_state = SVP_QUERY_INIT;
469 475 sqp->sq_header.svp_op = htons(SVP_R_VL3_REQ);
470 476 sqp->sq_header.svp_size = htonl(sizeof (svp_vl3_req_t));
471 477 sqp->sq_header.svp_id = id_alloc(svp_idspace);
472 478 if (sqp->sq_header.svp_id == (id_t)-1)
473 479 libvarpd_panic("failed to allcoate from svp_idspace: %d",
474 480 errno);
475 481 sqp->sq_header.svp_crc32 = htonl(0);
476 482 sqp->sq_rdata = vl3r;
477 483 sqp->sq_rsize = sizeof (svp_vl3_req_t);
478 484 sqp->sq_wdata = NULL;
479 485 sqp->sq_wsize = 0;
480 486
481 487 if (addr->sa_family == AF_INET6) {
482 488 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)addr;
483 489 vl3r->sl3r_type = htonl(SVP_VL3_IPV6);
484 490 bcopy(&s6->sin6_addr, vl3r->sl3r_ip,
485 491 sizeof (struct in6_addr));
486 492 } else {
487 493 struct sockaddr_in *s4 = (struct sockaddr_in *)addr;
488 494 struct in6_addr v6;
489 495
490 496 vl3r->sl3r_type = htonl(SVP_VL3_IP);
491 497 IN6_INADDR_TO_V4MAPPED(&s4->sin_addr, &v6);
492 498 bcopy(&v6, vl3r->sl3r_ip, sizeof (struct in6_addr));
493 499 }
494 500 vl3r->sl3r_vnetid = htonl(vid);
495 501
496 502 mutex_enter(&srp->sr_lock);
497 503 if (svp_remote_conn_queue(srp, sqp) == B_FALSE) {
498 504 sqp->sq_status = SVP_S_FATAL;
499 505 sqp->sq_func(sqp, arg);
500 506 }
501 507 mutex_exit(&srp->sr_lock);
502 508 }
503 509
504 510 /*
505 511 * This is a request to do a VL3 look-up that originated internally as opposed
506 512 * to coming from varpd. As such we need a slightly different query callback
507 513 * function upon completion and don't go through the normal path with the svp_t.
508 514 */
509 515 void
510 516 svp_remote_vl3_logreq(svp_remote_t *srp, svp_query_t *sqp, uint32_t vid,
511 517 const struct sockaddr *addr, svp_query_f func, void *arg)
512 518 {
513 519 svp_remote_vl3_common(srp, sqp, addr, func, arg, vid);
514 520 }
515 521
516 522 void
517 523 svp_remote_vl3_lookup(svp_t *svp, svp_query_t *sqp,
518 524 const struct sockaddr *addr, void *arg)
519 525 {
520 526 svp_remote_t *srp = svp->svp_remote;
521 527
522 528 sqp->sq_svp = svp;
523 529 svp_remote_vl3_common(srp, sqp, addr, svp_remote_vl3_lookup_cb,
524 530 arg, svp->svp_vid);
525 531 }
526 532
527 533 static void
528 534 svp_remote_log_request_cb(svp_query_t *sqp, void *arg)
529 535 {
530 536 svp_remote_t *srp = sqp->sq_arg;
531 537
532 538 assert(sqp->sq_wdata != NULL);
533 539 if (sqp->sq_status == SVP_S_OK)
534 540 svp_shootdown_logr_cb(srp, sqp->sq_status, sqp->sq_wdata,
535 541 sqp->sq_size);
536 542 else
537 543 svp_shootdown_logr_cb(srp, sqp->sq_status, NULL, 0);
538 544 }
539 545
540 546 void
541 547 svp_remote_log_request(svp_remote_t *srp, svp_query_t *sqp, void *buf,
542 548 size_t buflen)
543 549 {
544 550 svp_log_req_t *logr = &sqp->sq_rdun.sdq_logr;
545 551 boolean_t queued;
546 552
547 553 sqp->sq_func = svp_remote_log_request_cb;
548 554 sqp->sq_state = SVP_QUERY_INIT;
549 555 sqp->sq_arg = srp;
550 556 sqp->sq_header.svp_op = htons(SVP_R_LOG_REQ);
551 557 sqp->sq_header.svp_size = htonl(sizeof (svp_log_req_t));
552 558 sqp->sq_header.svp_id = id_alloc(svp_idspace);
553 559 if (sqp->sq_header.svp_id == (id_t)-1)
554 560 libvarpd_panic("failed to allcoate from svp_idspace: %d",
555 561 errno);
556 562 sqp->sq_header.svp_crc32 = htonl(0);
557 563 sqp->sq_rdata = logr;
558 564 sqp->sq_rsize = sizeof (svp_log_req_t);
559 565 sqp->sq_wdata = buf;
560 566 sqp->sq_wsize = buflen;
561 567
562 568 logr->svlr_count = htonl(buflen);
563 569 bcopy(&srp->sr_uip, logr->svlr_ip, sizeof (struct in6_addr));
564 570
565 571 /*
566 572 * If this fails, there isn't much that we can't do. Give the callback
567 573 * with a fatal status.
568 574 */
569 575 mutex_enter(&srp->sr_lock);
570 576 queued = svp_remote_conn_queue(srp, sqp);
571 577 mutex_exit(&srp->sr_lock);
572 578
573 579 if (queued == B_FALSE)
574 580 svp_shootdown_logr_cb(srp, SVP_S_FATAL, NULL, 0);
575 581 }
576 582
577 583 static void
578 584 svp_remote_lrm_request_cb(svp_query_t *sqp, void *arg)
579 585 {
580 586 svp_remote_t *srp = arg;
581 587
582 588 svp_shootdown_lrm_cb(srp, sqp->sq_status);
583 589 }
584 590
585 591 void
586 592 svp_remote_lrm_request(svp_remote_t *srp, svp_query_t *sqp, void *buf,
587 593 size_t buflen)
588 594 {
589 595 boolean_t queued;
590 596 svp_lrm_req_t *svrr = buf;
591 597
592 598 sqp->sq_func = svp_remote_lrm_request_cb;
593 599 sqp->sq_state = SVP_QUERY_INIT;
594 600 sqp->sq_arg = srp;
595 601 sqp->sq_header.svp_op = htons(SVP_R_LOG_RM);
596 602 sqp->sq_header.svp_size = htonl(buflen);
597 603 sqp->sq_header.svp_id = id_alloc(svp_idspace);
598 604 if (sqp->sq_header.svp_id == (id_t)-1)
599 605 libvarpd_panic("failed to allcoate from svp_idspace: %d",
600 606 errno);
601 607 sqp->sq_header.svp_crc32 = htonl(0);
602 608 sqp->sq_rdata = buf;
603 609 sqp->sq_rsize = buflen;
604 610 sqp->sq_wdata = NULL;
605 611 sqp->sq_wsize = 0;
606 612
607 613 /*
608 614 * We need to fix up the count to be in proper network order.
609 615 */
610 616 svrr->svrr_count = htonl(svrr->svrr_count);
611 617
612 618 /*
613 619 * If this fails, there isn't much that we can't do. Give the callback
614 620 * with a fatal status.
615 621 */
616 622 mutex_enter(&srp->sr_lock);
617 623 queued = svp_remote_conn_queue(srp, sqp);
618 624 mutex_exit(&srp->sr_lock);
619 625
620 626 if (queued == B_FALSE)
621 627 svp_shootdown_logr_cb(srp, SVP_S_FATAL, NULL, 0);
622 628 }
623 629
624 630 /* ARGSUSED */
625 631 void
626 632 svp_remote_dns_timer(void *unused)
627 633 {
628 634 svp_remote_t *s;
629 635 mutex_enter(&svp_remote_lock);
630 636 for (s = avl_first(&svp_remote_tree); s != NULL;
631 637 s = AVL_NEXT(&svp_remote_tree, s)) {
632 638 svp_host_queue(s);
633 639 }
634 640 mutex_exit(&svp_remote_lock);
635 641 }
636 642
637 643 void
638 644 svp_remote_resolved(svp_remote_t *srp, struct addrinfo *newaddrs)
639 645 {
640 646 struct addrinfo *a;
641 647 svp_conn_t *scp;
642 648 int ngen;
643 649
644 650 mutex_enter(&srp->sr_lock);
645 651 srp->sr_gen++;
646 652 ngen = srp->sr_gen;
647 653 mutex_exit(&srp->sr_lock);
648 654
649 655 for (a = newaddrs; a != NULL; a = a->ai_next) {
650 656 struct in6_addr in6;
651 657 struct in6_addr *addrp;
652 658
653 659 if (a->ai_family != AF_INET && a->ai_family != AF_INET6)
654 660 continue;
655 661
656 662 if (a->ai_family == AF_INET) {
657 663 struct sockaddr_in *v4;
658 664 v4 = (struct sockaddr_in *)a->ai_addr;
659 665 addrp = &in6;
660 666 IN6_INADDR_TO_V4MAPPED(&v4->sin_addr, addrp);
661 667 } else {
662 668 struct sockaddr_in6 *v6;
663 669 v6 = (struct sockaddr_in6 *)a->ai_addr;
664 670 addrp = &v6->sin6_addr;
665 671 }
666 672
667 673 mutex_enter(&srp->sr_lock);
668 674 for (scp = list_head(&srp->sr_conns); scp != NULL;
669 675 scp = list_next(&srp->sr_conns, scp)) {
670 676 mutex_enter(&scp->sc_lock);
671 677 if (bcmp(addrp, &scp->sc_addr,
672 678 sizeof (struct in6_addr)) == 0) {
673 679 scp->sc_gen = ngen;
674 680 mutex_exit(&scp->sc_lock);
675 681 break;
676 682 }
677 683 mutex_exit(&scp->sc_lock);
678 684 }
679 685
680 686 /*
681 687 * We need to be careful in the assumptions that we make here,
682 688 * as there's a good chance that svp_conn_create will
683 689 * drop the svp_remote_t`sr_lock to kick off its effective event
684 690 * loop.
685 691 */
686 692 if (scp == NULL)
687 693 (void) svp_conn_create(srp, addrp);
688 694 mutex_exit(&srp->sr_lock);
689 695 }
690 696
691 697 /*
692 698 * Now it's time to clean things up. We do not actively clean up the
693 699 * current connections that we have, instead allowing them to stay
694 700 * around assuming that they're still useful. Instead, we go through and
695 701 * purge the degraded list for anything that's from an older generation.
696 702 */
697 703 mutex_enter(&srp->sr_lock);
698 704 for (scp = list_head(&srp->sr_conns); scp != NULL;
699 705 scp = list_next(&srp->sr_conns, scp)) {
700 706 boolean_t fall = B_FALSE;
701 707 mutex_enter(&scp->sc_lock);
702 708 if (scp->sc_gen < srp->sr_gen)
703 709 fall = B_TRUE;
704 710 mutex_exit(&scp->sc_lock);
705 711 if (fall == B_TRUE)
706 712 svp_conn_fallout(scp);
707 713 }
708 714 mutex_exit(&srp->sr_lock);
709 715 }
710 716
711 717 /*
712 718 * This connection is in the process of being reset, we need to reassign all of
713 719 * its queries to other places or mark them as fatal. Note that the first
714 720 * connection was the one in flight when this failed. We always mark it as
715 721 * failed to avoid trying to reset its state.
716 722 */
717 723 void
718 724 svp_remote_reassign(svp_remote_t *srp, svp_conn_t *scp)
719 725 {
720 726 boolean_t first = B_TRUE;
721 727 assert(MUTEX_HELD(&srp->sr_lock));
722 728 assert(MUTEX_HELD(&srp->sr_lock));
723 729 svp_query_t *sqp;
724 730
725 731 /*
726 732 * As we try to reassigning all of its queries, remove it from the list.
727 733 */
728 734 list_remove(&srp->sr_conns, scp);
729 735
730 736 while ((sqp = list_remove_head(&scp->sc_queries)) != NULL) {
731 737
732 738 if (first == B_TRUE) {
733 739 sqp->sq_status = SVP_S_FATAL;
734 740 sqp->sq_func(sqp, sqp->sq_arg);
735 741 continue;
736 742 }
737 743
738 744 sqp->sq_acttime = -1;
739 745
740 746 /*
741 747 * We may want to maintain a queue of these for some time rather
742 748 * than just failing them all.
743 749 */
744 750 if (svp_remote_conn_queue(srp, sqp) == B_FALSE) {
745 751 sqp->sq_status = SVP_S_FATAL;
746 752 sqp->sq_func(sqp, sqp->sq_arg);
747 753 }
748 754 }
749 755
750 756 /*
751 757 * Now that we're done, go ahead and re-insert.
752 758 */
753 759 list_insert_tail(&srp->sr_conns, scp);
754 760 }
755 761
756 762 void
757 763 svp_remote_degrade(svp_remote_t *srp, svp_degrade_state_t flag)
758 764 {
759 765 int sf, nf;
760 766 char buf[256];
761 767
762 768 assert(MUTEX_HELD(&srp->sr_lock));
763 769
764 770 if (flag == SVP_RD_ALL || flag == 0)
765 771 libvarpd_panic("invalid flag passed to degrade");
766 772
767 773 if ((flag & srp->sr_degrade) != 0) {
768 774 return;
769 775 }
770 776
771 777 sf = ffs(srp->sr_degrade);
772 778 nf = ffs(flag);
773 779 srp->sr_degrade |= flag;
774 780 if (sf == 0 || sf > nf) {
775 781 svp_t *svp;
776 782 svp_remote_mkfmamsg(srp, flag, buf, sizeof (buf));
777 783
778 784 for (svp = avl_first(&srp->sr_tree); svp != NULL;
779 785 svp = AVL_NEXT(&srp->sr_tree, svp)) {
780 786 libvarpd_fma_degrade(svp->svp_hdl, buf);
781 787 }
782 788 }
783 789 }
784 790
785 791 void
786 792 svp_remote_restore(svp_remote_t *srp, svp_degrade_state_t flag)
787 793 {
788 794 int sf, nf;
789 795
790 796 assert(MUTEX_HELD(&srp->sr_lock));
791 797 sf = ffs(srp->sr_degrade);
792 798 if ((srp->sr_degrade & flag) != flag)
793 799 return;
794 800 srp->sr_degrade &= ~flag;
795 801 nf = ffs(srp->sr_degrade);
796 802
797 803 /*
798 804 * If we're now empty, restore the device. If we still are degraded, but
799 805 * we now have a higher base than we used to, change the message.
800 806 */
801 807 if (srp->sr_degrade == 0) {
802 808 svp_t *svp;
803 809 for (svp = avl_first(&srp->sr_tree); svp != NULL;
804 810 svp = AVL_NEXT(&srp->sr_tree, svp)) {
805 811 libvarpd_fma_restore(svp->svp_hdl);
806 812 }
807 813 } else if (nf != sf) {
808 814 svp_t *svp;
809 815 char buf[256];
810 816
811 817 svp_remote_mkfmamsg(srp, 1U << (nf - 1), buf, sizeof (buf));
812 818 for (svp = avl_first(&srp->sr_tree); svp != NULL;
813 819 svp = AVL_NEXT(&srp->sr_tree, svp)) {
814 820 libvarpd_fma_degrade(svp->svp_hdl, buf);
815 821 }
816 822 }
817 823 }
818 824
819 825 void
820 826 svp_remote_shootdown_vl3_cb(svp_query_t *sqp, void *arg)
821 827 {
822 828 svp_shoot_vl3_t *squery = arg;
823 829 svp_log_vl3_t *svl3 = squery->ssv_vl3;
824 830 svp_sdlog_t *sdl = squery->ssv_log;
825 831
826 832 if (sqp->sq_status == SVP_S_OK) {
827 833 svp_t *svp, lookup;
828 834
829 835 svp_remote_t *srp = sdl->sdl_remote;
830 836 svp_vl3_ack_t *vl3a = (svp_vl3_ack_t *)sqp->sq_wdata;
831 837
832 838 lookup.svp_vid = ntohl(svl3->svl3_vnetid);
833 839 mutex_enter(&srp->sr_lock);
834 840 if ((svp = avl_find(&srp->sr_tree, &lookup, NULL)) != NULL) {
835 841 svp->svp_cb.scb_vl3_inject(svp, ntohs(svl3->svl3_vlan),
836 842 (struct in6_addr *)svl3->svl3_ip, vl3a->sl3a_mac,
837 843 NULL);
838 844 }
839 845 mutex_exit(&srp->sr_lock);
840 846
841 847 }
842 848
843 849 svp_shootdown_vl3_cb(sqp->sq_status, svl3, sdl);
844 850
845 851 umem_free(squery, sizeof (svp_shoot_vl3_t));
846 852 }
847 853
848 854 void
849 855 svp_remote_shootdown_vl3(svp_remote_t *srp, svp_log_vl3_t *svl3,
850 856 svp_sdlog_t *sdl)
851 857 {
852 858 svp_shoot_vl3_t *squery;
853 859
854 860 squery = umem_zalloc(sizeof (svp_shoot_vl3_t), UMEM_DEFAULT);
855 861 if (squery == NULL) {
856 862 svp_shootdown_vl3_cb(SVP_S_FATAL, svl3, sdl);
857 863 return;
858 864 }
859 865
860 866 squery->ssv_vl3 = svl3;
861 867 squery->ssv_log = sdl;
862 868 squery->ssv_sock.sin6_family = AF_INET6;
863 869 bcopy(svl3->svl3_ip, &squery->ssv_sock.sin6_addr,
864 870 sizeof (svl3->svl3_ip));
865 871 svp_remote_vl3_logreq(srp, &squery->ssv_query, ntohl(svl3->svl3_vnetid),
866 872 (struct sockaddr *)&squery->ssv_sock, svp_remote_shootdown_vl3_cb,
867 873 squery);
868 874 }
869 875
870 876 void
871 877 svp_remote_shootdown_vl2(svp_remote_t *srp, svp_log_vl2_t *svl2)
872 878 {
873 879 svp_t *svp, lookup;
874 880
875 881 lookup.svp_vid = ntohl(svl2->svl2_vnetid);
876 882 mutex_enter(&srp->sr_lock);
877 883 if ((svp = avl_find(&srp->sr_tree, &lookup, NULL)) != NULL) {
878 884 svp->svp_cb.scb_vl2_invalidate(svp, svl2->svl2_mac);
879 885 }
880 886 mutex_exit(&srp->sr_lock);
881 887 }
882 888
883 889 int
884 890 svp_remote_init(void)
885 891 {
886 892 svp_idspace = id_space_create("svp_req_ids", 1, INT32_MAX);
887 893 if (svp_idspace == NULL)
888 894 return (errno);
889 895 avl_create(&svp_remote_tree, svp_remote_comparator,
890 896 sizeof (svp_remote_t), offsetof(svp_remote_t, sr_gnode));
891 897 svp_dns_timer.st_func = svp_remote_dns_timer;
892 898 svp_dns_timer.st_arg = NULL;
893 899 svp_dns_timer.st_oneshot = B_FALSE;
894 900 svp_dns_timer.st_value = svp_dns_timer_rate;
895 901 svp_timer_add(&svp_dns_timer);
896 902 return (0);
897 903 }
898 904
899 905 void
900 906 svp_remote_fini(void)
901 907 {
902 908 svp_timer_remove(&svp_dns_timer);
903 909 avl_destroy(&svp_remote_tree);
904 910 if (svp_idspace == NULL)
905 911 id_space_destroy(svp_idspace);
906 912 }
|
↓ open down ↓ |
846 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX