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