Print this page
    
NEX-4233 remove unnecessary libdladm header includes
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/cmd-inet/usr.lib/vrrpd/vrrpd.c
          +++ new/usr/src/cmd/cmd-inet/usr.lib/vrrpd/vrrpd.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  
    | 
      ↓ open down ↓ | 
    17 lines elided | 
    
      ↑ open up ↑ | 
  
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   */
  25   25  
  26   26  /*
  27   27   * Copyright (c) 2012, Joyent, Inc. All rights reserved.
       28 + * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  28   29   */
  29   30  
  30   31  #include <sys/types.h>
  31   32  #include <sys/socket.h>
  32   33  #include <sys/sockio.h>
  33   34  #include <sys/sysevent/vrrp.h>
  34   35  #include <sys/sysevent/eventdefs.h>
  35   36  #include <sys/varargs.h>
  36   37  #include <auth_attr.h>
  37   38  #include <ctype.h>
  38   39  #include <fcntl.h>
  39   40  #include <stdlib.h>
  40   41  #include <strings.h>
  41   42  #include <errno.h>
  42   43  #include <unistd.h>
  43   44  #include <zone.h>
  44   45  #include <libsysevent.h>
  45   46  #include <limits.h>
  46   47  #include <locale.h>
  47   48  #include <arpa/inet.h>
  48   49  #include <signal.h>
  49   50  #include <assert.h>
  50   51  #include <ucred.h>
  51   52  #include <bsm/adt.h>
  52   53  #include <bsm/adt_event.h>
  53   54  #include <priv_utils.h>
  54   55  #include <libdllink.h>
  55   56  #include <libdlvnic.h>
  56   57  #include <libipadm.h>
  57   58  #include <pwd.h>
  58   59  #include <libvrrpadm.h>
  59   60  #include <net/route.h>
  60   61  #include "vrrpd_impl.h"
  61   62  
  62   63  /*
  63   64   * A VRRP router can be only start participating the VRRP protocol of a virtual
  64   65   * router when all the following conditions are met:
  65   66   *
  66   67   * - The VRRP router is enabled (vr->vvr_conf.vvc_enabled is _B_TRUE)
  67   68   * - The RX socket is successfully created over the physical interface to
  68   69   *   receive the VRRP multicast advertisement. Note that one RX socket can
  69   70   *   be shared by several VRRP routers configured over the same physical
  70   71   *   interface. (See vrrpd_init_rxsock())
  71   72   * - The TX socket is successfully created over the VNIC interface to send
  72   73   *   the VRRP advertisment. (See vrrpd_init_txsock())
  73   74   * - The primary IP address has been successfully selected over the physical
  74   75   *   interface. (See vrrpd_select_primary())
  75   76   *
  76   77   * If a VRRP router is enabled but the other conditions haven't be satisfied,
  
    | 
      ↓ open down ↓ | 
    39 lines elided | 
    
      ↑ open up ↑ | 
  
  77   78   * the router will be stay at the VRRP_STATE_INIT state. If all the above
  78   79   * conditions are met, the VRRP router will be transit to either
  79   80   * the VRRP_STATE_MASTER or the VRRP_STATE_BACKUP state, depends on the VRRP
  80   81   * protocol.
  81   82   */
  82   83  
  83   84  #define skip_whitespace(p)      while (isspace(*(p))) ++(p)
  84   85  
  85   86  #define BUFFSIZE        65536
  86   87  
       88 +#define MAXLINELEN      1024
       89 +
  87   90  #define VRRPCONF        "/etc/inet/vrrp.conf"
  88   91  
  89   92  typedef struct vrrpd_rtsock_s {
  90   93          int             vrt_af;         /* address family */
  91   94          int             vrt_fd;         /* socket for the PF_ROUTE msg */
  92   95          iu_event_id_t   vrt_eid;        /* event ID */
  93   96  } vrrpd_rtsock_t;
  94   97  
  95   98  static ipadm_handle_t   vrrp_ipadm_handle = NULL;       /* libipadm handle */
  96   99  static int              vrrp_logflag = 0;
  97  100  boolean_t               vrrp_debug_level = 0;
  98  101  iu_eh_t                 *vrrpd_eh = NULL;
  99  102  iu_tq_t                 *vrrpd_timerq = NULL;
 100  103  static vrrp_handle_t    vrrpd_vh = NULL;
 101  104  static int              vrrpd_cmdsock_fd = -1;  /* socket to communicate */
 102  105                                                  /* between vrrpd/libvrrpadm */
 103  106  static iu_event_id_t    vrrpd_cmdsock_eid = -1;
 104  107  static int              vrrpd_ctlsock_fd = -1;  /* socket to bring up/down */
 105  108                                                  /* the virtual IP addresses */
 106  109  static int              vrrpd_ctlsock6_fd = -1;
 107  110  static vrrpd_rtsock_t   vrrpd_rtsocks[2] = {
 108  111          {AF_INET, -1, -1},
 109  112          {AF_INET6, -1, -1}
 110  113  };
 111  114  static iu_timer_id_t    vrrp_scan_timer_id = -1;
 112  115  
 113  116  TAILQ_HEAD(vrrp_vr_list_s, vrrp_vr_s);
 114  117  TAILQ_HEAD(vrrp_intf_list_s, vrrp_intf_s);
 115  118  static struct vrrp_vr_list_s    vrrp_vr_list;
 116  119  static struct vrrp_intf_list_s  vrrp_intf_list;
 117  120  static char             vrrpd_conffile[MAXPATHLEN];
 118  121  
 119  122  /*
 120  123   * Multicast address of VRRP advertisement in network byte order
 121  124   */
 122  125  static vrrp_addr_t      vrrp_muladdr4;
 123  126  static vrrp_addr_t      vrrp_muladdr6;
 124  127  
 125  128  static int              vrrpd_scan_interval = 20000;    /* ms */
 126  129  static int              pfds[2];
 127  130  
 128  131  /*
 129  132   * macros to calculate skew_time and master_down_timer
 130  133   *
 131  134   * Note that the input is in centisecs and output are in msecs
 132  135   */
 133  136  #define SKEW_TIME(pri, intv)    ((intv) * (256 - (pri)) / 256)
 134  137  #define MASTER_DOWN_INTERVAL(pri, intv) (3 * (intv) + SKEW_TIME((pri), (intv)))
 135  138  
 136  139  #define SKEW_TIME_VR(vr)        \
 137  140          SKEW_TIME((vr)->vvr_conf.vvc_pri, (vr)->vvr_master_adver_int)
 138  141  #define MASTER_DOWN_INTERVAL_VR(vr)     \
 139  142          MASTER_DOWN_INTERVAL((vr)->vvr_conf.vvc_pri, (vr)->vvr_master_adver_int)
 140  143  
 141  144  #define VRRP_CONF_UPDATE        0x01
 142  145  #define VRRP_CONF_DELETE        0x02
 143  146  
 144  147  static char *af_str(int);
 145  148  
 146  149  static iu_tq_callback_t vrrp_adv_timeout;
 147  150  static iu_tq_callback_t vrrp_b2m_timeout;
 148  151  static iu_eh_callback_t vrrpd_sock_handler;
 149  152  static iu_eh_callback_t vrrpd_rtsock_handler;
 150  153  static iu_eh_callback_t vrrpd_cmdsock_handler;
 151  154  
 152  155  static int daemon_init();
 153  156  
 154  157  static vrrp_err_t vrrpd_init();
 155  158  static void vrrpd_fini();
 156  159  static vrrp_err_t vrrpd_cmdsock_create();
 157  160  static void vrrpd_cmdsock_destroy();
 158  161  static vrrp_err_t vrrpd_rtsock_create();
 159  162  static void vrrpd_rtsock_destroy();
 160  163  static vrrp_err_t vrrpd_ctlsock_create();
 161  164  static void vrrpd_ctlsock_destroy();
 162  165  
 163  166  static void vrrpd_scan_timer(iu_tq_t *, void *);
 164  167  static void vrrpd_scan(int);
 165  168  static vrrp_err_t vrrpd_init_rxsock(vrrp_vr_t *);
 166  169  static void vrrpd_fini_rxsock(vrrp_vr_t *);
 167  170  static vrrp_err_t vrrpd_init_txsock(vrrp_vr_t *);
 168  171  static vrrp_err_t vrrpd_init_txsock_v4(vrrp_vr_t *);
 169  172  static vrrp_err_t vrrpd_init_txsock_v6(vrrp_vr_t *);
 170  173  static void vrrpd_fini_txsock(vrrp_vr_t *);
 171  174  
 172  175  static vrrp_err_t vrrpd_create_vr(vrrp_vr_conf_t *);
 173  176  static vrrp_err_t vrrpd_enable_vr(vrrp_vr_t *);
 174  177  static void vrrpd_disable_vr(vrrp_vr_t *, vrrp_intf_t *, boolean_t);
 175  178  static void vrrpd_delete_vr(vrrp_vr_t *);
 176  179  
 177  180  static vrrp_err_t vrrpd_create(vrrp_vr_conf_t *, boolean_t);
 178  181  static vrrp_err_t vrrpd_delete(const char *);
 179  182  static vrrp_err_t vrrpd_enable(const char *, boolean_t);
 180  183  static vrrp_err_t vrrpd_disable(const char *);
 181  184  static vrrp_err_t vrrpd_modify(vrrp_vr_conf_t *, uint32_t);
 182  185  static void vrrpd_list(vrid_t, char *, int, vrrp_ret_list_t *, size_t *);
 183  186  static void vrrpd_query(const char *, vrrp_ret_query_t *, size_t *);
 184  187  
 185  188  static boolean_t vrrp_rd_prop_name(vrrp_vr_conf_t *, const char *);
 186  189  static boolean_t vrrp_rd_prop_vrid(vrrp_vr_conf_t *, const char *);
 187  190  static boolean_t vrrp_rd_prop_af(vrrp_vr_conf_t *, const char *);
 188  191  static boolean_t vrrp_rd_prop_pri(vrrp_vr_conf_t *, const char *);
 189  192  static boolean_t vrrp_rd_prop_adver_int(vrrp_vr_conf_t *, const char *);
 190  193  static boolean_t vrrp_rd_prop_preempt(vrrp_vr_conf_t *, const char *);
 191  194  static boolean_t vrrp_rd_prop_accept(vrrp_vr_conf_t *, const char *);
 192  195  static boolean_t vrrp_rd_prop_ifname(vrrp_vr_conf_t *, const char *);
 193  196  static boolean_t vrrp_rd_prop_enabled(vrrp_vr_conf_t *, const char *);
 194  197  static int vrrp_wt_prop_name(vrrp_vr_conf_t *, char *, size_t);
 195  198  static int vrrp_wt_prop_vrid(vrrp_vr_conf_t *, char *, size_t);
 196  199  static int vrrp_wt_prop_af(vrrp_vr_conf_t *, char *, size_t);
 197  200  static int vrrp_wt_prop_pri(vrrp_vr_conf_t *, char *, size_t);
 198  201  static int vrrp_wt_prop_adver_int(vrrp_vr_conf_t *, char *, size_t);
 199  202  static int vrrp_wt_prop_preempt(vrrp_vr_conf_t *, char *, size_t);
 200  203  static int vrrp_wt_prop_accept(vrrp_vr_conf_t *, char *, size_t);
 201  204  static int vrrp_wt_prop_ifname(vrrp_vr_conf_t *, char *, size_t);
 202  205  static int vrrp_wt_prop_enabled(vrrp_vr_conf_t *, char *, size_t);
 203  206  
 204  207  static void vrrpd_cmd_create(void *, void *, size_t *);
 205  208  static void vrrpd_cmd_delete(void *, void *, size_t *);
 206  209  static void vrrpd_cmd_enable(void *, void *, size_t *);
 207  210  static void vrrpd_cmd_disable(void *, void *, size_t *);
 208  211  static void vrrpd_cmd_modify(void *, void *, size_t *);
 209  212  static void vrrpd_cmd_list(void *, void *, size_t *);
 210  213  static void vrrpd_cmd_query(void *, void *, size_t *);
 211  214  
 212  215  static vrrp_vr_t *vrrpd_lookup_vr_by_vrid(char *, vrid_t vrid_t, int);
 213  216  static vrrp_vr_t *vrrpd_lookup_vr_by_name(const char *);
 214  217  static vrrp_intf_t *vrrpd_lookup_if(const char *, int);
 215  218  static vrrp_err_t vrrpd_create_if(const char *, int, uint32_t, vrrp_intf_t **);
 216  219  static void vrrpd_delete_if(vrrp_intf_t *, boolean_t);
 217  220  static vrrp_err_t vrrpd_create_ip(vrrp_intf_t *, const char *, vrrp_addr_t *,
 218  221      uint64_t flags);
 219  222  static void vrrpd_delete_ip(vrrp_intf_t *, vrrp_ip_t *);
 220  223  
 221  224  static void vrrpd_init_ipcache(int);
 222  225  static void vrrpd_update_ipcache(int);
 223  226  static ipadm_status_t vrrpd_walk_addr_info(int);
 224  227  static vrrp_err_t vrrpd_add_ipaddr(char *, int, vrrp_addr_t *,
 225  228      int, uint64_t);
 226  229  static vrrp_ip_t *vrrpd_select_primary(vrrp_intf_t *);
 227  230  static void vrrpd_reselect_primary(vrrp_intf_t *);
 228  231  static void vrrpd_reenable_all_vr();
 229  232  static void vrrpd_remove_if(vrrp_intf_t *, boolean_t);
 230  233  
 231  234  static uint16_t in_cksum(int, uint16_t, void *);
 232  235  static uint16_t vrrp_cksum4(struct in_addr *, struct in_addr *,
 233  236      uint16_t, vrrp_pkt_t *);
 234  237  static uint16_t vrrp_cksum6(struct in6_addr *, struct in6_addr *,
 235  238      uint16_t, vrrp_pkt_t *);
 236  239  static size_t vrrpd_build_vrrp(vrrp_vr_t *, uchar_t *, int, boolean_t);
 237  240  
 238  241  static void vrrpd_process_adv(vrrp_vr_t *, vrrp_addr_t *, vrrp_pkt_t *);
 239  242  static vrrp_err_t vrrpd_send_adv(vrrp_vr_t *, boolean_t);
 240  243  
 241  244  /* state transition functions */
 242  245  static vrrp_err_t vrrpd_state_i2m(vrrp_vr_t *);
 243  246  static vrrp_err_t vrrpd_state_i2b(vrrp_vr_t *);
 244  247  static void vrrpd_state_m2i(vrrp_vr_t *);
 245  248  static void vrrpd_state_b2i(vrrp_vr_t *);
 246  249  static vrrp_err_t vrrpd_state_b2m(vrrp_vr_t *);
 247  250  static vrrp_err_t vrrpd_state_m2b(vrrp_vr_t *);
 248  251  static void vrrpd_state_trans(vrrp_state_t, vrrp_state_t, vrrp_vr_t *);
 249  252  
 250  253  static vrrp_err_t vrrpd_set_noaccept(vrrp_vr_t *, boolean_t);
 251  254  static vrrp_err_t vrrpd_virtualip_update(vrrp_vr_t *, boolean_t);
 252  255  static vrrp_err_t vrrpd_virtualip_updateone(vrrp_intf_t *, vrrp_ip_t *,
 253  256      boolean_t);
 254  257  static int vrrpd_post_event(const char *, vrrp_state_t, vrrp_state_t);
 255  258  
 256  259  static void vrrpd_initconf();
 257  260  static vrrp_err_t vrrpd_updateconf(vrrp_vr_conf_t *, uint_t);
 258  261  static vrrp_err_t vrrpd_write_vrconf(char *, size_t, vrrp_vr_conf_t *);
 259  262  static vrrp_err_t vrrpd_read_vrconf(char *, vrrp_vr_conf_t *);
 260  263  static vrrp_err_t vrrpd_readprop(const char *, vrrp_vr_conf_t *);
 261  264  static void vrrpd_cleanup();
 262  265  
 263  266  static void vrrp_log(int, char *, ...);
 264  267  static int timeval_to_milli(struct timeval);
 265  268  static struct timeval timeval_delta(struct timeval, struct timeval);
 266  269  
 267  270  typedef struct vrrpd_prop_s {
 268  271          char            *vs_propname;
 269  272          boolean_t       (*vs_propread)(vrrp_vr_conf_t *, const char *);
 270  273          int             (*vs_propwrite)(vrrp_vr_conf_t *, char *, size_t);
 271  274  } vrrp_prop_t;
 272  275  
 273  276  /*
 274  277   * persistent VRRP properties array
 275  278   */
 276  279  static vrrp_prop_t vrrp_prop_info_tbl[] = {
 277  280          {"name", vrrp_rd_prop_name, vrrp_wt_prop_name},
 278  281          {"vrid", vrrp_rd_prop_vrid, vrrp_wt_prop_vrid},
 279  282          {"priority", vrrp_rd_prop_pri, vrrp_wt_prop_pri},
 280  283          {"adv_intval", vrrp_rd_prop_adver_int, vrrp_wt_prop_adver_int},
 281  284          {"preempt_mode", vrrp_rd_prop_preempt, vrrp_wt_prop_preempt},
 282  285          {"accept_mode", vrrp_rd_prop_accept, vrrp_wt_prop_accept},
 283  286          {"interface", vrrp_rd_prop_ifname, vrrp_wt_prop_ifname},
 284  287          {"af", vrrp_rd_prop_af, vrrp_wt_prop_af},
 285  288          {"enabled", vrrp_rd_prop_enabled, vrrp_wt_prop_enabled}
 286  289  };
 287  290  
 288  291  #define VRRP_PROP_INFO_TABSIZE  \
 289  292          (sizeof (vrrp_prop_info_tbl) / sizeof (vrrp_prop_t))
 290  293  
 291  294  typedef void vrrp_cmd_func_t(void *, void *, size_t *);
 292  295  
 293  296  typedef struct vrrp_cmd_info_s {
 294  297          vrrp_cmd_type_t vi_cmd;
 295  298          size_t          vi_reqsize;
 296  299          size_t          vi_acksize;     /* 0 if the size is variable */
 297  300          boolean_t       vi_setop;       /* Set operation? Check credentials */
 298  301          vrrp_cmd_func_t *vi_cmdfunc;
 299  302  } vrrp_cmd_info_t;
 300  303  
 301  304  static vrrp_cmd_info_t vrrp_cmd_info_tbl[] = {
 302  305          {VRRP_CMD_CREATE, sizeof (vrrp_cmd_create_t),
 303  306              sizeof (vrrp_ret_create_t), _B_TRUE, vrrpd_cmd_create},
 304  307          {VRRP_CMD_DELETE, sizeof (vrrp_cmd_delete_t),
 305  308              sizeof (vrrp_ret_delete_t), _B_TRUE, vrrpd_cmd_delete},
 306  309          {VRRP_CMD_ENABLE, sizeof (vrrp_cmd_enable_t),
 307  310              sizeof (vrrp_ret_enable_t), _B_TRUE, vrrpd_cmd_enable},
 308  311          {VRRP_CMD_DISABLE, sizeof (vrrp_cmd_disable_t),
 309  312              sizeof (vrrp_ret_disable_t), _B_TRUE, vrrpd_cmd_disable},
 310  313          {VRRP_CMD_MODIFY, sizeof (vrrp_cmd_modify_t),
 311  314              sizeof (vrrp_ret_modify_t), _B_TRUE, vrrpd_cmd_modify},
 312  315          {VRRP_CMD_QUERY, sizeof (vrrp_cmd_query_t), 0,
 313  316              _B_FALSE, vrrpd_cmd_query},
 314  317          {VRRP_CMD_LIST, sizeof (vrrp_cmd_list_t), 0,
 315  318              _B_FALSE, vrrpd_cmd_list}
 316  319  };
 317  320  
 318  321  #define VRRP_DOOR_INFO_TABLE_SIZE       \
 319  322          (sizeof (vrrp_cmd_info_tbl) / sizeof (vrrp_cmd_info_t))
 320  323  
 321  324  static int
 322  325  ipaddr_cmp(int af, vrrp_addr_t *addr1, vrrp_addr_t *addr2)
 323  326  {
 324  327          if (af == AF_INET) {
 325  328                  return (memcmp(&addr1->in4.sin_addr,
 326  329                      &addr2->in4.sin_addr, sizeof (struct in_addr)));
 327  330          } else {
 328  331                  return (memcmp(&addr1->in6.sin6_addr,
 329  332                      &addr2->in6.sin6_addr, sizeof (struct in6_addr)));
 330  333          }
 331  334  }
 332  335  
 333  336  static vrrp_vr_t *
 334  337  vrrpd_lookup_vr_by_vrid(char *ifname, vrid_t vrid, int af)
 335  338  {
 336  339          vrrp_vr_t *vr;
 337  340  
 338  341          TAILQ_FOREACH(vr, &vrrp_vr_list, vvr_next) {
 339  342                  if (strcmp(vr->vvr_conf.vvc_link, ifname) == 0 &&
 340  343                      vr->vvr_conf.vvc_vrid == vrid &&
 341  344                      vr->vvr_conf.vvc_af == af) {
 342  345                          break;
 343  346                  }
 344  347          }
 345  348          return (vr);
 346  349  }
 347  350  
 348  351  static vrrp_vr_t *
 349  352  vrrpd_lookup_vr_by_name(const char *name)
 350  353  {
 351  354          vrrp_vr_t *vr;
 352  355  
 353  356          TAILQ_FOREACH(vr, &vrrp_vr_list, vvr_next) {
 354  357                  if (strcmp(vr->vvr_conf.vvc_name, name) == 0)
 355  358                          break;
 356  359          }
 357  360          return (vr);
 358  361  }
 359  362  
 360  363  static vrrp_intf_t *
 361  364  vrrpd_lookup_if(const char *ifname, int af)
 362  365  {
 363  366          vrrp_intf_t     *intf;
 364  367  
 365  368          TAILQ_FOREACH(intf, &vrrp_intf_list, vvi_next) {
 366  369                  if (strcmp(ifname, intf->vvi_ifname) == 0 &&
 367  370                      af == intf->vvi_af) {
 368  371                          break;
 369  372                  }
 370  373          }
 371  374          return (intf);
 372  375  }
 373  376  
 374  377  static vrrp_err_t
 375  378  vrrpd_create_if(const char *ifname, int af, uint32_t ifindex,
 376  379      vrrp_intf_t **intfp)
 377  380  {
 378  381          vrrp_intf_t     *intf;
 379  382  
 380  383          vrrp_log(VRRP_DBG0, "vrrpd_create_if(%s, %s, %d)",
 381  384              ifname, af_str(af), ifindex);
 382  385  
 383  386          if (((*intfp) = malloc(sizeof (vrrp_intf_t))) == NULL) {
 384  387                  vrrp_log(VRRP_ERR, "vrrpd_create_if(): failed to "
 385  388                      "allocate %s/%s interface", ifname, af_str(af));
 386  389                  return (VRRP_ENOMEM);
 387  390          }
 388  391  
 389  392          intf = *intfp;
 390  393          TAILQ_INIT(&intf->vvi_iplist);
 391  394          (void) strlcpy(intf->vvi_ifname, ifname, sizeof (intf->vvi_ifname));
 392  395          intf->vvi_af = af;
 393  396          intf->vvi_sockfd = -1;
 394  397          intf->vvi_nvr = 0;
 395  398          intf->vvi_eid = -1;
 396  399          intf->vvi_pip = NULL;
 397  400          intf->vvi_ifindex = ifindex;
 398  401          intf->vvi_state = NODE_STATE_NEW;
 399  402          intf->vvi_vr_state = VRRP_STATE_INIT;
 400  403          TAILQ_INSERT_TAIL(&vrrp_intf_list, intf, vvi_next);
 401  404          return (VRRP_SUCCESS);
 402  405  }
 403  406  
 404  407  /*
 405  408   * An interface is deleted. If update_vr is true, the deletion of the interface
 406  409   * may cause the state transition of assoicated VRRP router (if this interface
 407  410   * is either the primary or the VNIC interface of the VRRP router); otherwise,
 408  411   * simply delete the interface without updating the VRRP router.
 409  412   */
 410  413  static void
 411  414  vrrpd_delete_if(vrrp_intf_t *intf, boolean_t update_vr)
 412  415  {
 413  416          vrrp_ip_t       *ip;
 414  417  
 415  418          vrrp_log(VRRP_DBG0, "vrrpd_delete_if(%s, %s, %supdate_vr)",
 416  419              intf->vvi_ifname, af_str(intf->vvi_af), update_vr ? "" : "no_");
 417  420  
 418  421          if (update_vr) {
 419  422                  /*
 420  423                   * If a this interface is the physical interface or the VNIC
 421  424                   * of a VRRP router, the deletion of the interface (no IP
 422  425                   * address exists on this interface) may cause the state
 423  426                   * transition of the VRRP router. call vrrpd_remove_if()
 424  427                   * to find all corresponding VRRP router and update their
 425  428                   * states.
 426  429                   */
 427  430                  vrrpd_remove_if(intf, _B_FALSE);
 428  431          }
 429  432  
 430  433          /*
 431  434           * First remove and delete all the IP addresses on the interface
 432  435           */
 433  436          while (!TAILQ_EMPTY(&intf->vvi_iplist)) {
 434  437                  ip = TAILQ_FIRST(&intf->vvi_iplist);
 435  438                  vrrpd_delete_ip(intf, ip);
 436  439          }
 437  440  
 438  441          /*
 439  442           * Then remove and delete the interface
 440  443           */
 441  444          TAILQ_REMOVE(&vrrp_intf_list, intf, vvi_next);
 442  445          (void) free(intf);
 443  446  }
 444  447  
 445  448  static vrrp_err_t
 446  449  vrrpd_create_ip(vrrp_intf_t *intf, const char *lifname, vrrp_addr_t *addr,
 447  450      uint64_t flags)
 448  451  {
 449  452          vrrp_ip_t       *ip;
 450  453          char            abuf[INET6_ADDRSTRLEN];
 451  454  
 452  455          /* LINTED E_CONSTANT_CONDITION */
 453  456          VRRPADDR2STR(intf->vvi_af, addr, abuf, INET6_ADDRSTRLEN, _B_FALSE);
 454  457          vrrp_log(VRRP_DBG0, "vrrpd_create_ip(%s, %s, %s, 0x%x)",
 455  458              intf->vvi_ifname, lifname, abuf, flags);
 456  459  
 457  460          if ((ip = malloc(sizeof (vrrp_ip_t))) == NULL) {
 458  461                  vrrp_log(VRRP_ERR, "vrrpd_create_ip(%s, %s):"
 459  462                      "failed to allocate IP", lifname, abuf);
 460  463                  return (VRRP_ENOMEM);
 461  464          }
 462  465  
 463  466          (void) strncpy(ip->vip_lifname, lifname, sizeof (ip->vip_lifname));
 464  467          ip->vip_state = NODE_STATE_NEW;
 465  468          ip->vip_flags = flags;
 466  469          (void) memcpy(&ip->vip_addr, addr, sizeof (ip->vip_addr));
 467  470  
 468  471          /*
 469  472           * Make sure link-local IPv6 IP addresses are at the head of the list
 470  473           */
 471  474          if (intf->vvi_af == AF_INET6 &&
 472  475              IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr)) {
 473  476                  TAILQ_INSERT_HEAD(&intf->vvi_iplist, ip, vip_next);
 474  477          } else {
 475  478                  TAILQ_INSERT_TAIL(&intf->vvi_iplist, ip, vip_next);
 476  479          }
 477  480          return (VRRP_SUCCESS);
 478  481  }
 479  482  
 480  483  static void
 481  484  vrrpd_delete_ip(vrrp_intf_t *intf, vrrp_ip_t *ip)
 482  485  {
 483  486          char    abuf[INET6_ADDRSTRLEN];
 484  487          int     af = intf->vvi_af;
 485  488  
 486  489          /* LINTED E_CONSTANT_CONDITION */
 487  490          VRRPADDR2STR(af, &ip->vip_addr, abuf, sizeof (abuf), _B_FALSE);
 488  491          vrrp_log(VRRP_DBG0, "vrrpd_delete_ip(%s, %s, %s) is %sprimary",
 489  492              intf->vvi_ifname, ip->vip_lifname, abuf,
 490  493              intf->vvi_pip == ip ? "" : "not ");
 491  494  
 492  495          if (intf->vvi_pip == ip)
 493  496                  intf->vvi_pip = NULL;
 494  497  
 495  498          TAILQ_REMOVE(&intf->vvi_iplist, ip, vip_next);
 496  499          (void) free(ip);
 497  500  }
 498  501  
 499  502  static char *
 500  503  rtm_event2str(uchar_t event)
 501  504  {
 502  505          switch (event) {
 503  506          case RTM_NEWADDR:
 504  507                  return ("RTM_NEWADDR");
 505  508          case RTM_DELADDR:
 506  509                  return ("RTM_DELADDR");
 507  510          case RTM_IFINFO:
 508  511                  return ("RTM_IFINFO");
 509  512          case RTM_ADD:
 510  513                  return ("RTM_ADD");
 511  514          case RTM_DELETE:
 512  515                  return ("RTM_DELETE");
 513  516          case RTM_CHANGE:
 514  517                  return ("RTM_CHANGE");
 515  518          case RTM_OLDADD:
 516  519                  return ("RTM_OLDADD");
 517  520          case RTM_OLDDEL:
 518  521                  return ("RTM_OLDDEL");
 519  522          case RTM_CHGADDR:
 520  523                  return ("RTM_CHGADDR");
 521  524          case RTM_FREEADDR:
 522  525                  return ("RTM_FREEADDR");
 523  526          default:
 524  527                  return ("RTM_OTHER");
 525  528          }
 526  529  }
 527  530  
 528  531  /*
 529  532   * This is called by the child process to inform the parent process to
 530  533   * exit with the given return value. Note that the child process
 531  534   * (the daemon process) informs the parent process to exit when anything
 532  535   * goes wrong or when all the intialization is done.
 533  536   */
 534  537  static int
 535  538  vrrpd_inform_parent_exit(int rv)
 536  539  {
 537  540          int err = 0;
 538  541  
 539  542          /*
 540  543           * If vrrp_debug_level is none-zero, vrrpd is not running as
 541  544           * a daemon. Return directly.
 542  545           */
 543  546          if (vrrp_debug_level != 0)
 544  547                  return (0);
 545  548  
 546  549          if (write(pfds[1], &rv, sizeof (int)) != sizeof (int)) {
 547  550                  err = errno;
 548  551                  (void) close(pfds[1]);
 549  552                  return (err);
 550  553          }
 551  554          (void) close(pfds[1]);
 552  555          return (0);
 553  556  }
 554  557  
 555  558  int
 556  559  main(int argc, char *argv[])
 557  560  {
 558  561          int c, err;
 559  562          struct sigaction sa;
 560  563          sigset_t mask;
 561  564          struct rlimit rl;
 562  565  
 563  566          (void) setlocale(LC_ALL, "");
 564  567          (void) textdomain(TEXT_DOMAIN);
 565  568  
 566  569          /*
 567  570           * We need PRIV_SYS_CONFIG to post VRRP sysevent, PRIV_NET_RAWACESS
 568  571           * and PRIV_NET_ICMPACCESS to open  the raw socket, PRIV_SYS_IP_CONFIG
 569  572           * to bring up/down the virtual IP addresses, and PRIV_SYS_RESOURCE to
 570  573           * setrlimit().
 571  574           *
 572  575           * Note that sysevent is not supported in non-global zones.
 573  576           */
 574  577          if (getzoneid() == GLOBAL_ZONEID) {
 575  578                  err = __init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 0, 0,
 576  579                      PRIV_SYS_CONFIG, PRIV_NET_RAWACCESS, PRIV_NET_ICMPACCESS,
 577  580                      PRIV_SYS_IP_CONFIG, PRIV_SYS_RESOURCE, NULL);
 578  581          } else {
 579  582                  err = __init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 0, 0,
 580  583                      PRIV_NET_RAWACCESS, PRIV_NET_ICMPACCESS,
 581  584                      PRIV_SYS_IP_CONFIG, PRIV_SYS_RESOURCE, NULL);
 582  585          }
 583  586  
 584  587          if (err == -1) {
 585  588                  vrrp_log(VRRP_ERR, "main(): init_daemon_priv() failed");
 586  589                  return (EXIT_FAILURE);
 587  590          }
 588  591  
 589  592          /*
 590  593           * If vrrpd is started by other process, it will inherit the
 591  594           * signal block mask. We unblock all signals to make sure the
 592  595           * signal handling will work normally.
 593  596           */
 594  597          (void) sigfillset(&mask);
 595  598          (void) thr_sigsetmask(SIG_UNBLOCK, &mask, NULL);
 596  599          sa.sa_handler = vrrpd_cleanup;
 597  600          sa.sa_flags = 0;
 598  601          (void) sigemptyset(&sa.sa_mask);
 599  602          (void) sigaction(SIGINT, &sa, NULL);
 600  603          (void) sigaction(SIGQUIT, &sa, NULL);
 601  604          (void) sigaction(SIGTERM, &sa, NULL);
 602  605  
 603  606          vrrp_debug_level = 0;
 604  607          (void) strlcpy(vrrpd_conffile, VRRPCONF, sizeof (vrrpd_conffile));
 605  608          while ((c = getopt(argc, argv, "d:f:")) != EOF) {
 606  609                  switch (c) {
 607  610                  case 'd':
 608  611                          vrrp_debug_level = atoi(optarg);
 609  612                          break;
 610  613                  case 'f':
 611  614                          (void) strlcpy(vrrpd_conffile, optarg,
 612  615                              sizeof (vrrpd_conffile));
 613  616                          break;
 614  617                  default:
 615  618                          break;
 616  619                  }
 617  620          }
 618  621  
 619  622          closefrom(3);
 620  623          if (vrrp_debug_level == 0 && (daemon_init() != 0)) {
 621  624                  vrrp_log(VRRP_ERR, "main(): daemon_init() failed");
 622  625                  return (EXIT_FAILURE);
 623  626          }
 624  627  
 625  628          rl.rlim_cur = RLIM_INFINITY;
 626  629          rl.rlim_max = RLIM_INFINITY;
 627  630          if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
 628  631                  vrrp_log(VRRP_ERR, "main(): setrlimit() failed");
 629  632                  goto child_out;
 630  633          }
 631  634  
 632  635          if (vrrpd_init() != VRRP_SUCCESS) {
 633  636                  vrrp_log(VRRP_ERR, "main(): vrrpd_init() failed");
 634  637                  goto child_out;
 635  638          }
 636  639  
 637  640          /*
 638  641           * Get rid of unneeded privileges.
 639  642           */
 640  643          __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
 641  644              PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, PRIV_SYS_RESOURCE, NULL);
 642  645  
 643  646          /*
 644  647           * Read the configuration and initialize the existing VRRP
 645  648           * configuration
 646  649           */
 647  650          vrrpd_initconf();
 648  651  
 649  652          /*
 650  653           * Inform the parent process that it can successfully exit.
 651  654           */
 652  655          if ((err = vrrpd_inform_parent_exit(EXIT_SUCCESS)) != 0) {
 653  656                  vrrpd_cleanup();
 654  657                  vrrp_log(VRRP_WARNING, "vrrpd_inform_parent_exit() failed: %s",
 655  658                      strerror(err));
 656  659                  return (EXIT_FAILURE);
 657  660          }
 658  661  
 659  662          /*
 660  663           * Start the loop to handle the timer and the IO events.
 661  664           */
 662  665          switch (iu_handle_events(vrrpd_eh, vrrpd_timerq)) {
 663  666          case -1:
 664  667                  vrrp_log(VRRP_ERR, "main(): iu_handle_events() failed "
 665  668                      "abnormally");
 666  669                  break;
 667  670          default:
 668  671                  break;
 669  672          }
 670  673  
 671  674          vrrpd_cleanup();
 672  675          return (EXIT_SUCCESS);
 673  676  
 674  677  child_out:
 675  678          (void) vrrpd_inform_parent_exit(EXIT_FAILURE);
 676  679          return (EXIT_FAILURE);
 677  680  }
 678  681  
 679  682  static int
 680  683  daemon_init()
 681  684  {
 682  685          pid_t   pid;
 683  686          int     rv;
 684  687  
 685  688          vrrp_log(VRRP_DBG0, "daemon_init()");
 686  689  
 687  690          if (getenv("SMF_FMRI") == NULL) {
 688  691                  vrrp_log(VRRP_ERR, "daemon_init(): vrrpd is an smf(5) managed "
 689  692                      "service and should not be run from the command line.");
 690  693                  return (-1);
 691  694          }
 692  695  
 693  696          /*
 694  697           * Create the pipe used for the child process to inform the parent
 695  698           * process to exit after all initialization is done.
 696  699           */
 697  700          if (pipe(pfds) < 0) {
 698  701                  vrrp_log(VRRP_ERR, "daemon_init(): pipe() failed: %s",
 699  702                      strerror(errno));
 700  703                  return (-1);
 701  704          }
 702  705  
 703  706          if ((pid = fork()) < 0) {
 704  707                  vrrp_log(VRRP_ERR, "daemon_init(): fork() failed: %s",
 705  708                      strerror(errno));
 706  709                  (void) close(pfds[0]);
 707  710                  (void) close(pfds[1]);
 708  711                  return (-1);
 709  712          }
 710  713  
 711  714          if (pid != 0) { /* Parent */
 712  715                  (void) close(pfds[1]);
 713  716  
 714  717                  /*
 715  718                   * Read the child process's return value from the pfds.
 716  719                   * If the child process exits unexpectedly, read() returns -1.
 717  720                   */
 718  721                  if (read(pfds[0], &rv, sizeof (int)) != sizeof (int)) {
 719  722                          vrrp_log(VRRP_ERR, "daemon_init(): child process "
 720  723                              "exited unexpectedly %s", strerror(errno));
 721  724                          (void) kill(pid, SIGTERM);
 722  725                          rv = EXIT_FAILURE;
 723  726                  }
 724  727                  (void) close(pfds[0]);
 725  728                  exit(rv);
 726  729          }
 727  730  
 728  731          /*
 729  732           * in child process, became a daemon, and return to main() to continue.
 730  733           */
 731  734          (void) close(pfds[0]);
 732  735          (void) chdir("/");
 733  736          (void) setsid();
 734  737          (void) close(0);
 735  738          (void) close(1);
 736  739          (void) close(2);
 737  740          (void) open("/dev/null", O_RDWR, 0);
 738  741          (void) dup2(0, 1);
 739  742          (void) dup2(0, 2);
 740  743          openlog("vrrpd", LOG_PID, LOG_DAEMON);
 741  744          vrrp_logflag = 1;
 742  745          return (0);
 743  746  }
 744  747  
 745  748  static vrrp_err_t
 746  749  vrrpd_init()
 747  750  {
 748  751          vrrp_err_t      err = VRRP_ESYS;
 749  752  
 750  753          vrrp_log(VRRP_DBG0, "vrrpd_init()");
 751  754  
 752  755          TAILQ_INIT(&vrrp_vr_list);
 753  756          TAILQ_INIT(&vrrp_intf_list);
 754  757  
 755  758          if (vrrp_open(&vrrpd_vh) != VRRP_SUCCESS) {
 756  759                  vrrp_log(VRRP_ERR, "vrrpd_init(): vrrp_open() failed");
 757  760                  goto fail;
 758  761          }
 759  762  
 760  763          if ((vrrpd_timerq = iu_tq_create()) == NULL) {
 761  764                  vrrp_log(VRRP_ERR, "vrrpd_init(): iu_tq_create() failed");
 762  765                  goto fail;
 763  766          }
 764  767  
 765  768          if ((vrrpd_eh = iu_eh_create()) == NULL) {
 766  769                  vrrp_log(VRRP_ERR, "vrrpd_init(): iu_eh_create() failed");
 767  770                  goto fail;
 768  771          }
 769  772  
 770  773          /*
 771  774           * Create the AF_UNIX socket used to communicate with libvrrpadm.
 772  775           *
 773  776           * This socket is used to receive the administrative requests and
 774  777           * send back the results.
 775  778           */
 776  779          if (vrrpd_cmdsock_create() != VRRP_SUCCESS) {
 777  780                  vrrp_log(VRRP_ERR, "vrrpd_init(): vrrpd_cmdsock_create() "
 778  781                      "failed");
 779  782                  goto fail;
 780  783          }
 781  784  
 782  785          /*
 783  786           * Create the VRRP control socket used to bring up/down the virtual
 784  787           * IP addresses. It is also used to set the IFF_NOACCEPT flag of
 785  788           * the virtual IP addresses.
 786  789           */
 787  790          if (vrrpd_ctlsock_create() != VRRP_SUCCESS) {
 788  791                  vrrp_log(VRRP_ERR, "vrrpd_init(): vrrpd_ctlsock_create() "
 789  792                      "failed");
 790  793                  goto fail;
 791  794          }
 792  795  
 793  796          /*
 794  797           * Create the PF_ROUTER socket used to listen to the routing socket
 795  798           * messages and build the interface/IP address list.
 796  799           */
 797  800          if (vrrpd_rtsock_create() != VRRP_SUCCESS) {
 798  801                  vrrp_log(VRRP_ERR, "vrrpd_init(): vrrpd_rtsock_create() "
 799  802                      "failed");
 800  803                  goto fail;
 801  804          }
 802  805  
 803  806          /* Open the libipadm handle */
 804  807          if (ipadm_open(&vrrp_ipadm_handle, 0) != IPADM_SUCCESS) {
 805  808                  vrrp_log(VRRP_ERR, "vrrpd_init(): ipadm_open() failed");
 806  809                  goto fail;
 807  810          }
 808  811  
 809  812          /*
 810  813           * Build the list of interfaces and IP addresses. Also, start the time
 811  814           * to scan the interfaces/IP addresses periodically.
 812  815           */
 813  816          vrrpd_scan(AF_INET);
 814  817          vrrpd_scan(AF_INET6);
 815  818          if ((vrrp_scan_timer_id = iu_schedule_timer_ms(vrrpd_timerq,
 816  819              vrrpd_scan_interval, vrrpd_scan_timer, NULL)) == -1) {
 817  820                  vrrp_log(VRRP_ERR, "vrrpd_init(): start scan_timer failed");
 818  821                  goto fail;
 819  822          }
 820  823  
 821  824          /*
 822  825           * Initialize the VRRP multicast address.
 823  826           */
 824  827          bzero(&vrrp_muladdr4, sizeof (vrrp_addr_t));
 825  828          vrrp_muladdr4.in4.sin_family = AF_INET;
 826  829          (void) inet_pton(AF_INET, "224.0.0.18", &vrrp_muladdr4.in4.sin_addr);
 827  830  
 828  831          bzero(&vrrp_muladdr6, sizeof (vrrp_addr_t));
 829  832          vrrp_muladdr6.in6.sin6_family = AF_INET6;
 830  833          (void) inet_pton(AF_INET6, "ff02::12", &vrrp_muladdr6.in6.sin6_addr);
 831  834  
 832  835          return (VRRP_SUCCESS);
 833  836  
 834  837  fail:
 835  838          vrrpd_fini();
 836  839          return (err);
 837  840  }
 838  841  
 839  842  static void
 840  843  vrrpd_fini()
 841  844  {
 842  845          vrrp_log(VRRP_DBG0, "vrrpd_fini()");
 843  846  
 844  847          (void) iu_cancel_timer(vrrpd_timerq, vrrp_scan_timer_id, NULL);
 845  848          vrrp_scan_timer_id = -1;
 846  849  
 847  850          vrrpd_rtsock_destroy();
 848  851          vrrpd_ctlsock_destroy();
 849  852          vrrpd_cmdsock_destroy();
 850  853  
 851  854          if (vrrpd_eh != NULL) {
 852  855                  iu_eh_destroy(vrrpd_eh);
 853  856                  vrrpd_eh = NULL;
 854  857          }
 855  858  
 856  859          if (vrrpd_timerq != NULL) {
 857  860                  iu_tq_destroy(vrrpd_timerq);
 858  861                  vrrpd_timerq = NULL;
 859  862          }
 860  863  
 861  864          vrrp_close(vrrpd_vh);
 862  865          vrrpd_vh = NULL;
 863  866          assert(TAILQ_EMPTY(&vrrp_vr_list));
 864  867          assert(TAILQ_EMPTY(&vrrp_intf_list));
 865  868  
 866  869          ipadm_close(vrrp_ipadm_handle);
 867  870  }
 868  871  
 869  872  static void
 870  873  vrrpd_cleanup(void)
 871  874  {
 872  875          vrrp_vr_t       *vr;
 873  876          vrrp_intf_t     *intf;
 874  877  
 875  878          vrrp_log(VRRP_DBG0, "vrrpd_cleanup()");
 876  879  
 877  880          while (!TAILQ_EMPTY(&vrrp_vr_list)) {
 878  881                  vr = TAILQ_FIRST(&vrrp_vr_list);
 879  882                  vrrpd_delete_vr(vr);
 880  883          }
 881  884  
 882  885          while (!TAILQ_EMPTY(&vrrp_intf_list)) {
 883  886                  intf = TAILQ_FIRST(&vrrp_intf_list);
 884  887                  vrrpd_delete_if(intf, _B_FALSE);
 885  888          }
 886  889  
 887  890          vrrpd_fini();
 888  891          closelog();
 889  892          exit(1);
 890  893  }
 891  894  
 892  895  /*
 893  896   * Read the configuration file and initialize all the existing VRRP routers.
 894  897   */
 895  898  static void
 896  899  vrrpd_initconf()
 897  900  {
 898  901          FILE *fp;
 899  902          char line[LINE_MAX];
 900  903          int linenum = 0;
 901  904          vrrp_vr_conf_t conf;
 902  905          vrrp_err_t err;
 903  906  
 904  907          vrrp_log(VRRP_DBG0, "vrrpd_initconf()");
 905  908  
 906  909          if ((fp = fopen(vrrpd_conffile, "rF")) == NULL) {
 907  910                  vrrp_log(VRRP_ERR, "failed to open the configuration file %s",
 908  911                      vrrpd_conffile);
 909  912                  return;
 910  913          }
 911  914  
 912  915          while (fgets(line, sizeof (line), fp) != NULL) {
 913  916                  linenum++;
 914  917                  conf.vvc_vrid = VRRP_VRID_NONE;
 915  918                  if ((err = vrrpd_read_vrconf(line, &conf)) != VRRP_SUCCESS) {
 916  919                          vrrp_log(VRRP_ERR, "failed to parse %d line %s",
 917  920                              linenum, line);
 918  921                          continue;
 919  922                  }
 920  923  
 921  924                  /*
 922  925                   * Blank or comment line
 923  926                   */
 924  927                  if (conf.vvc_vrid == VRRP_VRID_NONE)
 925  928                          continue;
 926  929  
 927  930                  /*
 928  931                   * No need to update the configuration since the VRRP router
 929  932                   * created/enabled based on the existing configuration.
 930  933                   */
 931  934                  if ((err = vrrpd_create(&conf, _B_FALSE)) != VRRP_SUCCESS) {
 932  935                          vrrp_log(VRRP_ERR, "VRRP router %s creation failed: "
 933  936                              "%s", conf.vvc_name, vrrp_err2str(err));
 934  937                          continue;
 935  938                  }
 936  939  
 937  940                  if (conf.vvc_enabled &&
 938  941                      ((err = vrrpd_enable(conf.vvc_name, _B_FALSE)) !=
 939  942                      VRRP_SUCCESS)) {
 940  943                          vrrp_log(VRRP_ERR, "VRRP router %s enable failed: %s",
 941  944                              conf.vvc_name, vrrp_err2str(err));
 942  945                  }
 943  946          }
 944  947  
 945  948          (void) fclose(fp);
 946  949  }
 947  950  
 948  951  /*
 949  952   * Create the AF_UNIX socket used to communicate with libvrrpadm.
 950  953   *
 951  954   * This socket is used to receive the administrative request and
 952  955   * send back the results.
 953  956   */
 954  957  static vrrp_err_t
 955  958  vrrpd_cmdsock_create()
 956  959  {
 957  960          iu_event_id_t           eid;
 958  961          struct sockaddr_un      laddr;
 959  962          int                     sock, flags;
 960  963  
 961  964          vrrp_log(VRRP_DBG0, "vrrpd_cmdsock_create()");
 962  965  
 963  966          if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
 964  967                  vrrp_log(VRRP_ERR, "vrrpd_cmdsock_create(): socket(AF_UNIX) "
 965  968                      "failed: %s", strerror(errno));
 966  969                  return (VRRP_ESYS);
 967  970          }
 968  971  
 969  972          /*
 970  973           * Set it to be non-blocking.
 971  974           */
 972  975          flags = fcntl(sock, F_GETFL, 0);
 973  976          (void) fcntl(sock, F_SETFL, (flags | O_NONBLOCK));
 974  977  
 975  978          /*
 976  979           * Unlink first in case a previous daemon instance exited ungracefully.
 977  980           */
 978  981          (void) unlink(VRRPD_SOCKET);
 979  982  
 980  983          bzero(&laddr, sizeof (laddr));
 981  984          laddr.sun_family = AF_UNIX;
 982  985          (void) strlcpy(laddr.sun_path, VRRPD_SOCKET, sizeof (laddr.sun_path));
 983  986          if (bind(sock, (struct sockaddr *)&laddr, sizeof (laddr)) < 0) {
 984  987                  vrrp_log(VRRP_ERR, "vrrpd_cmdsock_create(): bind() failed: %s",
 985  988                      strerror(errno));
 986  989                  (void) close(sock);
 987  990                  return (VRRP_ESYS);
 988  991          }
 989  992  
 990  993          if (listen(sock, 30) < 0) {
 991  994                  vrrp_log(VRRP_ERR, "vrrpd_cmdsock_create(): listen() "
 992  995                      "failed: %s", strerror(errno));
 993  996                  (void) close(sock);
 994  997                  return (VRRP_ESYS);
 995  998          }
 996  999  
 997 1000          if ((eid = iu_register_event(vrrpd_eh, sock, POLLIN,
 998 1001              vrrpd_cmdsock_handler, NULL)) == -1) {
 999 1002                  vrrp_log(VRRP_ERR, "vrrpd_cmdsock_create(): iu_register_event()"
1000 1003                      " failed");
1001 1004                  (void) close(sock);
1002 1005                  return (VRRP_ESYS);
1003 1006          }
1004 1007  
1005 1008          vrrpd_cmdsock_fd = sock;
1006 1009          vrrpd_cmdsock_eid = eid;
1007 1010          return (VRRP_SUCCESS);
1008 1011  }
1009 1012  
1010 1013  static void
1011 1014  vrrpd_cmdsock_destroy()
1012 1015  {
1013 1016          vrrp_log(VRRP_DBG0, "vrrpd_cmdsock_destroy()");
1014 1017  
1015 1018          (void) iu_unregister_event(vrrpd_eh, vrrpd_cmdsock_eid, NULL);
1016 1019          (void) close(vrrpd_cmdsock_fd);
1017 1020          vrrpd_cmdsock_fd = -1;
1018 1021          vrrpd_cmdsock_eid = -1;
1019 1022  }
1020 1023  
1021 1024  /*
1022 1025   * Create the PF_ROUTER sockets used to listen to the routing socket
1023 1026   * messages and build the interface/IP address list. Create one for
1024 1027   * each address family (IPv4 and IPv6).
1025 1028   */
1026 1029  static vrrp_err_t
1027 1030  vrrpd_rtsock_create()
1028 1031  {
1029 1032          int             i, flags, sock;
1030 1033          iu_event_id_t   eid;
1031 1034  
1032 1035          vrrp_log(VRRP_DBG0, "vrrpd_rtsock_create()");
1033 1036  
1034 1037          for (i = 0; i < 2; i++) {
1035 1038                  sock = socket(PF_ROUTE, SOCK_RAW, vrrpd_rtsocks[i].vrt_af);
1036 1039                  if (sock == -1) {
1037 1040                          vrrp_log(VRRP_ERR, "vrrpd_rtsock_create(): socket() "
1038 1041                              "failed: %s", strerror(errno));
1039 1042                          break;
1040 1043                  }
1041 1044  
1042 1045                  /*
1043 1046                   * Set it to be non-blocking.
1044 1047                   */
1045 1048                  if ((flags = fcntl(sock, F_GETFL, 0)) < 0) {
1046 1049                          vrrp_log(VRRP_ERR, "vrrpd_rtsock_create(): "
1047 1050                              "fcntl(F_GETFL) failed: %s", strerror(errno));
1048 1051                          break;
1049 1052                  }
1050 1053  
1051 1054                  if ((fcntl(sock, F_SETFL, flags | O_NONBLOCK)) < 0) {
1052 1055                          vrrp_log(VRRP_ERR, "vrrpd_rtsock_create(): "
1053 1056                              "fcntl(F_SETFL) failed: %s", strerror(errno));
1054 1057                          break;
1055 1058                  }
1056 1059  
1057 1060                  if ((eid = iu_register_event(vrrpd_eh, sock, POLLIN,
1058 1061                      vrrpd_rtsock_handler, &(vrrpd_rtsocks[i].vrt_af))) == -1) {
1059 1062                          vrrp_log(VRRP_ERR, "vrrpd_rtsock_create(): register "
1060 1063                              "rtsock %d(%s) failed", sock,
1061 1064                              af_str(vrrpd_rtsocks[i].vrt_af));
1062 1065                          break;
1063 1066                  }
1064 1067  
1065 1068                  vrrpd_rtsocks[i].vrt_fd = sock;
1066 1069                  vrrpd_rtsocks[i].vrt_eid = eid;
1067 1070          }
1068 1071  
1069 1072          if (i != 2) {
1070 1073                  (void) close(sock);
1071 1074                  vrrpd_rtsock_destroy();
1072 1075                  return (VRRP_ESYS);
1073 1076          }
1074 1077  
1075 1078          return (VRRP_SUCCESS);
1076 1079  }
1077 1080  
1078 1081  static void
1079 1082  vrrpd_rtsock_destroy()
1080 1083  {
1081 1084          int             i;
1082 1085  
1083 1086          vrrp_log(VRRP_DBG0, "vrrpd_rtsock_destroy()");
1084 1087          for (i = 0; i < 2; i++) {
1085 1088                  (void) iu_unregister_event(vrrpd_eh, vrrpd_rtsocks[i].vrt_eid,
1086 1089                      NULL);
1087 1090                  (void) close(vrrpd_rtsocks[i].vrt_fd);
1088 1091                  vrrpd_rtsocks[i].vrt_eid = -1;
1089 1092                  vrrpd_rtsocks[i].vrt_fd = -1;
1090 1093          }
1091 1094  }
1092 1095  
1093 1096  /*
1094 1097   * Create the VRRP control socket used to bring up/down the virtual
1095 1098   * IP addresses. It is also used to set the IFF_NOACCEPT flag of
1096 1099   * the virtual IP addresses.
1097 1100   */
1098 1101  static vrrp_err_t
1099 1102  vrrpd_ctlsock_create()
1100 1103  {
1101 1104          int     s, s6;
1102 1105          int     on = _B_TRUE;
1103 1106  
1104 1107          if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1105 1108                  vrrp_log(VRRP_ERR, "vrrpd_ctlsock_create(): socket(INET) "
1106 1109                      "failed: %s", strerror(errno));
1107 1110                  return (VRRP_ESYS);
1108 1111          }
1109 1112          if (setsockopt(s, SOL_SOCKET, SO_VRRP, &on, sizeof (on)) < 0) {
1110 1113                  vrrp_log(VRRP_ERR, "vrrpd_ctlsock_create(): "
1111 1114                      "setsockopt(INET, SO_VRRP) failed: %s", strerror(errno));
1112 1115                  (void) close(s);
1113 1116                  return (VRRP_ESYS);
1114 1117          }
1115 1118  
1116 1119          if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1117 1120                  vrrp_log(VRRP_ERR, "vrrpd_ctlsock_create(): socket(INET6) "
1118 1121                      "failed: %s", strerror(errno));
1119 1122                  (void) close(s);
1120 1123                  return (VRRP_ESYS);
1121 1124          }
1122 1125          if (setsockopt(s6, SOL_SOCKET, SO_VRRP, &on, sizeof (on)) < 0) {
1123 1126                  vrrp_log(VRRP_ERR, "vrrpd_ctlsock_create(): "
1124 1127                      "setsockopt(INET6, SO_VRRP) failed: %s", strerror(errno));
1125 1128                  (void) close(s);
1126 1129                  (void) close(s6);
1127 1130                  return (VRRP_ESYS);
1128 1131          }
1129 1132  
1130 1133          vrrpd_ctlsock_fd = s;
1131 1134          vrrpd_ctlsock6_fd = s6;
1132 1135          return (VRRP_SUCCESS);
1133 1136  }
1134 1137  
1135 1138  static void
1136 1139  vrrpd_ctlsock_destroy()
1137 1140  {
1138 1141          (void) close(vrrpd_ctlsock_fd);
1139 1142          vrrpd_ctlsock_fd = -1;
1140 1143          (void) close(vrrpd_ctlsock6_fd);
1141 1144          vrrpd_ctlsock6_fd = -1;
1142 1145  }
1143 1146  
1144 1147  /*ARGSUSED*/
1145 1148  static void
1146 1149  vrrpd_cmd_create(void *arg1, void *arg2, size_t *arg2_sz)
1147 1150  {
1148 1151          vrrp_cmd_create_t       *cmd = (vrrp_cmd_create_t *)arg1;
1149 1152          vrrp_ret_create_t       *ret = (vrrp_ret_create_t *)arg2;
1150 1153          vrrp_err_t              err;
1151 1154  
1152 1155          err = vrrpd_create(&cmd->vcc_conf, _B_TRUE);
1153 1156          if (err == VRRP_SUCCESS && cmd->vcc_conf.vvc_enabled) {
1154 1157                  /*
1155 1158                   * No need to update the configuration since it is already
1156 1159                   * done in the above vrrpd_create() call
1157 1160                   */
1158 1161                  err = vrrpd_enable(cmd->vcc_conf.vvc_name, _B_FALSE);
1159 1162                  if (err != VRRP_SUCCESS)
1160 1163                          (void) vrrpd_delete(cmd->vcc_conf.vvc_name);
1161 1164          }
1162 1165          ret->vrc_err = err;
1163 1166  }
1164 1167  
1165 1168  /*ARGSUSED*/
1166 1169  static void
1167 1170  vrrpd_cmd_delete(void *arg1, void *arg2, size_t *arg2_sz)
1168 1171  {
1169 1172          vrrp_cmd_delete_t       *cmd = (vrrp_cmd_delete_t *)arg1;
1170 1173          vrrp_ret_delete_t       *ret = (vrrp_ret_delete_t *)arg2;
1171 1174  
1172 1175          ret->vrd_err = vrrpd_delete(cmd->vcd_name);
1173 1176  }
1174 1177  
1175 1178  /*ARGSUSED*/
1176 1179  static void
1177 1180  vrrpd_cmd_enable(void *arg1, void *arg2, size_t *arg2_sz)
1178 1181  {
1179 1182          vrrp_cmd_enable_t       *cmd = (vrrp_cmd_enable_t *)arg1;
1180 1183          vrrp_ret_enable_t       *ret = (vrrp_ret_enable_t *)arg2;
1181 1184  
1182 1185          ret->vrs_err = vrrpd_enable(cmd->vcs_name, _B_TRUE);
1183 1186  }
1184 1187  
1185 1188  /*ARGSUSED*/
1186 1189  static void
1187 1190  vrrpd_cmd_disable(void *arg1, void *arg2, size_t *arg2_sz)
1188 1191  {
1189 1192          vrrp_cmd_disable_t      *cmd = (vrrp_cmd_disable_t *)arg1;
1190 1193          vrrp_ret_disable_t      *ret = (vrrp_ret_disable_t *)arg2;
1191 1194  
1192 1195          ret->vrx_err = vrrpd_disable(cmd->vcx_name);
1193 1196  }
1194 1197  
1195 1198  /*ARGSUSED*/
1196 1199  static void
1197 1200  vrrpd_cmd_modify(void *arg1, void *arg2, size_t *arg2_sz)
1198 1201  {
1199 1202          vrrp_cmd_modify_t       *cmd = (vrrp_cmd_modify_t *)arg1;
1200 1203          vrrp_ret_modify_t       *ret = (vrrp_ret_modify_t *)arg2;
1201 1204  
1202 1205          ret->vrm_err = vrrpd_modify(&cmd->vcm_conf, cmd->vcm_mask);
1203 1206  }
1204 1207  
1205 1208  static void
1206 1209  vrrpd_cmd_query(void *arg1, void *arg2, size_t *arg2_sz)
1207 1210  {
1208 1211          vrrp_cmd_query_t        *cmd = (vrrp_cmd_query_t *)arg1;
1209 1212  
1210 1213          vrrpd_query(cmd->vcq_name, arg2, arg2_sz);
1211 1214  }
1212 1215  
1213 1216  static void
1214 1217  vrrpd_cmd_list(void *arg1, void *arg2, size_t *arg2_sz)
1215 1218  {
1216 1219          vrrp_cmd_list_t *cmd = (vrrp_cmd_list_t *)arg1;
1217 1220  
1218 1221          vrrpd_list(cmd->vcl_vrid, cmd->vcl_ifname, cmd->vcl_af, arg2, arg2_sz);
1219 1222  }
1220 1223  
1221 1224  /*
1222 1225   * Write-type requeset must have the solaris.network.vrrp authorization.
1223 1226   */
1224 1227  static boolean_t
1225 1228  vrrp_auth_check(int connfd, vrrp_cmd_info_t *cinfo)
1226 1229  {
1227 1230          ucred_t         *cred = NULL;
1228 1231          uid_t           uid;
1229 1232          struct passwd   *pw;
1230 1233          boolean_t       success = _B_FALSE;
1231 1234  
1232 1235          vrrp_log(VRRP_DBG0, "vrrp_auth_check()");
1233 1236  
1234 1237          if (!cinfo->vi_setop)
1235 1238                  return (_B_TRUE);
1236 1239  
1237 1240          /*
1238 1241           * Validate the credential
1239 1242           */
1240 1243          if (getpeerucred(connfd, &cred) == (uid_t)-1) {
1241 1244                  vrrp_log(VRRP_ERR, "vrrp_auth_check(): getpeerucred() "
1242 1245                      "failed: %s", strerror(errno));
1243 1246                  return (_B_FALSE);
1244 1247          }
1245 1248  
1246 1249          if ((uid = ucred_getruid((const ucred_t *)cred)) == (uid_t)-1) {
1247 1250                  vrrp_log(VRRP_ERR, "vrrp_auth_check(): ucred_getruid() "
1248 1251                      "failed: %s", strerror(errno));
1249 1252                  goto done;
1250 1253          }
1251 1254  
1252 1255          if ((pw = getpwuid(uid)) == NULL) {
1253 1256                  vrrp_log(VRRP_ERR, "vrrp_auth_check(): getpwuid() failed");
1254 1257                  goto done;
1255 1258          }
1256 1259  
1257 1260          success = (chkauthattr("solaris.network.vrrp", pw->pw_name) == 1);
1258 1261  
1259 1262  done:
1260 1263          ucred_free(cred);
1261 1264          return (success);
1262 1265  }
1263 1266  
1264 1267  /*
1265 1268   * Process the administrative request from libvrrpadm
1266 1269   */
1267 1270  /* ARGSUSED */
1268 1271  static void
1269 1272  vrrpd_cmdsock_handler(iu_eh_t *eh, int s, short events, iu_event_id_t id,
1270 1273      void *arg)
1271 1274  {
1272 1275          vrrp_cmd_info_t         *cinfo = NULL;
1273 1276          vrrp_err_t              err = VRRP_SUCCESS;
1274 1277          uchar_t                 buf[BUFFSIZE], ackbuf[BUFFSIZE];
1275 1278          size_t                  cursize, acksize, len;
1276 1279          uint32_t                cmd;
1277 1280          int                     connfd, i;
1278 1281          struct sockaddr_in      from;
1279 1282          socklen_t               fromlen;
1280 1283  
1281 1284          vrrp_log(VRRP_DBG0, "vrrpd_cmdsock_handler()");
1282 1285  
1283 1286          fromlen = (socklen_t)sizeof (from);
1284 1287          if ((connfd = accept(s, (struct sockaddr *)&from, &fromlen)) < 0) {
1285 1288                  vrrp_log(VRRP_ERR, "vrrpd_cmdsock_handler() accept(): %s",
1286 1289                      strerror(errno));
1287 1290                  return;
1288 1291          }
1289 1292  
1290 1293          /*
1291 1294           * First get the type of the request
1292 1295           */
1293 1296          cursize = 0;
1294 1297          while (cursize < sizeof (uint32_t)) {
1295 1298                  len = read(connfd, buf + cursize,
1296 1299                      sizeof (uint32_t) - cursize);
1297 1300                  if (len == (size_t)-1 && (errno == EAGAIN || errno == EINTR)) {
1298 1301                          continue;
1299 1302                  } else if (len > 0) {
1300 1303                          cursize += len;
1301 1304                          continue;
1302 1305                  }
1303 1306                  vrrp_log(VRRP_ERR, "vrrpd_cmdsock_handler(): invalid message "
1304 1307                      "length");
1305 1308                  (void) close(connfd);
1306 1309                  return;
1307 1310          }
1308 1311  
1309 1312          /* LINTED E_BAD_PTR_CAST_ALIGN */
1310 1313          cmd = ((vrrp_cmd_t *)buf)->vc_cmd;
1311 1314          for (i = 0; i < VRRP_DOOR_INFO_TABLE_SIZE; i++) {
1312 1315                  if (vrrp_cmd_info_tbl[i].vi_cmd == cmd) {
1313 1316                          cinfo = vrrp_cmd_info_tbl + i;
1314 1317                          break;
1315 1318                  }
1316 1319          }
1317 1320  
1318 1321          if (cinfo == NULL) {
1319 1322                  vrrp_log(VRRP_ERR, "vrrpd_cmdsock_handler(): invalid request "
1320 1323                      "type %d", cmd);
1321 1324                  err = VRRP_EINVAL;
1322 1325                  goto done;
1323 1326          }
1324 1327  
1325 1328          /*
1326 1329           * Get the rest of the request.
1327 1330           */
1328 1331          assert(cursize == sizeof (uint32_t));
1329 1332          while (cursize < cinfo->vi_reqsize) {
1330 1333                  len = read(connfd, buf + cursize,
1331 1334                      cinfo->vi_reqsize - cursize);
1332 1335                  if (len == (size_t)-1 && (errno == EAGAIN || errno == EINTR)) {
1333 1336                          continue;
1334 1337                  } else if (len > 0) {
1335 1338                          cursize += len;
1336 1339                          continue;
1337 1340                  }
1338 1341                  vrrp_log(VRRP_ERR, "vrrpd_cmdsock_handler(): invalid message "
1339 1342                      "length");
1340 1343                  err = VRRP_EINVAL;
1341 1344                  goto done;
1342 1345          }
1343 1346  
1344 1347          /*
1345 1348           * Validate the authorization
1346 1349           */
1347 1350          if (!vrrp_auth_check(connfd, cinfo)) {
1348 1351                  vrrp_log(VRRP_ERR, "vrrpd_cmdsock_handler(): "
1349 1352                      "not sufficient authorization");
1350 1353                  err = VRRP_EPERM;
1351 1354          }
1352 1355  
1353 1356  done:
1354 1357          /*
1355 1358           * Ack the request
1356 1359           */
1357 1360          if (err != 0) {
1358 1361                  /* LINTED E_BAD_PTR_CAST_ALIGN */
1359 1362                  ((vrrp_ret_t *)ackbuf)->vr_err = err;
1360 1363                  acksize = sizeof (vrrp_ret_t);
1361 1364          } else {
1362 1365                  /*
1363 1366                   * If the size of ack is varied, the cmdfunc callback
1364 1367                   * will set the right size.
1365 1368                   */
1366 1369                  if ((acksize = cinfo->vi_acksize) == 0)
1367 1370                          acksize = sizeof (ackbuf);
1368 1371  
1369 1372                  /* LINTED E_BAD_PTR_CAST_ALIGN */
1370 1373                  cinfo->vi_cmdfunc((vrrp_cmd_t *)buf, ackbuf, &acksize);
1371 1374          }
1372 1375  
1373 1376          /*
1374 1377           * Send the ack back.
1375 1378           */
1376 1379          cursize = 0;
1377 1380          while (cursize < acksize) {
1378 1381                  len = sendto(connfd, ackbuf + cursize, acksize - cursize,
1379 1382                      0, (struct sockaddr *)&from, fromlen);
1380 1383                  if (len == (size_t)-1 && errno == EAGAIN) {
1381 1384                          continue;
1382 1385                  } else if (len > 0) {
1383 1386                          cursize += len;
1384 1387                          continue;
1385 1388                  } else {
1386 1389                          vrrp_log(VRRP_ERR, "vrrpd_cmdsock_handler() failed to "
1387 1390                              "ack: %s", strerror(errno));
1388 1391                          break;
1389 1392                  }
1390 1393          }
1391 1394  
1392 1395          (void) shutdown(connfd, SHUT_RDWR);
1393 1396          (void) close(connfd);
1394 1397  }
1395 1398  
1396 1399  /*
1397 1400   * Process the routing socket messages and update the interfaces/IP addresses
1398 1401   * list
1399 1402   */
1400 1403  /* ARGSUSED */
1401 1404  static void
1402 1405  vrrpd_rtsock_handler(iu_eh_t *eh, int s, short events,
1403 1406      iu_event_id_t id, void *arg)
1404 1407  {
1405 1408          char                    buf[BUFFSIZE];
1406 1409          struct ifa_msghdr       *ifam;
1407 1410          int                     nbytes;
1408 1411          int                     af = *(int *)arg;
1409 1412          boolean_t               scanif = _B_FALSE;
1410 1413  
1411 1414          for (;;) {
1412 1415                  nbytes = read(s, buf, sizeof (buf));
1413 1416                  if (nbytes <= 0) {
1414 1417                          /* No more messages */
1415 1418                          break;
1416 1419                  }
1417 1420  
1418 1421                  /* LINTED E_BAD_PTR_CAST_ALIGN */
1419 1422                  ifam = (struct ifa_msghdr *)buf;
1420 1423                  if (ifam->ifam_version != RTM_VERSION) {
1421 1424                          vrrp_log(VRRP_ERR, "vrrpd_rtsock_handler(): version %d "
1422 1425                              "not understood", ifam->ifam_version);
1423 1426                          break;
1424 1427                  }
1425 1428  
1426 1429                  vrrp_log(VRRP_DBG0, "vrrpd_rtsock_handler(): recv %s event",
1427 1430                      rtm_event2str(ifam->ifam_type));
1428 1431  
1429 1432                  switch (ifam->ifam_type) {
1430 1433                  case RTM_FREEADDR:
1431 1434                  case RTM_CHGADDR:
1432 1435                  case RTM_NEWADDR:
1433 1436                  case RTM_DELADDR:
1434 1437                          /*
1435 1438                           * An IP address has been created/updated/deleted or
1436 1439                           * brought up/down, re-initilialize the interface/IP
1437 1440                           * address list.
1438 1441                           */
1439 1442                          scanif = _B_TRUE;
1440 1443                          break;
1441 1444                  default:
1442 1445                          /* Not interesting */
1443 1446                          break;
1444 1447                  }
1445 1448          }
1446 1449  
1447 1450          if (scanif)
1448 1451                  vrrpd_scan(af);
1449 1452  }
1450 1453  
1451 1454  /*
1452 1455   * Periodically scan the interface/IP addresses on the system.
1453 1456   */
1454 1457  /* ARGSUSED */
1455 1458  static void
1456 1459  vrrpd_scan_timer(iu_tq_t *tq, void *arg)
1457 1460  {
1458 1461          vrrp_log(VRRP_DBG0, "vrrpd_scan_timer()");
1459 1462          vrrpd_scan(AF_INET);
1460 1463          vrrpd_scan(AF_INET6);
1461 1464  }
1462 1465  
1463 1466  /*
1464 1467   * Get the list of the interface/IP addresses of the specified address
1465 1468   * family.
1466 1469   */
1467 1470  static void
1468 1471  vrrpd_scan(int af)
1469 1472  {
1470 1473          vrrp_log(VRRP_DBG0, "vrrpd_scan(%s)", af_str(af));
1471 1474  
1472 1475  again:
1473 1476          vrrpd_init_ipcache(af);
1474 1477  
1475 1478          /* If interface index changes, walk again. */
1476 1479          if (vrrpd_walk_addr_info(af) != IPADM_SUCCESS)
1477 1480                  goto again;
1478 1481  
1479 1482          vrrpd_update_ipcache(af);
1480 1483  }
1481 1484  
1482 1485  /*
1483 1486   * First mark all IP addresses of the specific address family to be removed.
1484 1487   * This flag will then be cleared when we walk up all the IP addresses.
1485 1488   */
1486 1489  static void
1487 1490  vrrpd_init_ipcache(int af)
1488 1491  {
1489 1492          vrrp_intf_t     *intf, *next_intf;
1490 1493          vrrp_ip_t       *ip, *nextip;
1491 1494          char            abuf[INET6_ADDRSTRLEN];
1492 1495  
1493 1496          vrrp_log(VRRP_DBG0, "vrrpd_init_ipcache(%s)", af_str(af));
1494 1497  
1495 1498          next_intf = TAILQ_FIRST(&vrrp_intf_list);
1496 1499          while ((intf = next_intf) != NULL) {
1497 1500                  next_intf = TAILQ_NEXT(intf, vvi_next);
1498 1501                  if (intf->vvi_af != af)
1499 1502                          continue;
1500 1503  
1501 1504                  /*
1502 1505                   * If the interface is still marked as new, it means that this
1503 1506                   * vrrpd_init_ipcache() call is a result of ifindex change,
1504 1507                   * which causes the re-walk of all the interfaces (see
1505 1508                   * vrrpd_add_ipaddr()), and some interfaces are still marked
1506 1509                   * as new during the last walk. In this case, delete this
1507 1510                   * interface with the "update_vr" argument to be _B_FALSE,
1508 1511                   * since no VRRP router has been assoicated with this
1509 1512                   * interface yet (the association is done in
1510 1513                   * vrrpd_update_ipcache()).
1511 1514                   *
1512 1515                   * This interface will be re-added later if it still exists.
1513 1516                   */
1514 1517                  if (intf->vvi_state == NODE_STATE_NEW) {
1515 1518                          vrrp_log(VRRP_DBG0, "vrrpd_init_ipcache(): remove %s "
1516 1519                              "(%d), may be added later", intf->vvi_ifname,
1517 1520                              intf->vvi_ifindex);
1518 1521                          vrrpd_delete_if(intf, _B_FALSE);
1519 1522                          continue;
1520 1523                  }
1521 1524  
1522 1525                  for (ip = TAILQ_FIRST(&intf->vvi_iplist); ip != NULL;
1523 1526                      ip = nextip) {
1524 1527                          nextip = TAILQ_NEXT(ip, vip_next);
1525 1528                          /* LINTED E_CONSTANT_CONDITION */
1526 1529                          VRRPADDR2STR(af, &ip->vip_addr, abuf,
1527 1530                              INET6_ADDRSTRLEN, _B_FALSE);
1528 1531  
1529 1532                          if (ip->vip_state != NODE_STATE_NEW) {
1530 1533                                  vrrp_log(VRRP_DBG0, "vrrpd_init_ipcache(%s/%d, "
1531 1534                                      "%s(%s/0x%x))", intf->vvi_ifname,
1532 1535                                      intf->vvi_ifindex, ip->vip_lifname,
1533 1536                                      abuf, ip->vip_flags);
1534 1537                                  ip->vip_state = NODE_STATE_STALE;
1535 1538                                  continue;
1536 1539                          }
1537 1540  
1538 1541                          /*
1539 1542                           * If the IP is still marked as new, it means that
1540 1543                           * this vrrpd_init_ipcache() call is a result of
1541 1544                           * ifindex change, which causes the re-walk of all
1542 1545                           * the IP addresses (see vrrpd_add_ipaddr()).
1543 1546                           * Delete this IP.
1544 1547                           *
1545 1548                           * This IP will be readded later if it still exists.
1546 1549                           */
1547 1550                          vrrp_log(VRRP_DBG0, "vrrpd_init_ipcache(): remove "
1548 1551                              "%s/%d , %s(%s)", intf->vvi_ifname,
1549 1552                              intf->vvi_ifindex, ip->vip_lifname, abuf);
1550 1553                          vrrpd_delete_ip(intf, ip);
1551 1554                  }
1552 1555          }
1553 1556  }
1554 1557  
1555 1558  /*
1556 1559   * Walk all the IP addresses of the given family and update its
1557 1560   * addresses list. Return IPADM_FAILURE if it is required to walk
1558 1561   * all the interfaces again (one of the interface index changes in between).
1559 1562   */
1560 1563  static ipadm_status_t
1561 1564  vrrpd_walk_addr_info(int af)
1562 1565  {
1563 1566          ipadm_addr_info_t       *ainfo, *ainfop;
1564 1567          ipadm_status_t          ipstatus;
1565 1568          char                    *lifname;
1566 1569          struct sockaddr_storage stor;
1567 1570          vrrp_addr_t             *addr;
1568 1571          int                     ifindex;
1569 1572          uint64_t                flags;
1570 1573  
1571 1574          vrrp_log(VRRP_DBG0, "vrrpd_walk_addr_info(%s)", af_str(af));
1572 1575  
1573 1576          ipstatus = ipadm_addr_info(vrrp_ipadm_handle, NULL, &ainfo, 0, 0);
1574 1577          if (ipstatus != IPADM_SUCCESS) {
1575 1578                  vrrp_log(VRRP_ERR, "vrrpd_walk_addr_info(%s): "
1576 1579                      "ipadm_addr_info() failed: %s",
1577 1580                      af_str(af), ipadm_status2str(ipstatus));
1578 1581                  return (IPADM_SUCCESS);
1579 1582          }
1580 1583  
1581 1584          for (ainfop = ainfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) {
1582 1585                  if (ainfop->ia_ifa.ifa_addr->sa_family != af)
1583 1586                          continue;
1584 1587  
1585 1588                  lifname = ainfop->ia_ifa.ifa_name;
1586 1589                  flags = ainfop->ia_ifa.ifa_flags;
1587 1590                  (void) memcpy(&stor, ainfop->ia_ifa.ifa_addr, sizeof (stor));
1588 1591                  addr = (vrrp_addr_t *)&stor;
1589 1592  
1590 1593                  vrrp_log(VRRP_DBG0, "vrrpd_walk_addr_info(%s): %s",
1591 1594                      af_str(af), lifname);
1592 1595  
1593 1596                  /* Skip virtual/IPMP/P2P interfaces */
1594 1597                  if (flags & (IFF_VIRTUAL|IFF_IPMP|IFF_POINTOPOINT)) {
1595 1598                          vrrp_log(VRRP_DBG0, "vrrpd_walk_addr_info(%s): "
1596 1599                              "skipped %s", af_str(af), lifname);
1597 1600                          continue;
1598 1601                  }
1599 1602  
1600 1603                  /* Filter out the all-zero IP address */
1601 1604                  if (VRRPADDR_UNSPECIFIED(af, addr))
1602 1605                          continue;
1603 1606  
1604 1607                  if ((ifindex = if_nametoindex(lifname)) == 0) {
1605 1608                          if (errno != ENXIO && errno != ENOENT) {
1606 1609                                  vrrp_log(VRRP_ERR, "vrrpd_walk_addr_info(%s): "
1607 1610                                      "if_nametoindex() failed for %s: %s",
1608 1611                                      af_str(af), lifname, strerror(errno));
1609 1612                          }
1610 1613                          break;
1611 1614                  }
1612 1615  
1613 1616                  /*
1614 1617                   * The interface is unplumbed/replumbed during the walk.  Try
1615 1618                   * to walk the IP addresses one more time.
1616 1619                   */
1617 1620                  if (vrrpd_add_ipaddr(lifname, af, addr, ifindex, flags)
1618 1621                      == VRRP_EAGAIN) {
1619 1622                          ipstatus = IPADM_FAILURE;
1620 1623                          break;
1621 1624                  }
1622 1625          }
1623 1626  
1624 1627          ipadm_free_addr_info(ainfo);
1625 1628          return (ipstatus);
1626 1629  }
1627 1630  
1628 1631  /*
1629 1632   * Given the information of each IP address, update the interface and
1630 1633   * IP addresses list
1631 1634   */
1632 1635  static vrrp_err_t
1633 1636  vrrpd_add_ipaddr(char *lifname, int af, vrrp_addr_t *addr, int ifindex,
1634 1637      uint64_t flags)
1635 1638  {
1636 1639          char            ifname[LIFNAMSIZ], *c;
1637 1640          vrrp_intf_t     *intf;
1638 1641          vrrp_ip_t       *ip;
1639 1642          char            abuf[INET6_ADDRSTRLEN];
1640 1643          vrrp_err_t      err;
1641 1644  
1642 1645          /* LINTED E_CONSTANT_CONDITION */
1643 1646          VRRPADDR2STR(af, addr, abuf, INET6_ADDRSTRLEN, _B_FALSE);
1644 1647          vrrp_log(VRRP_DBG0, "vrrpd_add_ipaddr(%s, %s, %d, 0x%x)", lifname,
1645 1648              abuf, ifindex, flags);
1646 1649  
1647 1650          /*
1648 1651           * Get the physical interface name from the logical interface name.
1649 1652           */
1650 1653          (void) strlcpy(ifname, lifname, sizeof (ifname));
1651 1654          if ((c = strchr(ifname, ':')) != NULL)
1652 1655                  *c = '\0';
1653 1656  
1654 1657          if ((intf = vrrpd_lookup_if(ifname, af)) == NULL) {
1655 1658                  vrrp_log(VRRP_DBG0, "vrrpd_add_ipaddr(): %s is new", ifname);
1656 1659                  err = vrrpd_create_if(ifname, af, ifindex, &intf);
1657 1660                  if (err != VRRP_SUCCESS)
1658 1661                          return (err);
1659 1662          } else if (intf->vvi_ifindex != ifindex) {
1660 1663                  /*
1661 1664                   * If index changes, it means that this interface is
1662 1665                   * unplumbed/replumbed since we last checked. If this
1663 1666                   * interface is not used by any VRRP router, just
1664 1667                   * update its ifindex, and the IP addresses list will
1665 1668                   * be updated later. Otherwise, return EAGAIN to rewalk
1666 1669                   * all the IP addresses from the beginning.
1667 1670                   */
1668 1671                  vrrp_log(VRRP_DBG0, "vrrpd_add_ipaddr(%s) ifindex changed ",
1669 1672                      "from %d to %d", ifname, intf->vvi_ifindex, ifindex);
1670 1673                  if (!IS_PRIMARY_INTF(intf) && !IS_VIRTUAL_INTF(intf)) {
1671 1674                          intf->vvi_ifindex = ifindex;
1672 1675                  } else {
1673 1676                          /*
1674 1677                           * delete this interface from the list if this
1675 1678                           * interface has already been assoicated with
1676 1679                           * any VRRP routers.
1677 1680                           */
1678 1681                          vrrpd_delete_if(intf, _B_TRUE);
1679 1682                          return (VRRP_EAGAIN);
1680 1683                  }
1681 1684          }
1682 1685  
1683 1686          /*
1684 1687           * Does this IP address already exist?
1685 1688           */
1686 1689          TAILQ_FOREACH(ip, &intf->vvi_iplist, vip_next) {
1687 1690                  if (strcmp(ip->vip_lifname, lifname) == 0)
1688 1691                          break;
1689 1692          }
1690 1693  
1691 1694          if (ip != NULL) {
1692 1695                  vrrp_log(VRRP_DBG0, "vrrpd_add_ipaddr(%s, %s) IP exists",
1693 1696                      lifname, abuf);
1694 1697                  ip->vip_state = NODE_STATE_NONE;
1695 1698                  ip->vip_flags = flags;
1696 1699                  if (ipaddr_cmp(af, addr, &ip->vip_addr) != 0) {
1697 1700                          /*
1698 1701                           * Address has been changed, mark it as new
1699 1702                           * If this address is already selected as the
1700 1703                           * primary IP address, the new IP will be checked
1701 1704                           * to see whether it is still qualified as the
1702 1705                           * primary IP address. If not, the primary IP
1703 1706                           * address will be reselected.
1704 1707                           */
1705 1708                          (void) memcpy(&ip->vip_addr, addr,
1706 1709                              sizeof (vrrp_addr_t));
1707 1710  
1708 1711                          ip->vip_state = NODE_STATE_NEW;
1709 1712                  }
1710 1713          } else {
1711 1714                  vrrp_log(VRRP_DBG0, "vrrpd_add_ipaddr(%s, %s) IP is new",
1712 1715                      lifname, abuf);
1713 1716  
1714 1717                  err = vrrpd_create_ip(intf, lifname, addr, flags);
1715 1718                  if (err != VRRP_SUCCESS)
1716 1719                          return (err);
1717 1720          }
1718 1721          return (VRRP_SUCCESS);
1719 1722  }
1720 1723  
1721 1724  /*
1722 1725   * Update the interface and IP addresses list. Remove the ones that have been
1723 1726   * staled since last time we walk the IP addresses and updated the ones that
1724 1727   * have been changed.
1725 1728   */
1726 1729  static void
1727 1730  vrrpd_update_ipcache(int af)
1728 1731  {
1729 1732          vrrp_intf_t     *intf, *nextif;
1730 1733          vrrp_ip_t       *ip, *nextip;
1731 1734          char            abuf[INET6_ADDRSTRLEN];
1732 1735          boolean_t       primary_selected;
1733 1736          boolean_t       primary_now_selected;
1734 1737          boolean_t       need_reenable = _B_FALSE;
1735 1738  
1736 1739          vrrp_log(VRRP_DBG0, "vrrpd_update_ipcache(%s)", af_str(af));
1737 1740  
1738 1741          nextif = TAILQ_FIRST(&vrrp_intf_list);
1739 1742          while ((intf = nextif) != NULL) {
1740 1743                  nextif = TAILQ_NEXT(intf, vvi_next);
1741 1744                  if (intf->vvi_af != af)
1742 1745                          continue;
1743 1746  
1744 1747                  /*
1745 1748                   * Does the interface already select its primary IP address?
1746 1749                   */
1747 1750                  primary_selected = (intf->vvi_pip != NULL);
1748 1751                  assert(!primary_selected || IS_PRIMARY_INTF(intf));
1749 1752  
1750 1753                  /*
1751 1754                   * Removed the IP addresses that have been unconfigured.
1752 1755                   */
1753 1756                  for (ip = TAILQ_FIRST(&intf->vvi_iplist); ip != NULL;
1754 1757                      ip = nextip) {
1755 1758                          nextip = TAILQ_NEXT(ip, vip_next);
1756 1759                          if (ip->vip_state != NODE_STATE_STALE)
1757 1760                                  continue;
1758 1761  
1759 1762                          /* LINTED E_CONSTANT_CONDITION */
1760 1763                          VRRPADDR2STR(af, &ip->vip_addr, abuf, INET6_ADDRSTRLEN,
1761 1764                              _B_FALSE);
1762 1765                          vrrp_log(VRRP_DBG0, "vrrpd_update_ipcache(): IP %s "
1763 1766                              "is removed over %s", abuf, intf->vvi_ifname);
1764 1767                          vrrpd_delete_ip(intf, ip);
1765 1768                  }
1766 1769  
1767 1770                  /*
1768 1771                   * No IP addresses left, delete this interface.
1769 1772                   */
1770 1773                  if (TAILQ_EMPTY(&intf->vvi_iplist)) {
1771 1774                          vrrp_log(VRRP_DBG0, "vrrpd_update_ipcache(): "
1772 1775                              "no IP left over %s", intf->vvi_ifname);
1773 1776                          vrrpd_delete_if(intf, _B_TRUE);
1774 1777                          continue;
1775 1778                  }
1776 1779  
1777 1780                  /*
1778 1781                   * If this is selected ss the physical interface for any
1779 1782                   * VRRP router, reselect the primary address if needed.
1780 1783                   */
1781 1784                  if (IS_PRIMARY_INTF(intf)) {
1782 1785                          vrrpd_reselect_primary(intf);
1783 1786                          primary_now_selected = (intf->vvi_pip != NULL);
1784 1787  
1785 1788                          /*
1786 1789                           * Cannot find the new primary IP address.
1787 1790                           */
1788 1791                          if (primary_selected && !primary_now_selected) {
1789 1792                                  vrrp_log(VRRP_DBG0, "vrrpd_update_ipcache() "
1790 1793                                      "reselect primary IP on %s failed",
1791 1794                                      intf->vvi_ifname);
1792 1795                                  vrrpd_remove_if(intf, _B_TRUE);
1793 1796                          } else if (!primary_selected && primary_now_selected) {
1794 1797                                  /*
1795 1798                                   * The primary IP address is successfully
1796 1799                                   * selected on the physical interfacew we
1797 1800                                   * need to walk through all the VRRP routers
1798 1801                                   * that is created on this physical interface
1799 1802                                   * and see whether they can now be enabled.
1800 1803                                   */
1801 1804                                  need_reenable = _B_TRUE;
1802 1805                          }
1803 1806                  }
1804 1807  
1805 1808                  /*
1806 1809                   * For every new virtual IP address, bring up/down it based
1807 1810                   * on the state of VRRP router.
1808 1811                   *
1809 1812                   * Note that it is fine to not update the IP's vip_flags field
1810 1813                   * even if vrrpd_virtualip_updateone() changed the address's
1811 1814                   * up/down state, since the vip_flags field is only used for
1812 1815                   * select primary IP address over a physical interface, and
1813 1816                   * vrrpd_virtualip_updateone() only affects the virtual IP
1814 1817                   * address's status.
1815 1818                   */
1816 1819                  for (ip = TAILQ_FIRST(&intf->vvi_iplist); ip != NULL;
1817 1820                      ip = nextip) {
1818 1821                          nextip = TAILQ_NEXT(ip, vip_next);
1819 1822                          /* LINTED E_CONSTANT_CONDITION */
1820 1823                          VRRPADDR2STR(af, &ip->vip_addr, abuf, INET6_ADDRSTRLEN,
1821 1824                              _B_FALSE);
1822 1825                          vrrp_log(VRRP_DBG0, "vrrpd_update_ipcache(): "
1823 1826                              "IP %s over %s%s", abuf, intf->vvi_ifname,
1824 1827                              ip->vip_state == NODE_STATE_NEW ? " is new" : "");
1825 1828  
1826 1829                          if (IS_VIRTUAL_INTF(intf)) {
1827 1830                                  /*
1828 1831                                   * If this IP is new, update its up/down state
1829 1832                                   * based on the virtual interface's state
1830 1833                                   * (which is determined by the VRRP router's
1831 1834                                   * state). Otherwise, check only and prompt
1832 1835                                   * warnings if its up/down state has been
1833 1836                                   * changed.
1834 1837                                   */
1835 1838                                  if (vrrpd_virtualip_updateone(intf, ip,
1836 1839                                      ip->vip_state == NODE_STATE_NONE) !=
1837 1840                                      VRRP_SUCCESS) {
1838 1841                                          vrrp_log(VRRP_DBG0,
1839 1842                                              "vrrpd_update_ipcache(): "
1840 1843                                              "IP %s over %s update failed", abuf,
1841 1844                                              intf->vvi_ifname);
1842 1845                                          vrrpd_delete_ip(intf, ip);
1843 1846                                          continue;
1844 1847                                  }
1845 1848                          }
1846 1849                          ip->vip_state = NODE_STATE_NONE;
1847 1850                  }
1848 1851  
1849 1852                  /*
1850 1853                   * The IP address is deleted when it is failed to be brought
1851 1854                   * up. If no IP addresses are left, delete this interface.
1852 1855                   */
1853 1856                  if (TAILQ_EMPTY(&intf->vvi_iplist)) {
1854 1857                          vrrp_log(VRRP_DBG0, "vrrpd_update_ipcache(): "
1855 1858                              "no IP left over %s", intf->vvi_ifname);
1856 1859                          vrrpd_delete_if(intf, _B_TRUE);
1857 1860                          continue;
1858 1861                  }
1859 1862  
1860 1863                  if (intf->vvi_state == NODE_STATE_NEW) {
1861 1864                          /*
1862 1865                           * A new interface is found. This interface can be
1863 1866                           * the primary interface or the virtual VNIC
1864 1867                           * interface.  Again, we need to walk throught all
1865 1868                           * the VRRP routers to see whether some of them can
1866 1869                           * now be enabled because of the new primary IP
1867 1870                           * address or the new virtual IP addresses.
1868 1871                           */
1869 1872                          intf->vvi_state = NODE_STATE_NONE;
1870 1873                          need_reenable = _B_TRUE;
1871 1874                  }
1872 1875          }
1873 1876  
1874 1877          if (need_reenable)
1875 1878                  vrrpd_reenable_all_vr();
1876 1879  }
1877 1880  
1878 1881  /*
1879 1882   * Reselect primary IP if:
1880 1883   * - The existing primary IP is no longer qualified (removed or it is down or
1881 1884   *   not a link-local IP for IPv6 VRRP router);
1882 1885   * - This is a physical interface but no primary IP is chosen;
1883 1886   */
1884 1887  static void
1885 1888  vrrpd_reselect_primary(vrrp_intf_t *intf)
1886 1889  {
1887 1890          vrrp_ip_t       *ip;
1888 1891          char            abuf[INET6_ADDRSTRLEN];
1889 1892  
1890 1893          assert(IS_PRIMARY_INTF(intf));
1891 1894  
1892 1895          /*
1893 1896           * If the interface's old primary IP address is still valid, return
1894 1897           */
1895 1898          if (((ip = intf->vvi_pip) != NULL) && (QUALIFY_PRIMARY_ADDR(intf, ip)))
1896 1899                  return;
1897 1900  
1898 1901          if (ip != NULL) {
1899 1902                  /* LINTED E_CONSTANT_CONDITION */
1900 1903                  VRRPADDR2STR(intf->vvi_af, &ip->vip_addr, abuf,
1901 1904                      sizeof (abuf), _B_FALSE);
1902 1905                  vrrp_log(VRRP_DBG0, "vrrpd_reselect_primary(%s): primary IP %s "
1903 1906                      "is no longer qualified", intf->vvi_ifname, abuf);
1904 1907          }
1905 1908  
1906 1909          ip = vrrpd_select_primary(intf);
1907 1910          intf->vvi_pip = ip;
1908 1911  
1909 1912          if (ip != NULL) {
1910 1913                  /* LINTED E_CONSTANT_CONDITION */
1911 1914                  VRRPADDR2STR(intf->vvi_af, &ip->vip_addr, abuf,
1912 1915                      sizeof (abuf), _B_FALSE);
1913 1916                  vrrp_log(VRRP_DBG0, "vrrpd_reselect_primary(%s): primary IP %s "
1914 1917                      "is selected", intf->vvi_ifname, abuf);
1915 1918          }
1916 1919  }
1917 1920  
1918 1921  /*
1919 1922   * Select the primary IP address. Since the link-local IP address is always
1920 1923   * at the head of the IP address list, try to find the first UP IP address
1921 1924   * and see whether it qualify.
1922 1925   */
1923 1926  static vrrp_ip_t *
1924 1927  vrrpd_select_primary(vrrp_intf_t *pif)
1925 1928  {
1926 1929          vrrp_ip_t       *pip;
1927 1930          char            abuf[INET6_ADDRSTRLEN];
1928 1931  
1929 1932          vrrp_log(VRRP_DBG1, "vrrpd_select_primary(%s)", pif->vvi_ifname);
1930 1933  
1931 1934          TAILQ_FOREACH(pip, &pif->vvi_iplist, vip_next) {
1932 1935                  assert(pip->vip_state != NODE_STATE_STALE);
1933 1936  
1934 1937                  /* LINTED E_CONSTANT_CONDITION */
1935 1938                  VRRPADDR2STR(pif->vvi_af, &pip->vip_addr, abuf,
1936 1939                      INET6_ADDRSTRLEN, _B_FALSE);
1937 1940                  vrrp_log(VRRP_DBG0, "vrrpd_select_primary(%s): %s is %s",
1938 1941                      pif->vvi_ifname, abuf,
1939 1942                      (pip->vip_flags & IFF_UP) ? "up" : "down");
1940 1943  
1941 1944                  if (pip->vip_flags & IFF_UP)
1942 1945                          break;
1943 1946          }
1944 1947  
1945 1948          /*
1946 1949           * Is this valid primary IP address?
1947 1950           */
1948 1951          if (pip == NULL || !QUALIFY_PRIMARY_ADDR(pif, pip)) {
1949 1952                  vrrp_log(VRRP_DBG0, "vrrpd_select_primary(%s/%s) failed",
1950 1953                      pif->vvi_ifname, af_str(pif->vvi_af));
1951 1954                  return (NULL);
1952 1955          }
1953 1956          return (pip);
1954 1957  }
1955 1958  
1956 1959  /*
1957 1960   * This is a new interface. Check whether any VRRP router is waiting for it
1958 1961   */
1959 1962  static void
1960 1963  vrrpd_reenable_all_vr()
1961 1964  {
1962 1965          vrrp_vr_t *vr;
1963 1966  
1964 1967          vrrp_log(VRRP_DBG0, "vrrpd_reenable_all_vr()");
1965 1968  
1966 1969          TAILQ_FOREACH(vr, &vrrp_vr_list, vvr_next) {
1967 1970                  if (vr->vvr_conf.vvc_enabled)
1968 1971                          (void) vrrpd_enable_vr(vr);
1969 1972          }
1970 1973  }
1971 1974  
1972 1975  /*
1973 1976   * If primary_addr_gone is _B_TRUE, it means that we failed to select
1974 1977   * the primary IP address on this (physical) interface; otherwise,
1975 1978   * it means the interface is no longer available.
1976 1979   */
1977 1980  static void
1978 1981  vrrpd_remove_if(vrrp_intf_t *intf, boolean_t primary_addr_gone)
1979 1982  {
1980 1983          vrrp_vr_t *vr;
1981 1984  
1982 1985          vrrp_log(VRRP_DBG0, "vrrpd_remove_if(%s): %s", intf->vvi_ifname,
1983 1986              primary_addr_gone ? "primary address gone" : "interface deleted");
1984 1987  
1985 1988          TAILQ_FOREACH(vr, &vrrp_vr_list, vvr_next) {
1986 1989                  if (vr->vvr_conf.vvc_enabled)
1987 1990                          vrrpd_disable_vr(vr, intf, primary_addr_gone);
1988 1991          }
1989 1992  }
1990 1993  
1991 1994  /*
1992 1995   * Update the VRRP configuration file based on the given configuration.
1993 1996   * op is either VRRP_CONF_UPDATE or VRRP_CONF_DELETE
1994 1997   */
1995 1998  static vrrp_err_t
1996 1999  vrrpd_updateconf(vrrp_vr_conf_t *newconf, uint_t op)
1997 2000  {
1998 2001          vrrp_vr_conf_t  conf;
1999 2002          FILE            *fp, *nfp;
2000 2003          int             nfd;
2001 2004          char            line[LINE_MAX];
2002 2005          char            newfile[MAXPATHLEN];
2003 2006          boolean_t       found = _B_FALSE;
2004 2007          vrrp_err_t      err = VRRP_SUCCESS;
2005 2008  
2006 2009          vrrp_log(VRRP_DBG0, "vrrpd_updateconf(%s, %s)", newconf->vvc_name,
2007 2010              op == VRRP_CONF_UPDATE ? "update" : "delete");
2008 2011  
2009 2012          if ((fp = fopen(vrrpd_conffile, "r+F")) == NULL) {
2010 2013                  if (errno != ENOENT) {
2011 2014                          vrrp_log(VRRP_ERR, "vrrpd_updateconf(): open %s for "
2012 2015                              "update failed: %s", vrrpd_conffile,
2013 2016                              strerror(errno));
2014 2017                          return (VRRP_EDB);
2015 2018                  }
2016 2019  
2017 2020                  if ((fp = fopen(vrrpd_conffile, "w+F")) == NULL) {
2018 2021                          vrrp_log(VRRP_ERR, "vrrpd_updateconf(): open %s for "
2019 2022                              "write failed: %s", vrrpd_conffile,
2020 2023                              strerror(errno));
2021 2024                          return (VRRP_EDB);
2022 2025                  }
2023 2026          }
2024 2027  
2025 2028          (void) snprintf(newfile, MAXPATHLEN, "%s.new", vrrpd_conffile);
2026 2029          if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
2027 2030              S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
2028 2031                  vrrp_log(VRRP_ERR, "vrrpd_updateconf(): open %s failed: %s",
2029 2032                      newfile, strerror(errno));
2030 2033                  (void) fclose(fp);
2031 2034                  return (VRRP_EDB);
2032 2035          }
2033 2036  
2034 2037          if ((nfp = fdopen(nfd, "wF")) == NULL) {
2035 2038                  vrrp_log(VRRP_ERR, "vrrpd_updateconf(): fdopen(%s) failed: %s",
2036 2039                      newfile, strerror(errno));
2037 2040                  goto done;
2038 2041          }
2039 2042  
2040 2043          while (fgets(line, sizeof (line), fp) != NULL) {
2041 2044                  conf.vvc_vrid = VRRP_VRID_NONE;
2042 2045                  if (!found && (err = vrrpd_read_vrconf(line, &conf)) !=
2043 2046                      VRRP_SUCCESS) {
2044 2047                          vrrp_log(VRRP_ERR, "vrrpd_updateconf(): invalid "
2045 2048                              "configuration format: %s", line);
2046 2049                          goto done;
2047 2050                  }
2048 2051  
2049 2052                  /*
2050 2053                   * Write this line out if:
2051 2054                   * - this is a comment line; or
2052 2055                   * - we've done updating/deleting the the given VR; or
2053 2056                   * - if the name of the VR read from this line does not match
2054 2057                   *   the VR name that we are about to update/delete;
2055 2058                   */
2056 2059                  if (found || conf.vvc_vrid == VRRP_VRID_NONE ||
2057 2060                      strcmp(conf.vvc_name, newconf->vvc_name) != 0) {
2058 2061                          if (fputs(line, nfp) != EOF)
2059 2062                                  continue;
2060 2063  
2061 2064                          vrrp_log(VRRP_ERR, "vrrpd_updateconf(): failed to "
2062 2065                              "write line %s", line);
2063 2066                          err = VRRP_EDB;
2064 2067                          goto done;
2065 2068                  }
2066 2069  
2067 2070                  /*
2068 2071                   * Otherwise, update/skip the line.
2069 2072                   */
2070 2073                  found = _B_TRUE;
2071 2074                  if (op == VRRP_CONF_DELETE)
2072 2075                          continue;
2073 2076  
2074 2077                  assert(op == VRRP_CONF_UPDATE);
2075 2078                  if ((err = vrrpd_write_vrconf(line, sizeof (line),
2076 2079                      newconf)) != VRRP_SUCCESS) {
2077 2080                          vrrp_log(VRRP_ERR, "vrrpd_updateconf(): failed to "
2078 2081                              "update configuration for %s", newconf->vvc_name);
2079 2082                          goto done;
2080 2083                  }
2081 2084                  if (fputs(line, nfp) == EOF) {
2082 2085                          vrrp_log(VRRP_ERR, "vrrpd_updateconf(): failed to "
2083 2086                              "write line %s", line);
2084 2087                          err = VRRP_EDB;
2085 2088                          goto done;
2086 2089                  }
2087 2090          }
2088 2091  
2089 2092          /*
2090 2093           * If we get to the end of the file and have not seen the router that
2091 2094           * we are about to update, write it out.
2092 2095           */
2093 2096          if (!found && op == VRRP_CONF_UPDATE) {
2094 2097                  if ((err = vrrpd_write_vrconf(line, sizeof (line),
2095 2098                      newconf)) == VRRP_SUCCESS && fputs(line, nfp) == EOF) {
2096 2099                          vrrp_log(VRRP_ERR, "vrrpd_updateconf(): failed to "
2097 2100                              "write line %s", line);
2098 2101                          err = VRRP_EDB;
2099 2102                  }
2100 2103          } else if (!found && op == VRRP_CONF_DELETE) {
2101 2104                  vrrp_log(VRRP_ERR, "vrrpd_updateconf(): failed to find "
2102 2105                      "configuation for %s", newconf->vvc_name);
2103 2106                  err = VRRP_ENOTFOUND;
2104 2107          }
2105 2108  
2106 2109          if (err != VRRP_SUCCESS)
2107 2110                  goto done;
2108 2111  
2109 2112          if (fflush(nfp) == EOF || rename(newfile, vrrpd_conffile) < 0) {
2110 2113                  vrrp_log(VRRP_ERR, "vrrpd_updateconf(): failed to "
2111 2114                      "rename file %s", newfile);
2112 2115                  err = VRRP_EDB;
2113 2116          }
2114 2117  
2115 2118  done:
2116 2119          (void) fclose(fp);
2117 2120          (void) fclose(nfp);
2118 2121          (void) unlink(newfile);
2119 2122          return (err);
2120 2123  }
2121 2124  
2122 2125  static vrrp_err_t
2123 2126  vrrpd_write_vrconf(char *line, size_t len, vrrp_vr_conf_t *conf)
2124 2127  {
2125 2128          vrrp_prop_t     *prop;
2126 2129          int             n, i;
2127 2130  
2128 2131          vrrp_log(VRRP_DBG0, "vrrpd_write_vrconf(%s)", conf->vvc_name);
2129 2132  
2130 2133          for (i = 0; i < VRRP_PROP_INFO_TABSIZE; i++) {
2131 2134                  prop = &vrrp_prop_info_tbl[i];
2132 2135                  n = snprintf(line, len, i == 0 ? "%s=" : " %s=",
2133 2136                      prop->vs_propname);
2134 2137                  if (n < 0 || n >= len)
2135 2138                          break;
2136 2139                  len -= n;
2137 2140                  line += n;
2138 2141                  n = prop->vs_propwrite(conf, line, len);
2139 2142                  if (n < 0 || n >= len)
2140 2143                          break;
2141 2144                  len -= n;
2142 2145                  line += n;
2143 2146          }
2144 2147          if (i != VRRP_PROP_INFO_TABSIZE) {
2145 2148                  vrrp_log(VRRP_ERR, "vrrpd_write_vrconf(%s): buffer size too"
2146 2149                      "small", conf->vvc_name);
2147 2150                  return (VRRP_EDB);
2148 2151          }
2149 2152          n = snprintf(line, len, "\n");
2150 2153          if (n < 0 || n >= len) {
2151 2154                  vrrp_log(VRRP_ERR, "vrrpd_write_vrconf(%s): buffer size too"
2152 2155                      "small", conf->vvc_name);
2153 2156                  return (VRRP_EDB);
2154 2157          }
2155 2158          return (VRRP_SUCCESS);
2156 2159  }
2157 2160  
2158 2161  static vrrp_err_t
2159 2162  vrrpd_read_vrconf(char *line, vrrp_vr_conf_t *conf)
2160 2163  {
2161 2164          char            *str, *token;
2162 2165          char            *next;
2163 2166          vrrp_err_t      err = VRRP_SUCCESS;
2164 2167          char            tmpbuf[MAXLINELEN];
2165 2168  
2166 2169          str = tmpbuf;
2167 2170          (void) strlcpy(tmpbuf, line, MAXLINELEN);
2168 2171  
2169 2172          /*
2170 2173           * Skip leading spaces, blank lines, and comments.
2171 2174           */
2172 2175          skip_whitespace(str);
2173 2176          if ((str - tmpbuf == strlen(tmpbuf)) || (*str == '#')) {
2174 2177                  conf->vvc_vrid = VRRP_VRID_NONE;
2175 2178                  return (VRRP_SUCCESS);
2176 2179          }
2177 2180  
2178 2181          /*
2179 2182           * Read each VR properties.
2180 2183           */
2181 2184          for (token = strtok_r(str, " \n\t", &next); token != NULL;
2182 2185              token = strtok_r(NULL, " \n\t", &next)) {
2183 2186                  if ((err = vrrpd_readprop(token, conf)) != VRRP_SUCCESS)
2184 2187                          break;
2185 2188          }
2186 2189  
2187 2190          /* All properties read but no VRID defined */
2188 2191          if (err == VRRP_SUCCESS && conf->vvc_vrid == VRRP_VRID_NONE)
2189 2192                  err = VRRP_EINVAL;
2190 2193  
2191 2194          return (err);
2192 2195  }
2193 2196  
2194 2197  static vrrp_err_t
2195 2198  vrrpd_readprop(const char *str, vrrp_vr_conf_t *conf)
2196 2199  {
2197 2200          vrrp_prop_t     *prop;
2198 2201          char            *pstr;
2199 2202          int             i;
2200 2203  
2201 2204          if ((pstr = strchr(str, '=')) == NULL) {
2202 2205                  vrrp_log(VRRP_ERR, "vrrpd_readprop(%s): invalid property", str);
2203 2206                  return (VRRP_EINVAL);
2204 2207          }
2205 2208  
2206 2209          *pstr++ = '\0';
2207 2210          for (i = 0; i < VRRP_PROP_INFO_TABSIZE; i++) {
2208 2211                  prop = &vrrp_prop_info_tbl[i];
2209 2212                  if (strcasecmp(str, prop->vs_propname) == 0) {
2210 2213                          if (prop->vs_propread(conf, pstr))
2211 2214                                  break;
2212 2215                  }
2213 2216          }
2214 2217  
2215 2218          if (i == VRRP_PROP_INFO_TABSIZE) {
2216 2219                  vrrp_log(VRRP_ERR, "vrrpd_readprop(%s): invalid property", str);
2217 2220                  return (VRRP_EINVAL);
2218 2221          }
2219 2222  
2220 2223          return (VRRP_SUCCESS);
2221 2224  }
2222 2225  
2223 2226  static boolean_t
2224 2227  vrrp_rd_prop_name(vrrp_vr_conf_t *conf, const char *str)
2225 2228  {
2226 2229          size_t size = sizeof (conf->vvc_name);
2227 2230          return (strlcpy(conf->vvc_name, str, size) < size);
2228 2231  }
2229 2232  
2230 2233  static boolean_t
2231 2234  vrrp_rd_prop_vrid(vrrp_vr_conf_t *conf, const char *str)
2232 2235  {
2233 2236          conf->vvc_vrid = strtol(str, NULL, 0);
2234 2237          return (!(conf->vvc_vrid < VRRP_VRID_MIN ||
2235 2238              conf->vvc_vrid > VRRP_VRID_MAX ||
2236 2239              (conf->vvc_vrid == 0 && errno != 0)));
2237 2240  }
2238 2241  
2239 2242  static boolean_t
2240 2243  vrrp_rd_prop_af(vrrp_vr_conf_t *conf, const char *str)
2241 2244  {
2242 2245          if (strcasecmp(str, "AF_INET") == 0)
2243 2246                  conf->vvc_af = AF_INET;
2244 2247          else if (strcasecmp(str, "AF_INET6") == 0)
2245 2248                  conf->vvc_af = AF_INET6;
2246 2249          else
2247 2250                  return (_B_FALSE);
2248 2251          return (_B_TRUE);
2249 2252  }
2250 2253  
2251 2254  static boolean_t
2252 2255  vrrp_rd_prop_pri(vrrp_vr_conf_t *conf, const char *str)
2253 2256  {
2254 2257          conf->vvc_pri = strtol(str, NULL, 0);
2255 2258          return (!(conf->vvc_pri < VRRP_PRI_MIN ||
2256 2259              conf->vvc_pri > VRRP_PRI_OWNER ||
2257 2260              (conf->vvc_pri == 0 && errno != 0)));
2258 2261  }
2259 2262  
2260 2263  static boolean_t
2261 2264  vrrp_rd_prop_adver_int(vrrp_vr_conf_t *conf, const char *str)
2262 2265  {
2263 2266          conf->vvc_adver_int = strtol(str, NULL, 0);
2264 2267          return (!(conf->vvc_adver_int < VRRP_MAX_ADVER_INT_MIN ||
2265 2268              conf->vvc_adver_int > VRRP_MAX_ADVER_INT_MAX ||
2266 2269              (conf->vvc_adver_int == 0 && errno != 0)));
2267 2270  }
2268 2271  
2269 2272  static boolean_t
2270 2273  vrrp_rd_prop_preempt(vrrp_vr_conf_t *conf, const char *str)
2271 2274  {
2272 2275          if (strcasecmp(str, "true") == 0)
2273 2276                  conf->vvc_preempt = _B_TRUE;
2274 2277          else if (strcasecmp(str, "false") == 0)
2275 2278                  conf->vvc_preempt = _B_FALSE;
2276 2279          else
2277 2280                  return (_B_FALSE);
2278 2281          return (_B_TRUE);
2279 2282  }
2280 2283  
2281 2284  static boolean_t
2282 2285  vrrp_rd_prop_accept(vrrp_vr_conf_t *conf, const char *str)
2283 2286  {
2284 2287          if (strcasecmp(str, "true") == 0)
2285 2288                  conf->vvc_accept = _B_TRUE;
2286 2289          else if (strcasecmp(str, "false") == 0)
2287 2290                  conf->vvc_accept = _B_FALSE;
2288 2291          else
2289 2292                  return (_B_FALSE);
2290 2293          return (_B_TRUE);
2291 2294  }
2292 2295  
2293 2296  static boolean_t
2294 2297  vrrp_rd_prop_enabled(vrrp_vr_conf_t *conf, const char *str)
2295 2298  {
2296 2299          if (strcasecmp(str, "enabled") == 0)
2297 2300                  conf->vvc_enabled = _B_TRUE;
2298 2301          else if (strcasecmp(str, "disabled") == 0)
2299 2302                  conf->vvc_enabled = _B_FALSE;
2300 2303          else
2301 2304                  return (_B_FALSE);
2302 2305          return (_B_TRUE);
2303 2306  }
2304 2307  
2305 2308  static boolean_t
2306 2309  vrrp_rd_prop_ifname(vrrp_vr_conf_t *conf, const char *str)
2307 2310  {
2308 2311          size_t size = sizeof (conf->vvc_link);
2309 2312          return (strlcpy(conf->vvc_link, str, size) < size);
2310 2313  }
2311 2314  
2312 2315  static int
2313 2316  vrrp_wt_prop_name(vrrp_vr_conf_t *conf, char *str, size_t size)
2314 2317  {
2315 2318          return (snprintf(str, size, "%s", conf->vvc_name));
2316 2319  }
2317 2320  
2318 2321  static int
2319 2322  vrrp_wt_prop_pri(vrrp_vr_conf_t *conf, char *str, size_t size)
2320 2323  {
2321 2324          return (snprintf(str, size, "%d", conf->vvc_pri));
2322 2325  }
2323 2326  
2324 2327  static int
2325 2328  vrrp_wt_prop_adver_int(vrrp_vr_conf_t *conf, char *str, size_t size)
2326 2329  {
2327 2330          return (snprintf(str, size, "%d", conf->vvc_adver_int));
2328 2331  }
2329 2332  
2330 2333  static int
2331 2334  vrrp_wt_prop_preempt(vrrp_vr_conf_t *conf, char *str, size_t size)
2332 2335  {
2333 2336          return (snprintf(str, size, "%s",
2334 2337              conf->vvc_preempt ? "true" : "false"));
2335 2338  }
2336 2339  
2337 2340  static int
2338 2341  vrrp_wt_prop_accept(vrrp_vr_conf_t *conf, char *str, size_t size)
2339 2342  {
2340 2343          return (snprintf(str, size, "%s",
2341 2344              conf->vvc_accept ? "true" : "false"));
2342 2345  }
2343 2346  
2344 2347  static int
2345 2348  vrrp_wt_prop_enabled(vrrp_vr_conf_t *conf, char *str, size_t size)
2346 2349  {
2347 2350          return (snprintf(str, size, "%s",
2348 2351              conf->vvc_enabled ? "enabled" : "disabled"));
2349 2352  }
2350 2353  
2351 2354  static int
2352 2355  vrrp_wt_prop_vrid(vrrp_vr_conf_t *conf, char *str, size_t size)
2353 2356  {
2354 2357          return (snprintf(str, size, "%d", conf->vvc_vrid));
2355 2358  }
2356 2359  
2357 2360  static int
2358 2361  vrrp_wt_prop_af(vrrp_vr_conf_t *conf, char *str, size_t size)
2359 2362  {
2360 2363          return (snprintf(str, size, "%s",
2361 2364              conf->vvc_af == AF_INET ? "AF_INET" : "AF_INET6"));
2362 2365  }
2363 2366  
2364 2367  static int
2365 2368  vrrp_wt_prop_ifname(vrrp_vr_conf_t *conf, char *str, size_t size)
2366 2369  {
2367 2370          return (snprintf(str, size, "%s", conf->vvc_link));
2368 2371  }
2369 2372  
2370 2373  static char *
2371 2374  af_str(int af)
2372 2375  {
2373 2376          if (af == 4 || af == AF_INET)
2374 2377                  return ("AF_INET");
2375 2378          else if (af == 6 || af == AF_INET6)
2376 2379                  return ("AF_INET6");
2377 2380          else if (af == AF_UNSPEC)
2378 2381                  return ("AF_UNSPEC");
2379 2382          else
2380 2383                  return ("AF_error");
2381 2384  }
2382 2385  
2383 2386  static vrrp_err_t
2384 2387  vrrpd_create_vr(vrrp_vr_conf_t *conf)
2385 2388  {
2386 2389          vrrp_vr_t       *vr;
2387 2390  
2388 2391          vrrp_log(VRRP_DBG0, "vrrpd_create_vr(%s)", conf->vvc_name);
2389 2392  
2390 2393          if ((vr = malloc(sizeof (vrrp_vr_t))) == NULL) {
2391 2394                  vrrp_log(VRRP_ERR, "vrrpd_create_vr(): memory allocation for %s"
2392 2395                      " failed", conf->vvc_name);
2393 2396                  return (VRRP_ENOMEM);
2394 2397          }
2395 2398  
2396 2399          bzero(vr, sizeof (vrrp_vr_t));
2397 2400          vr->vvr_state = VRRP_STATE_NONE;
2398 2401          vr->vvr_timer_id = -1;
2399 2402          vrrpd_state_trans(VRRP_STATE_NONE, VRRP_STATE_INIT, vr);
2400 2403          (void) memcpy(&vr->vvr_conf, conf, sizeof (vrrp_vr_conf_t));
2401 2404          vr->vvr_conf.vvc_enabled = _B_FALSE;
2402 2405          TAILQ_INSERT_HEAD(&vrrp_vr_list, vr, vvr_next);
2403 2406          return (VRRP_SUCCESS);
2404 2407  }
2405 2408  
2406 2409  static void
2407 2410  vrrpd_delete_vr(vrrp_vr_t *vr)
2408 2411  {
2409 2412          vrrp_log(VRRP_DBG0, "vrrpd_delete_vr(%s)", vr->vvr_conf.vvc_name);
2410 2413          if (vr->vvr_conf.vvc_enabled)
2411 2414                  vrrpd_disable_vr(vr, NULL, _B_FALSE);
2412 2415          assert(vr->vvr_state == VRRP_STATE_INIT);
2413 2416          vrrpd_state_trans(VRRP_STATE_INIT, VRRP_STATE_NONE, vr);
2414 2417          TAILQ_REMOVE(&vrrp_vr_list, vr, vvr_next);
2415 2418          (void) free(vr);
2416 2419  }
2417 2420  
2418 2421  static vrrp_err_t
2419 2422  vrrpd_enable_vr(vrrp_vr_t *vr)
2420 2423  {
2421 2424          vrrp_err_t      rx_err, tx_err, err = VRRP_EINVAL;
2422 2425  
2423 2426          vrrp_log(VRRP_DBG0, "vrrpd_enable_vr(%s)", vr->vvr_conf.vvc_name);
2424 2427  
2425 2428          assert(vr->vvr_conf.vvc_enabled);
2426 2429  
2427 2430          /*
2428 2431           * This VRRP router has been successfully enabled and start
2429 2432           * participating.
2430 2433           */
2431 2434          if (vr->vvr_state != VRRP_STATE_INIT)
2432 2435                  return (VRRP_SUCCESS);
2433 2436  
2434 2437          if ((rx_err = vrrpd_init_rxsock(vr)) == VRRP_SUCCESS) {
2435 2438                  /*
2436 2439                   * Select the primary IP address. Even if this time
2437 2440                   * primary IP selection failed, we will reselect the
2438 2441                   * primary IP address when new IP address comes up.
2439 2442                   */
2440 2443                  vrrpd_reselect_primary(vr->vvr_pif);
2441 2444                  if (vr->vvr_pif->vvi_pip == NULL) {
2442 2445                          vrrp_log(VRRP_DBG0, "vrrpd_enable_vr(%s): "
2443 2446                              "select_primary over %s failed",
2444 2447                              vr->vvr_conf.vvc_name, vr->vvr_pif->vvi_ifname);
2445 2448                          rx_err = VRRP_ENOPRIM;
2446 2449                  }
2447 2450          }
2448 2451  
2449 2452          /*
2450 2453           * Initialize the TX socket used for this vrrp_vr_t to send the
2451 2454           * multicast packets.
2452 2455           */
2453 2456          tx_err = vrrpd_init_txsock(vr);
2454 2457  
2455 2458          /*
2456 2459           * Only start the state transition if sockets for both RX and TX are
2457 2460           * initialized correctly.
2458 2461           */
2459 2462          if (rx_err != VRRP_SUCCESS || tx_err != VRRP_SUCCESS) {
2460 2463                  /*
2461 2464                   * Record the error information for diagnose purpose.
2462 2465                   */
2463 2466                  vr->vvr_err = (rx_err == VRRP_SUCCESS) ? tx_err : rx_err;
2464 2467                  return (err);
2465 2468          }
2466 2469  
2467 2470          if (vr->vvr_conf.vvc_pri == 255)
2468 2471                  err = vrrpd_state_i2m(vr);
2469 2472          else
2470 2473                  err = vrrpd_state_i2b(vr);
2471 2474  
2472 2475          if (err != VRRP_SUCCESS) {
2473 2476                  vr->vvr_err = err;
2474 2477                  vr->vvr_pif->vvi_pip = NULL;
2475 2478                  vrrpd_fini_txsock(vr);
2476 2479                  vrrpd_fini_rxsock(vr);
2477 2480          }
2478 2481          return (err);
2479 2482  }
2480 2483  
2481 2484  /*
2482 2485   * Given the removed interface, see whether the given VRRP router would
2483 2486   * be affected and stop participating the VRRP protocol.
2484 2487   *
2485 2488   * If intf is NULL, VR disabling request is coming from the admin.
2486 2489   */
2487 2490  static void
2488 2491  vrrpd_disable_vr(vrrp_vr_t *vr, vrrp_intf_t *intf, boolean_t primary_addr_gone)
2489 2492  {
2490 2493          vrrp_log(VRRP_DBG0, "vrrpd_disable_vr(%s): %s%s", vr->vvr_conf.vvc_name,
2491 2494              intf == NULL ? "requested by admin" : intf->vvi_ifname,
2492 2495              intf == NULL ? "" : (primary_addr_gone ? "primary address gone" :
2493 2496              "interface deleted"));
2494 2497  
2495 2498          /*
2496 2499           * An interface is deleted, see whether this interface is the
2497 2500           * physical interface or the VNIC of the given VRRP router.
2498 2501           * If so, continue to disable the VRRP router.
2499 2502           */
2500 2503          if (!primary_addr_gone && (intf != NULL) && (intf != vr->vvr_pif) &&
2501 2504              (intf != vr->vvr_vif)) {
2502 2505                  return;
2503 2506          }
2504 2507  
2505 2508          /*
2506 2509           * If this is the case that the primary IP address is gone,
2507 2510           * and we failed to reselect another primary IP address,
2508 2511           * continue to disable the VRRP router.
2509 2512           */
2510 2513          if (primary_addr_gone && intf != vr->vvr_pif)
2511 2514                  return;
2512 2515  
2513 2516          vrrp_log(VRRP_DBG1, "vrrpd_disable_vr(%s): disabling",
2514 2517              vr->vvr_conf.vvc_name);
2515 2518  
2516 2519          if (vr->vvr_state == VRRP_STATE_MASTER) {
2517 2520                  /*
2518 2521                   * If this router is disabled by the administrator, send
2519 2522                   * the zero-priority advertisement to indicate the Master
2520 2523                   * stops participating VRRP.
2521 2524                   */
2522 2525                  if (intf == NULL)
2523 2526                          (void) vrrpd_send_adv(vr, _B_TRUE);
2524 2527  
2525 2528                  vrrpd_state_m2i(vr);
2526 2529          } else  if (vr->vvr_state == VRRP_STATE_BACKUP) {
2527 2530                  vrrpd_state_b2i(vr);
2528 2531          }
2529 2532  
2530 2533          /*
2531 2534           * If no primary IP address can be selected, the VRRP router
2532 2535           * stays at the INIT state and will become BACKUP and MASTER when
2533 2536           * a primary IP address is reselected.
2534 2537           */
2535 2538          if (primary_addr_gone) {
2536 2539                  vrrp_log(VRRP_DBG1, "vrrpd_disable_vr(%s): primary IP "
2537 2540                      "is removed", vr->vvr_conf.vvc_name);
2538 2541                  vr->vvr_err = VRRP_ENOPRIM;
2539 2542          } else if (intf == NULL) {
2540 2543                  /*
2541 2544                   * The VRRP router is disable by the administrator
2542 2545                   */
2543 2546                  vrrp_log(VRRP_DBG1, "vrrpd_disable_vr(%s): disabled by admin",
2544 2547                      vr->vvr_conf.vvc_name);
2545 2548                  vr->vvr_err = VRRP_SUCCESS;
2546 2549                  vrrpd_fini_txsock(vr);
2547 2550                  vrrpd_fini_rxsock(vr);
2548 2551          } else if (intf == vr->vvr_pif) {
2549 2552                  vrrp_log(VRRP_DBG1, "vrrpd_disable_vr(%s): physical interface "
2550 2553                      "%s removed", vr->vvr_conf.vvc_name, intf->vvi_ifname);
2551 2554                  vr->vvr_err = VRRP_ENOPRIM;
2552 2555                  vrrpd_fini_rxsock(vr);
2553 2556          } else if (intf == vr->vvr_vif) {
2554 2557                  vrrp_log(VRRP_DBG1, "vrrpd_disable_vr(%s): VNIC interface %s"
2555 2558                      " removed", vr->vvr_conf.vvc_name, intf->vvi_ifname);
2556 2559                  vr->vvr_err = VRRP_ENOVIRT;
2557 2560                  vrrpd_fini_txsock(vr);
2558 2561          }
2559 2562  }
2560 2563  
2561 2564  vrrp_err_t
2562 2565  vrrpd_create(vrrp_vr_conf_t *conf, boolean_t updateconf)
2563 2566  {
2564 2567          vrrp_err_t      err = VRRP_SUCCESS;
2565 2568  
2566 2569          vrrp_log(VRRP_DBG0, "vrrpd_create(%s, %s, %d)", conf->vvc_name,
2567 2570              conf->vvc_link, conf->vvc_vrid);
2568 2571  
2569 2572          assert(conf != NULL);
2570 2573  
2571 2574          /*
2572 2575           * Sanity check
2573 2576           */
2574 2577          if ((strlen(conf->vvc_name) == 0) ||
2575 2578              (strlen(conf->vvc_link) == 0) ||
2576 2579              (conf->vvc_vrid < VRRP_VRID_MIN ||
2577 2580              conf->vvc_vrid > VRRP_VRID_MAX) ||
2578 2581              (conf->vvc_pri < VRRP_PRI_MIN ||
2579 2582              conf->vvc_pri > VRRP_PRI_OWNER) ||
2580 2583              (conf->vvc_adver_int < VRRP_MAX_ADVER_INT_MIN ||
2581 2584              conf->vvc_adver_int > VRRP_MAX_ADVER_INT_MAX) ||
2582 2585              (conf->vvc_af != AF_INET && conf->vvc_af != AF_INET6) ||
2583 2586              (conf->vvc_pri == VRRP_PRI_OWNER && !conf->vvc_accept)) {
2584 2587                  vrrp_log(VRRP_DBG1, "vrrpd_create(%s): invalid argument",
2585 2588                      conf->vvc_name);
2586 2589                  return (VRRP_EINVAL);
2587 2590          }
2588 2591  
2589 2592          if (!vrrp_valid_name(conf->vvc_name)) {
2590 2593                  vrrp_log(VRRP_DBG1, "vrrpd_create(): %s is not a valid router "
2591 2594                      "name", conf->vvc_name);
2592 2595                  return (VRRP_EINVALVRNAME);
2593 2596          }
2594 2597  
2595 2598          if (vrrpd_lookup_vr_by_name(conf->vvc_name) != NULL) {
2596 2599                  vrrp_log(VRRP_DBG1, "vrrpd_create(): %s already exists",
2597 2600                      conf->vvc_name);
2598 2601                  return (VRRP_EINSTEXIST);
2599 2602          }
2600 2603  
2601 2604          if (vrrpd_lookup_vr_by_vrid(conf->vvc_link, conf->vvc_vrid,
2602 2605              conf->vvc_af) != NULL) {
2603 2606                  vrrp_log(VRRP_DBG1, "vrrpd_create(): VRID %d/%s over %s "
2604 2607                      "already exists", conf->vvc_vrid, af_str(conf->vvc_af),
2605 2608                      conf->vvc_link);
2606 2609                  return (VRRP_EVREXIST);
2607 2610          }
2608 2611  
2609 2612          if (updateconf && (err = vrrpd_updateconf(conf,
2610 2613              VRRP_CONF_UPDATE)) != VRRP_SUCCESS) {
2611 2614                  vrrp_log(VRRP_ERR, "vrrpd_create(): failed to update "
2612 2615                      "configuration for %s", conf->vvc_name);
2613 2616                  return (err);
2614 2617          }
2615 2618  
2616 2619          err = vrrpd_create_vr(conf);
2617 2620          if (err != VRRP_SUCCESS && updateconf)
2618 2621                  (void) vrrpd_updateconf(conf, VRRP_CONF_DELETE);
2619 2622  
2620 2623          return (err);
2621 2624  }
2622 2625  
2623 2626  static vrrp_err_t
2624 2627  vrrpd_delete(const char *vn)
2625 2628  {
2626 2629          vrrp_vr_t       *vr;
2627 2630          vrrp_err_t      err;
2628 2631  
2629 2632          vrrp_log(VRRP_DBG0, "vrrpd_delete(%s)", vn);
2630 2633  
2631 2634          if ((vr = vrrpd_lookup_vr_by_name(vn)) == NULL) {
2632 2635                  vrrp_log(VRRP_DBG1, "vrrpd_delete(): %s not exists", vn);
2633 2636                  return (VRRP_ENOTFOUND);
2634 2637          }
2635 2638  
2636 2639          err = vrrpd_updateconf(&vr->vvr_conf, VRRP_CONF_DELETE);
2637 2640          if (err != VRRP_SUCCESS) {
2638 2641                  vrrp_log(VRRP_ERR, "vrrpd_delete(): failed to delete "
2639 2642                      "configuration for %s", vr->vvr_conf.vvc_name);
2640 2643                  return (err);
2641 2644          }
2642 2645  
2643 2646          vrrpd_delete_vr(vr);
2644 2647          return (VRRP_SUCCESS);
2645 2648  }
2646 2649  
2647 2650  static vrrp_err_t
2648 2651  vrrpd_enable(const char *vn, boolean_t updateconf)
2649 2652  {
2650 2653          vrrp_vr_t               *vr;
2651 2654          vrrp_vr_conf_t          *conf;
2652 2655          uint32_t                flags;
2653 2656          datalink_class_t        class;
2654 2657          vrrp_err_t              err = VRRP_SUCCESS;
2655 2658  
2656 2659          vrrp_log(VRRP_DBG0, "vrrpd_enable(%s)", vn);
2657 2660  
2658 2661          if ((vr = vrrpd_lookup_vr_by_name(vn)) == NULL) {
2659 2662                  vrrp_log(VRRP_DBG1, "vrrpd_enable(): %s does not exist", vn);
2660 2663                  return (VRRP_ENOTFOUND);
2661 2664          }
2662 2665  
2663 2666          /*
2664 2667           * The VR is already enabled.
2665 2668           */
2666 2669          conf = &vr->vvr_conf;
2667 2670          if (conf->vvc_enabled) {
2668 2671                  vrrp_log(VRRP_DBG1, "vrrpd_enable(): %s is already "
2669 2672                      "enabled", vn);
2670 2673                  return (VRRP_EALREADY);
2671 2674          }
2672 2675  
2673 2676          /*
2674 2677           * Check whether the link exists.
2675 2678           */
2676 2679          if ((strlen(conf->vvc_link) == 0) || dladm_name2info(vrrpd_vh->vh_dh,
2677 2680              conf->vvc_link, NULL, &flags, &class, NULL) != DLADM_STATUS_OK ||
2678 2681              !(flags & DLADM_OPT_ACTIVE) || ((class != DATALINK_CLASS_PHYS) &&
2679 2682              (class != DATALINK_CLASS_VLAN) && (class != DATALINK_CLASS_AGGR) &&
2680 2683              (class != DATALINK_CLASS_VNIC))) {
2681 2684                  vrrp_log(VRRP_DBG1, "vrrpd_enable(%s): invalid link %s",
2682 2685                      vn, conf->vvc_link);
2683 2686                  return (VRRP_EINVALLINK);
2684 2687          }
2685 2688  
2686 2689          /*
2687 2690           * Get the associated VNIC name by the given interface/vrid/
2688 2691           * address famitly.
2689 2692           */
2690 2693          err = vrrp_get_vnicname(vrrpd_vh, conf->vvc_vrid,
2691 2694              conf->vvc_af, conf->vvc_link, NULL, NULL, vr->vvr_vnic,
2692 2695              sizeof (vr->vvr_vnic));
2693 2696          if (err != VRRP_SUCCESS) {
2694 2697                  vrrp_log(VRRP_DBG1, "vrrpd_enable(%s): no VNIC for VRID %d/%s "
2695 2698                      "over %s", vn, conf->vvc_vrid, af_str(conf->vvc_af),
2696 2699                      conf->vvc_link);
2697 2700                  err = VRRP_ENOVNIC;
2698 2701                  goto fail;
2699 2702          }
2700 2703  
2701 2704          /*
2702 2705           * Find the right VNIC, primary interface and get the list of the
2703 2706           * protected IP adressses and primary IP address. Note that if
2704 2707           * either interface is NULL (no IP addresses configured over the
2705 2708           * interface), we will still continue and mark this VRRP router
2706 2709           * as "enabled".
2707 2710           */
2708 2711          vr->vvr_conf.vvc_enabled = _B_TRUE;
2709 2712          if (updateconf && (err = vrrpd_updateconf(&vr->vvr_conf,
2710 2713              VRRP_CONF_UPDATE)) != VRRP_SUCCESS) {
2711 2714                  vrrp_log(VRRP_ERR, "vrrpd_enable(): failed to update "
2712 2715                      "configuration for %s", vr->vvr_conf.vvc_name);
2713 2716                  goto fail;
2714 2717          }
2715 2718  
2716 2719          /*
2717 2720           * If vrrpd_setup_vr() fails, it is possible that there is no IP
2718 2721           * addresses over ether the primary interface or the VNIC yet,
2719 2722           * return success in this case, the VRRP router will stay in
2720 2723           * the initialized state and start to work when the IP address is
2721 2724           * configured.
2722 2725           */
2723 2726          (void) vrrpd_enable_vr(vr);
2724 2727          return (VRRP_SUCCESS);
2725 2728  
2726 2729  fail:
2727 2730          vr->vvr_conf.vvc_enabled = _B_FALSE;
2728 2731          vr->vvr_vnic[0] = '\0';
2729 2732          return (err);
2730 2733  }
2731 2734  
2732 2735  static vrrp_err_t
2733 2736  vrrpd_disable(const char *vn)
2734 2737  {
2735 2738          vrrp_vr_t       *vr;
2736 2739          vrrp_err_t      err;
2737 2740  
2738 2741          vrrp_log(VRRP_DBG0, "vrrpd_disable(%s)", vn);
2739 2742  
2740 2743          if ((vr = vrrpd_lookup_vr_by_name(vn)) == NULL) {
2741 2744                  vrrp_log(VRRP_DBG1, "vrrpd_disable(): %s does not exist", vn);
2742 2745                  return (VRRP_ENOTFOUND);
2743 2746          }
2744 2747  
2745 2748          /*
2746 2749           * The VR is already disable.
2747 2750           */
2748 2751          if (!vr->vvr_conf.vvc_enabled) {
2749 2752                  vrrp_log(VRRP_DBG1, "vrrpd_disable(): %s was not enabled", vn);
2750 2753                  return (VRRP_EALREADY);
2751 2754          }
2752 2755  
2753 2756          vr->vvr_conf.vvc_enabled = _B_FALSE;
2754 2757          err = vrrpd_updateconf(&vr->vvr_conf, VRRP_CONF_UPDATE);
2755 2758          if (err != VRRP_SUCCESS) {
2756 2759                  vr->vvr_conf.vvc_enabled = _B_TRUE;
2757 2760                  vrrp_log(VRRP_ERR, "vrrpd_disable(): failed to update "
2758 2761                      "configuration for %s", vr->vvr_conf.vvc_name);
2759 2762                  return (err);
2760 2763          }
2761 2764  
2762 2765          vrrpd_disable_vr(vr, NULL, _B_FALSE);
2763 2766          vr->vvr_vnic[0] = '\0';
2764 2767          return (VRRP_SUCCESS);
2765 2768  }
2766 2769  
2767 2770  static vrrp_err_t
2768 2771  vrrpd_modify(vrrp_vr_conf_t *conf, uint32_t mask)
2769 2772  {
2770 2773          vrrp_vr_t       *vr;
2771 2774          vrrp_vr_conf_t  savconf;
2772 2775          int             pri;
2773 2776          boolean_t       accept, set_accept = _B_FALSE;
2774 2777          vrrp_err_t      err;
2775 2778  
2776 2779          vrrp_log(VRRP_DBG0, "vrrpd_modify(%s)", conf->vvc_name);
2777 2780  
2778 2781          if (mask == 0)
2779 2782                  return (VRRP_SUCCESS);
2780 2783  
2781 2784          if ((vr = vrrpd_lookup_vr_by_name(conf->vvc_name)) == NULL) {
2782 2785                  vrrp_log(VRRP_DBG1, "vrrpd_modify(): cannot find the given "
2783 2786                      "VR instance: %s", conf->vvc_name);
2784 2787                  return (VRRP_ENOTFOUND);
2785 2788          }
2786 2789  
2787 2790          if (mask & VRRP_CONF_INTERVAL) {
2788 2791                  if (conf->vvc_adver_int < VRRP_MAX_ADVER_INT_MIN ||
2789 2792                      conf->vvc_adver_int > VRRP_MAX_ADVER_INT_MAX) {
2790 2793                          vrrp_log(VRRP_DBG1, "vrrpd_modify(%s): invalid "
2791 2794                              "adver_interval %d", conf->vvc_name,
2792 2795                              conf->vvc_adver_int);
2793 2796                          return (VRRP_EINVAL);
2794 2797                  }
2795 2798          }
2796 2799  
2797 2800          pri = vr->vvr_conf.vvc_pri;
2798 2801          if (mask & VRRP_CONF_PRIORITY) {
2799 2802                  if (conf->vvc_pri < VRRP_PRI_MIN ||
2800 2803                      conf->vvc_pri > VRRP_PRI_OWNER) {
2801 2804                          vrrp_log(VRRP_DBG1, "vrrpd_modify(%s): invalid "
2802 2805                              "priority %d", conf->vvc_name, conf->vvc_pri);
2803 2806                          return (VRRP_EINVAL);
2804 2807                  }
2805 2808                  pri = conf->vvc_pri;
2806 2809          }
2807 2810  
2808 2811          accept = vr->vvr_conf.vvc_accept;
2809 2812          if (mask & VRRP_CONF_ACCEPT)
2810 2813                  accept = conf->vvc_accept;
2811 2814  
2812 2815          if (pri == VRRP_PRI_OWNER && !accept) {
2813 2816                  vrrp_log(VRRP_DBG1, "vrrpd_modify(%s): accept mode must be "
2814 2817                      "true for VRRP address owner", conf->vvc_name);
2815 2818                  return (VRRP_EINVAL);
2816 2819          }
2817 2820  
2818 2821          if ((mask & VRRP_CONF_ACCEPT) && (vr->vvr_conf.vvc_accept != accept)) {
2819 2822                  err = vrrpd_set_noaccept(vr, !accept);
2820 2823                  if (err != VRRP_SUCCESS) {
2821 2824                          vrrp_log(VRRP_ERR, "vrrpd_modify(%s): access mode "
2822 2825                              "updating failed: %s", conf->vvc_name,
2823 2826                              vrrp_err2str(err));
2824 2827                          return (err);
2825 2828                  }
2826 2829                  set_accept = _B_TRUE;
2827 2830          }
2828 2831  
2829 2832          /*
2830 2833           * Save the current configuration, so it can be restored if the
2831 2834           * following fails.
2832 2835           */
2833 2836          (void) memcpy(&savconf, &vr->vvr_conf, sizeof (vrrp_vr_conf_t));
2834 2837          if (mask & VRRP_CONF_PREEMPT)
2835 2838                  vr->vvr_conf.vvc_preempt = conf->vvc_preempt;
2836 2839  
2837 2840          if (mask & VRRP_CONF_ACCEPT)
2838 2841                  vr->vvr_conf.vvc_accept = accept;
2839 2842  
2840 2843          if (mask & VRRP_CONF_PRIORITY)
2841 2844                  vr->vvr_conf.vvc_pri = pri;
2842 2845  
2843 2846          if (mask & VRRP_CONF_INTERVAL)
2844 2847                  vr->vvr_conf.vvc_adver_int = conf->vvc_adver_int;
2845 2848  
2846 2849          err = vrrpd_updateconf(&vr->vvr_conf, VRRP_CONF_UPDATE);
2847 2850          if (err != VRRP_SUCCESS) {
2848 2851                  vrrp_log(VRRP_ERR, "vrrpd_modify(%s): configuration update "
2849 2852                      "failed: %s", conf->vvc_name, vrrp_err2str(err));
2850 2853                  if (set_accept)
2851 2854                          (void) vrrpd_set_noaccept(vr, accept);
2852 2855                  (void) memcpy(&vr->vvr_conf, &savconf, sizeof (vrrp_vr_conf_t));
2853 2856                  return (err);
2854 2857          }
2855 2858  
2856 2859          if ((mask & VRRP_CONF_PRIORITY) && (vr->vvr_state == VRRP_STATE_BACKUP))
2857 2860                  vr->vvr_timeout = MASTER_DOWN_INTERVAL_VR(vr);
2858 2861  
2859 2862          if ((mask & VRRP_CONF_INTERVAL) && (vr->vvr_state == VRRP_STATE_MASTER))
2860 2863                  vr->vvr_timeout = conf->vvc_adver_int;
2861 2864  
2862 2865          return (VRRP_SUCCESS);
2863 2866  }
2864 2867  
2865 2868  static void
2866 2869  vrrpd_list(vrid_t vrid, char *ifname, int af, vrrp_ret_list_t *ret,
2867 2870      size_t *sizep)
2868 2871  {
2869 2872          vrrp_vr_t       *vr;
2870 2873          char            *p = (char *)ret + sizeof (vrrp_ret_list_t);
2871 2874          size_t          size = (*sizep) - sizeof (vrrp_ret_list_t);
2872 2875  
2873 2876          vrrp_log(VRRP_DBG0, "vrrpd_list(%d_%s_%s)", vrid, ifname, af_str(af));
2874 2877  
2875 2878          ret->vrl_cnt = 0;
2876 2879          TAILQ_FOREACH(vr, &vrrp_vr_list, vvr_next) {
2877 2880                  if (vrid !=  VRRP_VRID_NONE && vr->vvr_conf.vvc_vrid != vrid)
2878 2881                          continue;
2879 2882  
2880 2883                  if (strlen(ifname) != 0 && strcmp(ifname,
2881 2884                      vr->vvr_conf.vvc_link) == 0) {
2882 2885                          continue;
2883 2886                  }
2884 2887  
2885 2888                  if ((af == AF_INET || af == AF_INET6) &&
2886 2889                      vr->vvr_conf.vvc_af != af)
2887 2890                          continue;
2888 2891  
2889 2892                  if (size < VRRP_NAME_MAX) {
2890 2893                          vrrp_log(VRRP_DBG1, "vrrpd_list(): buffer size too "
2891 2894                              "small to hold %d router names", ret->vrl_cnt);
2892 2895                          *sizep = sizeof (vrrp_ret_list_t);
2893 2896                          ret->vrl_err = VRRP_ETOOSMALL;
2894 2897                          return;
2895 2898                  }
2896 2899                  (void) strlcpy(p, vr->vvr_conf.vvc_name, VRRP_NAME_MAX);
2897 2900                  p += (strlen(vr->vvr_conf.vvc_name) + 1);
2898 2901                  ret->vrl_cnt++;
2899 2902                  size -= VRRP_NAME_MAX;
2900 2903          }
2901 2904  
2902 2905          *sizep = sizeof (vrrp_ret_list_t) + ret->vrl_cnt * VRRP_NAME_MAX;
2903 2906          vrrp_log(VRRP_DBG1, "vrrpd_list() return %d", ret->vrl_cnt);
2904 2907          ret->vrl_err = VRRP_SUCCESS;
2905 2908  }
2906 2909  
2907 2910  static void
2908 2911  vrrpd_query(const char *vn, vrrp_ret_query_t *ret, size_t *sizep)
2909 2912  {
2910 2913          vrrp_queryinfo_t        *infop;
2911 2914          vrrp_vr_t               *vr;
2912 2915          vrrp_intf_t             *vif;
2913 2916          vrrp_ip_t               *ip;
2914 2917          struct timeval          now;
2915 2918          uint32_t                vipcnt = 0;
2916 2919          size_t                  size = *sizep;
2917 2920  
2918 2921          vrrp_log(VRRP_DBG1, "vrrpd_query(%s)", vn);
2919 2922  
2920 2923          if ((vr = vrrpd_lookup_vr_by_name(vn)) == NULL) {
2921 2924                  vrrp_log(VRRP_DBG1, "vrrpd_query(): %s does not exist", vn);
2922 2925                  *sizep = sizeof (vrrp_ret_query_t);
2923 2926                  ret->vrq_err = VRRP_ENOTFOUND;
2924 2927                  return;
2925 2928          }
2926 2929  
2927 2930          /*
2928 2931           * Get the virtual IP list if the router is not in the INIT state.
2929 2932           */
2930 2933          if (vr->vvr_state != VRRP_STATE_INIT) {
2931 2934                  vif = vr->vvr_vif;
2932 2935                  TAILQ_FOREACH(ip, &vif->vvi_iplist, vip_next) {
2933 2936                          vipcnt++;
2934 2937                  }
2935 2938          }
2936 2939  
2937 2940          *sizep = sizeof (vrrp_ret_query_t);
2938 2941          *sizep += (vipcnt == 0) ? 0 : (vipcnt - 1) * sizeof (vrrp_addr_t);
2939 2942          if (*sizep > size) {
2940 2943                  vrrp_log(VRRP_ERR, "vrrpd_query(): not enough space to hold "
2941 2944                      "%d virtual IPs", vipcnt);
2942 2945                  *sizep = sizeof (vrrp_ret_query_t);
2943 2946                  ret->vrq_err = VRRP_ETOOSMALL;
2944 2947                  return;
2945 2948          }
2946 2949  
2947 2950          (void) gettimeofday(&now, NULL);
2948 2951  
2949 2952          bzero(ret, *sizep);
2950 2953          infop = &ret->vrq_qinfo;
2951 2954          (void) memcpy(&infop->show_vi,
2952 2955              &(vr->vvr_conf), sizeof (vrrp_vr_conf_t));
2953 2956          (void) memcpy(&infop->show_vs,
2954 2957              &(vr->vvr_sinfo), sizeof (vrrp_stateinfo_t));
2955 2958          (void) strlcpy(infop->show_va.va_vnic, vr->vvr_vnic, MAXLINKNAMELEN);
2956 2959          infop->show_vt.vt_since_last_tran = timeval_to_milli(
2957 2960              timeval_delta(now, vr->vvr_sinfo.vs_st_time));
2958 2961  
2959 2962          if (vr->vvr_state == VRRP_STATE_INIT) {
2960 2963                  ret->vrq_err = VRRP_SUCCESS;
2961 2964                  return;
2962 2965          }
2963 2966  
2964 2967          vipcnt = 0;
2965 2968          TAILQ_FOREACH(ip, &vif->vvi_iplist, vip_next) {
2966 2969                  (void) memcpy(&infop->show_va.va_vips[vipcnt++],
2967 2970                      &ip->vip_addr, sizeof (vrrp_addr_t));
2968 2971          }
2969 2972          infop->show_va.va_vipcnt = vipcnt;
2970 2973  
2971 2974          (void) memcpy(&infop->show_va.va_primary,
2972 2975              &vr->vvr_pif->vvi_pip->vip_addr, sizeof (vrrp_addr_t));
2973 2976  
2974 2977          (void) memcpy(&infop->show_vp, &(vr->vvr_peer), sizeof (vrrp_peer_t));
2975 2978  
2976 2979          /*
2977 2980           * Check whether there is a peer.
2978 2981           */
2979 2982          if (!VRRPADDR_UNSPECIFIED(vr->vvr_conf.vvc_af,
2980 2983              &(vr->vvr_peer.vp_addr))) {
2981 2984                  infop->show_vt.vt_since_last_adv = timeval_to_milli(
2982 2985                      timeval_delta(now, vr->vvr_peer.vp_time));
2983 2986          }
2984 2987  
2985 2988          if (vr->vvr_state == VRRP_STATE_BACKUP) {
2986 2989                  infop->show_vt.vt_master_down_intv =
2987 2990                      MASTER_DOWN_INTERVAL_VR(vr);
2988 2991          }
2989 2992  
2990 2993          ret->vrq_err = VRRP_SUCCESS;
2991 2994  }
2992 2995  
2993 2996  /*
2994 2997   * Build the VRRP packet (not including the IP header). Return the
2995 2998   * payload length.
2996 2999   *
2997 3000   * If zero_pri is set to be B_TRUE, then this is the specical zero-priority
2998 3001   * advertisement which is sent by the Master to indicate that it has been
2999 3002   * stopped participating in VRRP.
3000 3003   */
3001 3004  static size_t
3002 3005  vrrpd_build_vrrp(vrrp_vr_t *vr, uchar_t *buf, int buflen, boolean_t zero_pri)
3003 3006  {
3004 3007          /* LINTED E_BAD_PTR_CAST_ALIGN */
3005 3008          vrrp_pkt_t      *vp = (vrrp_pkt_t *)buf;
3006 3009          /* LINTED E_BAD_PTR_CAST_ALIGN */
3007 3010          struct in_addr  *a4 = (struct in_addr *)(vp + 1);
3008 3011          /* LINTED E_BAD_PTR_CAST_ALIGN */
3009 3012          struct in6_addr *a6 = (struct in6_addr *)(vp + 1);
3010 3013          vrrp_intf_t     *vif = vr->vvr_vif;
3011 3014          vrrp_ip_t       *vip;
3012 3015          int             af = vif->vvi_af;
3013 3016          size_t          size = sizeof (vrrp_pkt_t);
3014 3017          uint16_t        rsvd_adver_int;
3015 3018          int             nip = 0;
3016 3019  
3017 3020          vrrp_log(VRRP_DBG1, "vrrpd_build_vrrp(%s, %s_priority): intv %d",
3018 3021              vr->vvr_conf.vvc_name, zero_pri ? "zero" : "non-zero",
3019 3022              vr->vvr_conf.vvc_adver_int);
3020 3023  
3021 3024          TAILQ_FOREACH(vip, &vif->vvi_iplist, vip_next) {
3022 3025                  if ((size += ((af == AF_INET) ? sizeof (struct in_addr) :
3023 3026                      sizeof (struct in6_addr))) > buflen) {
3024 3027                          vrrp_log(VRRP_ERR, "vrrpd_build_vrrp(%s): buffer size "
3025 3028                              "not big enough %d", vr->vvr_conf.vvc_name, size);
3026 3029                          return (0);
3027 3030                  }
3028 3031  
3029 3032                  if (af == AF_INET)
3030 3033                          a4[nip++] = vip->vip_addr.in4.sin_addr;
3031 3034                  else
3032 3035                          a6[nip++] = vip->vip_addr.in6.sin6_addr;
3033 3036          }
3034 3037  
3035 3038          if (nip == 0) {
3036 3039                  vrrp_log(VRRP_ERR, "vrrpd_build_vrrp(%s): no virtual IP "
3037 3040                      "address", vr->vvr_conf.vvc_name);
3038 3041                  return (0);
3039 3042          }
3040 3043  
3041 3044          vp->vp_vers_type = (VRRP_VERSION << 4) | VRRP_PKT_ADVERT;
3042 3045          vp->vp_vrid = vr->vvr_conf.vvc_vrid;
3043 3046          vp->vp_prio = zero_pri ? VRRP_PRIO_ZERO : vr->vvr_conf.vvc_pri;
3044 3047  
3045 3048          rsvd_adver_int = MSEC2CENTISEC(vr->vvr_conf.vvc_adver_int) & 0x0fff;
3046 3049          vp->vp_rsvd_adver_int = htons(rsvd_adver_int);
3047 3050          vp->vp_ipnum = nip;
3048 3051  
3049 3052          /*
3050 3053           * Set the checksum to 0 first, then caculate it.
3051 3054           */
3052 3055          vp->vp_chksum = 0;
3053 3056          if (af == AF_INET) {
3054 3057                  vp->vp_chksum = vrrp_cksum4(
3055 3058                      &vr->vvr_pif->vvi_pip->vip_addr.in4.sin_addr,
3056 3059                      &vrrp_muladdr4.in4.sin_addr, size, vp);
3057 3060          } else {
3058 3061                  vp->vp_chksum = vrrp_cksum6(
3059 3062                      &vr->vvr_pif->vvi_pip->vip_addr.in6.sin6_addr,
3060 3063                      &vrrp_muladdr6.in6.sin6_addr, size, vp);
3061 3064          }
3062 3065  
3063 3066          return (size);
3064 3067  }
3065 3068  
3066 3069  /*
3067 3070   * We need to build the IPv4 header on our own.
3068 3071   */
3069 3072  static vrrp_err_t
3070 3073  vrrpd_send_adv_v4(vrrp_vr_t *vr, uchar_t *buf, size_t len, boolean_t zero_pri)
3071 3074  {
3072 3075          /* LINTED E_BAD_PTR_CAST_ALIGN */
3073 3076          struct ip *ip = (struct ip *)buf;
3074 3077          size_t plen;
3075 3078  
3076 3079          vrrp_log(VRRP_DBG1, "vrrpd_send_adv_v4(%s)", vr->vvr_conf.vvc_name);
3077 3080  
3078 3081          if ((plen = vrrpd_build_vrrp(vr, buf + sizeof (struct ip),
3079 3082              len - sizeof (struct ip), zero_pri)) == 0) {
3080 3083                  return (VRRP_ETOOSMALL);
3081 3084          }
3082 3085  
3083 3086          ip->ip_hl = sizeof (struct ip) >> 2;
3084 3087          ip->ip_v = IPV4_VERSION;
3085 3088          ip->ip_tos = 0;
3086 3089          plen += sizeof (struct ip);
3087 3090          ip->ip_len = htons(plen);
3088 3091          ip->ip_off = 0;
3089 3092          ip->ip_ttl = VRRP_IP_TTL;
3090 3093          ip->ip_p = IPPROTO_VRRP;
3091 3094          ip->ip_src = vr->vvr_pif->vvi_pip->vip_addr.in4.sin_addr;
3092 3095          ip->ip_dst = vrrp_muladdr4.in4.sin_addr;
3093 3096  
3094 3097          /*
3095 3098           * The kernel will set the IP cksum and the IPv4 identification.
3096 3099           */
3097 3100          ip->ip_id = 0;
3098 3101          ip->ip_sum = 0;
3099 3102  
3100 3103          if ((len = sendto(vr->vvr_vif->vvi_sockfd, buf, plen, 0,
3101 3104              (const struct sockaddr *)&vrrp_muladdr4,
3102 3105              sizeof (struct sockaddr_in))) != plen) {
3103 3106                  vrrp_log(VRRP_ERR, "vrrpd_send_adv_v4(): sendto() on "
3104 3107                      "(vrid:%d, %s, %s) failed: %s sent:%d expect:%d",
3105 3108                      vr->vvr_conf.vvc_vrid, vr->vvr_vif->vvi_ifname,
3106 3109                      af_str(vr->vvr_conf.vvc_af), strerror(errno), len, plen);
3107 3110                  return (VRRP_ESYS);
3108 3111          }
3109 3112  
3110 3113          vrrp_log(VRRP_DBG1, "vrrpd_send_adv_v4(%s) succeed",
3111 3114              vr->vvr_conf.vvc_name);
3112 3115          return (VRRP_SUCCESS);
3113 3116  }
3114 3117  
3115 3118  static vrrp_err_t
3116 3119  vrrpd_send_adv_v6(vrrp_vr_t *vr, uchar_t *buf, size_t len, boolean_t zero_pri)
3117 3120  {
3118 3121          struct msghdr msg6;
3119 3122          size_t hoplimit_space = 0;
3120 3123          size_t pktinfo_space = 0;
3121 3124          size_t bufspace = 0;
3122 3125          struct in6_pktinfo *pktinfop;
3123 3126          struct cmsghdr *cmsgp;
3124 3127          uchar_t *cmsg_datap;
3125 3128          struct iovec iov;
3126 3129          size_t plen;
3127 3130  
3128 3131          vrrp_log(VRRP_DBG1, "vrrpd_send_adv_v6(%s)", vr->vvr_conf.vvc_name);
3129 3132  
3130 3133          if ((plen = vrrpd_build_vrrp(vr, buf, len, zero_pri)) == 0)
3131 3134                  return (VRRP_ETOOSMALL);
3132 3135  
3133 3136          msg6.msg_control = NULL;
3134 3137          msg6.msg_controllen = 0;
3135 3138  
3136 3139          hoplimit_space = sizeof (int);
3137 3140          bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT +
3138 3141              hoplimit_space + _MAX_ALIGNMENT;
3139 3142  
3140 3143          pktinfo_space = sizeof (struct in6_pktinfo);
3141 3144          bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT +
3142 3145              pktinfo_space + _MAX_ALIGNMENT;
3143 3146  
3144 3147          /*
3145 3148           * We need to temporarily set the msg6.msg_controllen to bufspace
3146 3149           * (we will later trim it to actual length used). This is needed because
3147 3150           * CMSG_NXTHDR() uses it to check we have not exceeded the bounds.
3148 3151           */
3149 3152          bufspace += sizeof (struct cmsghdr);
3150 3153          msg6.msg_controllen = bufspace;
3151 3154  
3152 3155          msg6.msg_control = (struct cmsghdr *)malloc(bufspace);
3153 3156          if (msg6.msg_control == NULL) {
3154 3157                  vrrp_log(VRRP_ERR, "vrrpd_send_adv_v6(%s): memory allocation "
3155 3158                      "failed: %s", vr->vvr_conf.vvc_name, strerror(errno));
3156 3159                  return (VRRP_ENOMEM);
3157 3160          }
3158 3161  
3159 3162          cmsgp = CMSG_FIRSTHDR(&msg6);
3160 3163  
3161 3164          cmsgp->cmsg_level = IPPROTO_IPV6;
3162 3165          cmsgp->cmsg_type = IPV6_HOPLIMIT;
3163 3166          cmsg_datap = CMSG_DATA(cmsgp);
3164 3167          /* LINTED */
3165 3168          *(int *)cmsg_datap = VRRP_IP_TTL;
3166 3169          cmsgp->cmsg_len = cmsg_datap + hoplimit_space - (uchar_t *)cmsgp;
3167 3170          cmsgp = CMSG_NXTHDR(&msg6, cmsgp);
3168 3171  
3169 3172          cmsgp->cmsg_level = IPPROTO_IPV6;
3170 3173          cmsgp->cmsg_type = IPV6_PKTINFO;
3171 3174          cmsg_datap = CMSG_DATA(cmsgp);
3172 3175  
3173 3176          /* LINTED */
3174 3177          pktinfop = (struct in6_pktinfo *)cmsg_datap;
3175 3178          /*
3176 3179           * We don't know if pktinfop->ipi6_addr is aligned properly,
3177 3180           * therefore let's use bcopy, instead of assignment.
3178 3181           */
3179 3182          (void) bcopy(&vr->vvr_pif->vvi_pip->vip_addr.in6.sin6_addr,
3180 3183              &pktinfop->ipi6_addr, sizeof (struct in6_addr));
3181 3184  
3182 3185          /*
3183 3186           *  We can assume pktinfop->ipi6_ifindex is 32 bit aligned.
3184 3187           */
3185 3188          pktinfop->ipi6_ifindex = vr->vvr_vif->vvi_ifindex;
3186 3189          cmsgp->cmsg_len = cmsg_datap + pktinfo_space - (uchar_t *)cmsgp;
3187 3190          cmsgp = CMSG_NXTHDR(&msg6, cmsgp);
3188 3191          msg6.msg_controllen = (char *)cmsgp - (char *)msg6.msg_control;
3189 3192  
3190 3193          msg6.msg_name = &vrrp_muladdr6;
3191 3194          msg6.msg_namelen = sizeof (struct sockaddr_in6);
3192 3195  
3193 3196          iov.iov_base = buf;
3194 3197          iov.iov_len = plen;
3195 3198          msg6.msg_iov = &iov;
3196 3199          msg6.msg_iovlen = 1;
3197 3200  
3198 3201          if ((len = sendmsg(vr->vvr_vif->vvi_sockfd,
3199 3202              (const struct msghdr *)&msg6, 0)) != plen) {
3200 3203                  vrrp_log(VRRP_ERR, "vrrpd_send_adv_v6(%s): sendmsg() failed: "
3201 3204                      "%s expect %d sent %d", vr->vvr_conf.vvc_name,
3202 3205                      strerror(errno), plen, len);
3203 3206                  (void) free(msg6.msg_control);
3204 3207                  return (VRRP_ESYS);
3205 3208          }
3206 3209  
3207 3210          vrrp_log(VRRP_DBG1, "vrrpd_send_adv_v6(%s) succeed",
3208 3211              vr->vvr_conf.vvc_name);
3209 3212          (void) free(msg6.msg_control);
3210 3213          return (VRRP_SUCCESS);
3211 3214  }
3212 3215  
3213 3216  /*
3214 3217   * Send the VRRP advertisement packets.
3215 3218   */
3216 3219  static vrrp_err_t
3217 3220  vrrpd_send_adv(vrrp_vr_t *vr, boolean_t zero_pri)
3218 3221  {
3219 3222          uint64_t buf[(IP_MAXPACKET + 1)/8];
3220 3223  
3221 3224          vrrp_log(VRRP_DBG1, "vrrpd_send_adv(%s, %s_priority)",
3222 3225              vr->vvr_conf.vvc_name, zero_pri ? "zero" : "non_zero");
3223 3226  
3224 3227          assert(vr->vvr_pif->vvi_pip != NULL);
3225 3228  
3226 3229          if (vr->vvr_pif->vvi_pip == NULL) {
3227 3230                  vrrp_log(VRRP_DBG0, "vrrpd_send_adv(%s): no primary IP "
3228 3231                      "address", vr->vvr_conf.vvc_name);
3229 3232                  return (VRRP_EINVAL);
3230 3233          }
3231 3234  
3232 3235          if (vr->vvr_conf.vvc_af == AF_INET) {
3233 3236                  return (vrrpd_send_adv_v4(vr, (uchar_t *)buf,
3234 3237                      sizeof (buf), zero_pri));
3235 3238          } else {
3236 3239                  return (vrrpd_send_adv_v6(vr, (uchar_t *)buf,
3237 3240                      sizeof (buf), zero_pri));
3238 3241          }
3239 3242  }
3240 3243  
3241 3244  static void
3242 3245  vrrpd_process_adv(vrrp_vr_t *vr, vrrp_addr_t *from, vrrp_pkt_t *vp)
3243 3246  {
3244 3247          vrrp_vr_conf_t *conf = &vr->vvr_conf;
3245 3248          char            peer[INET6_ADDRSTRLEN];
3246 3249          char            local[INET6_ADDRSTRLEN];
3247 3250          int             addr_cmp;
3248 3251          uint16_t        peer_adver_int;
3249 3252  
3250 3253          /* LINTED E_CONSTANT_CONDITION */
3251 3254          VRRPADDR2STR(vr->vvr_conf.vvc_af, from, peer, INET6_ADDRSTRLEN,
3252 3255              _B_FALSE);
3253 3256          vrrp_log(VRRP_DBG1, "vrrpd_process_adv(%s) from %s", conf->vvc_name,
3254 3257              peer);
3255 3258  
3256 3259          if (vr->vvr_state <= VRRP_STATE_INIT) {
3257 3260                  vrrp_log(VRRP_DBG1, "vrrpd_process_adv(%s): state: %s, not "
3258 3261                      "ready", conf->vvc_name, vrrp_state2str(vr->vvr_state));
3259 3262                  return;
3260 3263          }
3261 3264  
3262 3265          peer_adver_int = CENTISEC2MSEC(ntohs(vp->vp_rsvd_adver_int) & 0x0fff);
3263 3266  
3264 3267          /* LINTED E_CONSTANT_CONDITION */
3265 3268          VRRPADDR2STR(vr->vvr_pif->vvi_af, &vr->vvr_pif->vvi_pip->vip_addr,
3266 3269              local, INET6_ADDRSTRLEN, _B_FALSE);
3267 3270          vrrp_log(VRRP_DBG1, "vrrpd_process_adv(%s): local/state/pri"
3268 3271              "(%s/%s/%d) peer/pri/intv(%s/%d/%d)", conf->vvc_name, local,
3269 3272              vrrp_state2str(vr->vvr_state), conf->vvc_pri, peer,
3270 3273              vp->vp_prio, peer_adver_int);
3271 3274  
3272 3275          addr_cmp = ipaddr_cmp(vr->vvr_pif->vvi_af, from,
3273 3276              &vr->vvr_pif->vvi_pip->vip_addr);
3274 3277          if (addr_cmp == 0) {
3275 3278                  vrrp_log(VRRP_DBG1, "vrrpd_process_adv(%s): local message",
3276 3279                      conf->vvc_name);
3277 3280                  return;
3278 3281          } else if (conf->vvc_pri == vp->vp_prio) {
3279 3282                  vrrp_log(VRRP_DBG1, "vrrpd_process_adv(%s): peer IP %s is %s"
3280 3283                      " than the local IP %s", conf->vvc_name, peer,
3281 3284                      addr_cmp > 0 ? "greater" : "less", local);
3282 3285          }
3283 3286  
3284 3287          if (conf->vvc_pri == 255) {
3285 3288                  vrrp_log(VRRP_ERR, "vrrpd_process_adv(%s): virtual address "
3286 3289                      "owner received advertisement from %s", conf->vvc_name,
3287 3290                      peer);
3288 3291                  return;
3289 3292          }
3290 3293  
3291 3294          (void) gettimeofday(&vr->vvr_peer_time, NULL);
3292 3295          (void) memcpy(&vr->vvr_peer_addr, from, sizeof (vrrp_addr_t));
3293 3296          vr->vvr_peer_prio = vp->vp_prio;
3294 3297          vr->vvr_peer_adver_int = peer_adver_int;
3295 3298  
3296 3299          if (vr->vvr_state == VRRP_STATE_BACKUP) {
3297 3300                  vr->vvr_master_adver_int = vr->vvr_peer_adver_int;
3298 3301                  if ((vp->vp_prio == VRRP_PRIO_ZERO) ||
3299 3302                      (conf->vvc_preempt == _B_FALSE ||
3300 3303                      vp->vp_prio >= conf->vvc_pri)) {
3301 3304                          (void) iu_cancel_timer(vrrpd_timerq,
3302 3305                              vr->vvr_timer_id, NULL);
3303 3306                          if (vp->vp_prio == VRRP_PRIO_ZERO) {
3304 3307                                  /* the master stops participating in VRRP */
3305 3308                                  vr->vvr_timeout = SKEW_TIME_VR(vr);
3306 3309                          } else {
3307 3310                                  vr->vvr_timeout = MASTER_DOWN_INTERVAL_VR(vr);
3308 3311                          }
3309 3312                          if ((vr->vvr_timer_id = iu_schedule_timer_ms(
3310 3313                              vrrpd_timerq, vr->vvr_timeout, vrrp_b2m_timeout,
3311 3314                              vr)) == -1) {
3312 3315                                  vrrp_log(VRRP_ERR, "vrrpd_process_adv(%s): "
3313 3316                                      "start vrrp_b2m_timeout(%d) failed",
3314 3317                                      conf->vvc_name, vr->vvr_timeout);
3315 3318                          } else {
3316 3319                                  vrrp_log(VRRP_DBG1, "vrrpd_process_adv(%s): "
3317 3320                                      "start vrrp_b2m_timeout(%d)",
3318 3321                                      conf->vvc_name, vr->vvr_timeout);
3319 3322                          }
3320 3323                  }
3321 3324          } else if (vr->vvr_state == VRRP_STATE_MASTER) {
3322 3325                  if (vp->vp_prio == VRRP_PRIO_ZERO) {
3323 3326                          (void) vrrpd_send_adv(vr, _B_FALSE);
3324 3327                          (void) iu_cancel_timer(vrrpd_timerq,
3325 3328                              vr->vvr_timer_id, NULL);
3326 3329                          if ((vr->vvr_timer_id = iu_schedule_timer_ms(
3327 3330                              vrrpd_timerq, vr->vvr_timeout, vrrp_adv_timeout,
3328 3331                              vr)) == -1) {
3329 3332                                  vrrp_log(VRRP_ERR, "vrrpd_process_adv(%s): "
3330 3333                                      "start vrrp_adv_timeout(%d) failed",
3331 3334                                      conf->vvc_name, vr->vvr_timeout);
3332 3335                          } else {
3333 3336                                  vrrp_log(VRRP_DBG1, "vrrpd_process_adv(%s): "
3334 3337                                      "start vrrp_adv_timeout(%d)",
3335 3338                                      conf->vvc_name, vr->vvr_timeout);
3336 3339                          }
3337 3340                  } else if (vp->vp_prio > conf->vvc_pri ||
3338 3341                      (vp->vp_prio == conf->vvc_pri && addr_cmp > 0)) {
3339 3342                          (void) vrrpd_state_m2b(vr);
3340 3343                  }
3341 3344          } else {
3342 3345                  assert(_B_FALSE);
3343 3346          }
3344 3347  }
3345 3348  
3346 3349  static vrrp_err_t
3347 3350  vrrpd_process_vrrp(vrrp_intf_t *pif, vrrp_pkt_t *vp, size_t len,
3348 3351      vrrp_addr_t *from)
3349 3352  {
3350 3353          vrrp_vr_t       *vr;
3351 3354          uint8_t         vers_type;
3352 3355          uint16_t        saved_cksum, cksum;
3353 3356          char            peer[INET6_ADDRSTRLEN];
3354 3357  
3355 3358          /* LINTED E_CONSTANT_CONDITION */
3356 3359          VRRPADDR2STR(pif->vvi_af, from, peer, INET6_ADDRSTRLEN, _B_FALSE);
3357 3360          vrrp_log(VRRP_DBG0, "vrrpd_process_vrrp(%s) from %s", pif->vvi_ifname,
3358 3361              peer);
3359 3362  
3360 3363          if (len < sizeof (vrrp_pkt_t)) {
3361 3364                  vrrp_log(VRRP_ERR, "vrrpd_process_vrrp(%s): invalid message "
3362 3365                      "length %d", len);
3363 3366                  return (VRRP_EINVAL);
3364 3367          }
3365 3368  
3366 3369          /*
3367 3370           * Verify: VRRP version number and packet type.
3368 3371           */
3369 3372          vers_type = ((vp->vp_vers_type & VRRP_VER_MASK) >> 4);
3370 3373          if (vers_type != VRRP_VERSION) {
3371 3374                  vrrp_log(VRRP_ERR, "vrrpd_process_vrrp(%s) unsupported "
3372 3375                      "version %d", pif->vvi_ifname, vers_type);
3373 3376                  return (VRRP_EINVAL);
3374 3377          }
3375 3378  
3376 3379          if (vp->vp_ipnum == 0) {
3377 3380                  vrrp_log(VRRP_ERR, "vrrpd_process_vrrp(%s): zero IPvX count",
3378 3381                      pif->vvi_ifname);
3379 3382                  return (VRRP_EINVAL);
3380 3383          }
3381 3384  
3382 3385          if (len - sizeof (vrrp_pkt_t) !=
3383 3386              vp->vp_ipnum * (pif->vvi_af == AF_INET ? sizeof (struct in_addr) :
3384 3387              sizeof (struct in6_addr))) {
3385 3388                  vrrp_log(VRRP_ERR, "vrrpd_process_vrrp(%s): invalid IPvX count"
3386 3389                      " %d", pif->vvi_ifname, vp->vp_ipnum);
3387 3390                  return (VRRP_EINVAL);
3388 3391          }
3389 3392  
3390 3393          vers_type = (vp->vp_vers_type & VRRP_TYPE_MASK);
3391 3394  
3392 3395          /*
3393 3396           * verify: VRRP checksum. Note that vrrp_cksum returns network byte
3394 3397           * order checksum value;
3395 3398           */
3396 3399          saved_cksum = vp->vp_chksum;
3397 3400          vp->vp_chksum = 0;
3398 3401          if (pif->vvi_af == AF_INET) {
3399 3402                  cksum = vrrp_cksum4(&from->in4.sin_addr,
3400 3403                      &vrrp_muladdr4.in4.sin_addr, len, vp);
3401 3404          } else {
3402 3405                  cksum = vrrp_cksum6(&from->in6.sin6_addr,
3403 3406                      &vrrp_muladdr6.in6.sin6_addr, len, vp);
3404 3407          }
3405 3408  
3406 3409          if (cksum != saved_cksum) {
3407 3410                  vrrp_log(VRRP_ERR, "vrrpd_process_vrrp(%s) invalid "
3408 3411                      "checksum: expected/real(0x%x/0x%x)", pif->vvi_ifname,
3409 3412                      cksum, saved_cksum);
3410 3413                  return (VRRP_EINVAL);
3411 3414          }
3412 3415  
3413 3416          if ((vr = vrrpd_lookup_vr_by_vrid(pif->vvi_ifname, vp->vp_vrid,
3414 3417              pif->vvi_af)) != NULL && vers_type == VRRP_PKT_ADVERT) {
3415 3418                  vrrpd_process_adv(vr, from, vp);
3416 3419          } else {
3417 3420                  vrrp_log(VRRP_DBG1, "vrrpd_process_vrrp(%s) VRID(%d/%s) "
3418 3421                      "not configured", pif->vvi_ifname, vp->vp_vrid,
3419 3422                      af_str(pif->vvi_af));
3420 3423          }
3421 3424          return (VRRP_SUCCESS);
3422 3425  }
3423 3426  
3424 3427  /*
3425 3428   * IPv4 socket, the IPv4 header is included.
3426 3429   */
3427 3430  static vrrp_err_t
3428 3431  vrrpd_process_adv_v4(vrrp_intf_t *pif, struct msghdr *msgp, size_t len)
3429 3432  {
3430 3433          char            abuf[INET6_ADDRSTRLEN];
3431 3434          struct ip       *ip;
3432 3435  
3433 3436          vrrp_log(VRRP_DBG0, "vrrpd_process_adv_v4(%s, %d)",
3434 3437              pif->vvi_ifname, len);
3435 3438  
3436 3439          ip = (struct ip *)msgp->msg_iov->iov_base;
3437 3440  
3438 3441          /* Sanity check */
3439 3442          if (len < sizeof (struct ip) || len < ntohs(ip->ip_len)) {
3440 3443                  vrrp_log(VRRP_ERR, "vrrpd_process_adv_v4(%s): invalid length "
3441 3444                      "%d", pif->vvi_ifname, len);
3442 3445                  return (VRRP_EINVAL);
3443 3446          }
3444 3447  
3445 3448          assert(ip->ip_v == IPV4_VERSION);
3446 3449          assert(ip->ip_p == IPPROTO_VRRP);
3447 3450          assert(msgp->msg_namelen == sizeof (struct sockaddr_in));
3448 3451  
3449 3452          if (vrrp_muladdr4.in4.sin_addr.s_addr != ip->ip_dst.s_addr) {
3450 3453                  vrrp_log(VRRP_ERR, "vrrpd_process_adv_v4(%s): invalid "
3451 3454                      "destination %s", pif->vvi_ifname,
3452 3455                      inet_ntop(pif->vvi_af, &(ip->ip_dst), abuf, sizeof (abuf)));
3453 3456                  return (VRRP_EINVAL);
3454 3457          }
3455 3458  
3456 3459          if (ip->ip_ttl != VRRP_IP_TTL) {
3457 3460                  vrrp_log(VRRP_ERR, "vrrpd_process_adv_v4(%s): invalid "
3458 3461                      "ttl %d", pif->vvi_ifname, ip->ip_ttl);
3459 3462                  return (VRRP_EINVAL);
3460 3463          }
3461 3464  
3462 3465          /*
3463 3466           * Note that the ip_len contains only the IP payload length.
3464 3467           */
3465 3468          return (vrrpd_process_vrrp(pif,
3466 3469              /* LINTED E_BAD_PTR_CAST_ALIGN */
3467 3470              (vrrp_pkt_t *)((char *)ip + ip->ip_hl * 4), ntohs(ip->ip_len),
3468 3471              (vrrp_addr_t *)msgp->msg_name));
3469 3472  }
3470 3473  
3471 3474  /*
3472 3475   * IPv6 socket, check the ancillary_data.
3473 3476   */
3474 3477  static vrrp_err_t
3475 3478  vrrpd_process_adv_v6(vrrp_intf_t *pif, struct msghdr *msgp, size_t len)
3476 3479  {
3477 3480          struct cmsghdr          *cmsgp;
3478 3481          uchar_t                 *cmsg_datap;
3479 3482          struct in6_pktinfo      *pktinfop;
3480 3483          char                    abuf[INET6_ADDRSTRLEN];
3481 3484          int                     ttl;
3482 3485  
3483 3486          vrrp_log(VRRP_DBG1, "vrrpd_process_adv_v6(%s, %d)",
3484 3487              pif->vvi_ifname, len);
3485 3488  
3486 3489          /* Sanity check */
3487 3490          if (len < sizeof (vrrp_pkt_t)) {
3488 3491                  vrrp_log(VRRP_ERR, "vrrpd_process_adv_v6(%s): invalid length "
3489 3492                      "%d", pif->vvi_ifname, len);
3490 3493                  return (VRRP_EINVAL);
3491 3494          }
3492 3495  
3493 3496          assert(msgp->msg_namelen == sizeof (struct sockaddr_in6));
3494 3497  
3495 3498          for (cmsgp = CMSG_FIRSTHDR(msgp); cmsgp != NULL;
3496 3499              cmsgp = CMSG_NXTHDR(msgp, cmsgp)) {
3497 3500                  assert(cmsgp->cmsg_level == IPPROTO_IPV6);
3498 3501                  cmsg_datap = CMSG_DATA(cmsgp);
3499 3502  
3500 3503                  switch (cmsgp->cmsg_type) {
3501 3504                  case IPV6_HOPLIMIT:
3502 3505                          /* LINTED E_BAD_PTR_CAST_ALIGN */
3503 3506                          if ((ttl = *(int *)cmsg_datap) == VRRP_IP_TTL)
3504 3507                                  break;
3505 3508  
3506 3509                          vrrp_log(VRRP_ERR, "vrrpd_process_adv_v4(%s): invalid "
3507 3510                              "ttl %d", pif->vvi_ifname, ttl);
3508 3511                          return (VRRP_EINVAL);
3509 3512                  case IPV6_PKTINFO:
3510 3513                          /* LINTED E_BAD_PTR_CAST_ALIGN */
3511 3514                          pktinfop = (struct in6_pktinfo *)cmsg_datap;
3512 3515                          if (IN6_ARE_ADDR_EQUAL(&pktinfop->ipi6_addr,
3513 3516                              &vrrp_muladdr6.in6.sin6_addr)) {
3514 3517                                  break;
3515 3518                          }
3516 3519  
3517 3520                          vrrp_log(VRRP_ERR, "vrrpd_process_adv_v4(%s): invalid "
3518 3521                              "destination %s", pif->vvi_ifname,
3519 3522                              inet_ntop(pif->vvi_af, &pktinfop->ipi6_addr, abuf,
3520 3523                              sizeof (abuf)));
3521 3524                          return (VRRP_EINVAL);
3522 3525                  }
3523 3526          }
3524 3527  
3525 3528          return (vrrpd_process_vrrp(pif, msgp->msg_iov->iov_base, len,
3526 3529              msgp->msg_name));
3527 3530  }
3528 3531  
3529 3532  /* ARGSUSED */
3530 3533  static void
3531 3534  vrrpd_sock_handler(iu_eh_t *eh, int s, short events, iu_event_id_t id,
3532 3535      void *arg)
3533 3536  {
3534 3537          struct msghdr           msg;
3535 3538          vrrp_addr_t             from;
3536 3539          uint64_t                buf[(IP_MAXPACKET + 1)/8];
3537 3540          uint64_t                ancillary_data[(IP_MAXPACKET + 1)/8];
3538 3541          vrrp_intf_t             *pif = arg;
3539 3542          int                     af = pif->vvi_af;
3540 3543          int                     len;
3541 3544          struct iovec            iov;
3542 3545  
3543 3546          vrrp_log(VRRP_DBG1, "vrrpd_sock_handler(%s)", pif->vvi_ifname);
3544 3547  
3545 3548          msg.msg_name = (struct sockaddr *)&from;
3546 3549          msg.msg_namelen = (af == AF_INET) ? sizeof (struct sockaddr_in) :
3547 3550              sizeof (struct sockaddr_in6);
3548 3551          iov.iov_base = (char *)buf;
3549 3552          iov.iov_len = sizeof (buf);
3550 3553          msg.msg_iov = &iov;
3551 3554          msg.msg_iovlen = 1;
3552 3555          msg.msg_control = ancillary_data;
3553 3556          msg.msg_controllen = sizeof (ancillary_data);
3554 3557  
3555 3558          if ((len = recvmsg(s, &msg, 0)) == -1) {
3556 3559                  vrrp_log(VRRP_ERR, "vrrpd_sock_handler() recvmsg(%s) "
3557 3560                      "failed: %s", pif->vvi_ifname, strerror(errno));
3558 3561                  return;
3559 3562          }
3560 3563  
3561 3564          /*
3562 3565           * Ignore packets whose control buffers that don't fit
3563 3566           */
3564 3567          if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
3565 3568                  vrrp_log(VRRP_ERR, "vrrpd_sock_handler() %s buffer not "
3566 3569                      "big enough", pif->vvi_ifname);
3567 3570                  return;
3568 3571          }
3569 3572  
3570 3573          if (af == AF_INET)
3571 3574                  (void) vrrpd_process_adv_v4(pif, &msg, len);
3572 3575          else
3573 3576                  (void) vrrpd_process_adv_v6(pif, &msg, len);
3574 3577  }
3575 3578  
3576 3579  /*
3577 3580   * Create the socket which is used to receive VRRP packets. Virtual routers
3578 3581   * that configured on the same physical interface share the same socket.
3579 3582   */
3580 3583  static vrrp_err_t
3581 3584  vrrpd_init_rxsock(vrrp_vr_t *vr)
3582 3585  {
3583 3586          vrrp_intf_t *pif;       /* Physical interface used to recv packets */
3584 3587          struct group_req greq;
3585 3588          struct sockaddr_storage *muladdr;
3586 3589          int af, proto;
3587 3590          int on = 1;
3588 3591          vrrp_err_t err = VRRP_SUCCESS;
3589 3592  
3590 3593          vrrp_log(VRRP_DBG1, "vrrpd_init_rxsock(%s)", vr->vvr_conf.vvc_name);
3591 3594  
3592 3595          /*
3593 3596           * The RX sockets may already been initialized.
3594 3597           */
3595 3598          if ((pif = vr->vvr_pif) != NULL) {
3596 3599                  vrrp_log(VRRP_DBG1, "vrrpd_init_rxsock(%s) already done on %s",
3597 3600                      vr->vvr_conf.vvc_name, pif->vvi_ifname);
3598 3601                  assert(pif->vvi_sockfd != -1);
3599 3602                  return (VRRP_SUCCESS);
3600 3603          }
3601 3604  
3602 3605          /*
3603 3606           * If no IP addresses configured on the primary interface,
3604 3607           * return failure.
3605 3608           */
3606 3609          af = vr->vvr_conf.vvc_af;
3607 3610          pif = vrrpd_lookup_if(vr->vvr_conf.vvc_link, af);
3608 3611          if (pif == NULL) {
3609 3612                  vrrp_log(VRRP_DBG1, "vrrpd_init_rxsock(%s): no IP address "
3610 3613                      "over %s/%s", vr->vvr_conf.vvc_name,
3611 3614                      vr->vvr_conf.vvc_link, af_str(af));
3612 3615                  return (VRRP_ENOPRIM);
3613 3616          }
3614 3617  
3615 3618          proto = (af == AF_INET ? IPPROTO_IP : IPPROTO_IPV6);
3616 3619          if (pif->vvi_nvr++ == 0) {
3617 3620                  assert(pif->vvi_sockfd < 0);
3618 3621                  pif->vvi_sockfd = socket(af, SOCK_RAW, IPPROTO_VRRP);
3619 3622                  if (pif->vvi_sockfd < 0) {
3620 3623                          vrrp_log(VRRP_ERR, "vrrpd_init_rxsock(%s): socket() "
3621 3624                              "failed %s", vr->vvr_conf.vvc_name,
3622 3625                              strerror(errno));
3623 3626                          err = VRRP_ESYS;
3624 3627                          goto done;
3625 3628                  }
3626 3629  
3627 3630                  /*
3628 3631                   * Join the multicast group to receive VRRP packets.
3629 3632                   */
3630 3633                  if (af == AF_INET) {
3631 3634                          muladdr = (struct sockaddr_storage *)
3632 3635                              (void *)&vrrp_muladdr4;
3633 3636                  } else {
3634 3637                          muladdr = (struct sockaddr_storage *)
3635 3638                              (void *)&vrrp_muladdr6;
3636 3639                  }
3637 3640  
3638 3641                  greq.gr_interface = pif->vvi_ifindex;
3639 3642                  (void) memcpy(&greq.gr_group, muladdr,
3640 3643                      sizeof (struct sockaddr_storage));
3641 3644                  if (setsockopt(pif->vvi_sockfd, proto, MCAST_JOIN_GROUP, &greq,
3642 3645                      sizeof (struct group_req)) < 0) {
3643 3646                          vrrp_log(VRRP_ERR, "vrrpd_init_rxsock(%s): "
3644 3647                              "join_group(%d) failed: %s", vr->vvr_conf.vvc_name,
3645 3648                              pif->vvi_ifindex, strerror(errno));
3646 3649                          err = VRRP_ESYS;
3647 3650                          goto done;
3648 3651                  } else {
3649 3652                          vrrp_log(VRRP_DBG1, "vrrpd_init_rxsock(%s): "
3650 3653                              "join_group(%d) succeeded", vr->vvr_conf.vvc_name,
3651 3654                              pif->vvi_ifindex);
3652 3655                  }
3653 3656  
3654 3657                  /*
3655 3658                   * Unlike IPv4, the IPv6 raw socket does not pass the IP header
3656 3659                   * when a packet is received. Call setsockopt() to receive such
3657 3660                   * information.
3658 3661                   */
3659 3662                  if (af == AF_INET6) {
3660 3663                          /*
3661 3664                           * Enable receipt of destination address info
3662 3665                           */
3663 3666                          if (setsockopt(pif->vvi_sockfd, proto, IPV6_RECVPKTINFO,
3664 3667                              (char *)&on, sizeof (on)) < 0) {
3665 3668                                  vrrp_log(VRRP_ERR, "vrrpd_init_rxsock(%s): "
3666 3669                                      "enable recvpktinfo failed: %s",
3667 3670                                      vr->vvr_conf.vvc_name, strerror(errno));
3668 3671                                  err = VRRP_ESYS;
3669 3672                                  goto done;
3670 3673                          }
3671 3674  
3672 3675                          /*
3673 3676                           * Enable receipt of hoplimit info
3674 3677                           */
3675 3678                          if (setsockopt(pif->vvi_sockfd, proto,
3676 3679                              IPV6_RECVHOPLIMIT, (char *)&on, sizeof (on)) < 0) {
3677 3680                                  vrrp_log(VRRP_ERR, "vrrpd_init_rxsock(%s): "
3678 3681                                      "enable recvhoplimit failed: %s",
3679 3682                                      vr->vvr_conf.vvc_name, strerror(errno));
3680 3683                                  err = VRRP_ESYS;
3681 3684                                  goto done;
3682 3685                          }
3683 3686                  }
3684 3687  
3685 3688                  if ((pif->vvi_eid = iu_register_event(vrrpd_eh,
3686 3689                      pif->vvi_sockfd, POLLIN, vrrpd_sock_handler, pif)) == -1) {
3687 3690                          vrrp_log(VRRP_ERR, "vrrpd_init_rxsock(%s): "
3688 3691                              "iu_register_event() failed",
3689 3692                              vr->vvr_conf.vvc_name);
3690 3693                          err = VRRP_ESYS;
3691 3694                          goto done;
3692 3695                  }
3693 3696          } else {
3694 3697                  vrrp_log(VRRP_DBG1, "vrrpd_init_rxsock(%s) over %s already "
3695 3698                      "done %d", vr->vvr_conf.vvc_name, pif->vvi_ifname,
3696 3699                      pif->vvi_nvr);
3697 3700                  assert(IS_PRIMARY_INTF(pif));
3698 3701          }
3699 3702  
3700 3703  done:
3701 3704          vr->vvr_pif = pif;
3702 3705          if (err != VRRP_SUCCESS)
3703 3706                  vrrpd_fini_rxsock(vr);
3704 3707  
3705 3708          return (err);
3706 3709  }
3707 3710  
3708 3711  /*
3709 3712   * Delete the socket which is used to receive VRRP packets for the given
3710 3713   * VRRP router. Since all virtual routers that configured on the same
3711 3714   * physical interface share the same socket, the socket is only closed
3712 3715   * when the last VRRP router share this socket is deleted.
3713 3716   */
3714 3717  static void
3715 3718  vrrpd_fini_rxsock(vrrp_vr_t *vr)
3716 3719  {
3717 3720          vrrp_intf_t     *pif = vr->vvr_pif;
3718 3721  
3719 3722          vrrp_log(VRRP_DBG1, "vrrpd_fini_rxsock(%s)", vr->vvr_conf.vvc_name);
3720 3723  
3721 3724          if (pif == NULL)
3722 3725                  return;
3723 3726  
3724 3727          if (--pif->vvi_nvr == 0) {
3725 3728                  vrrp_log(VRRP_DBG1, "vrrpd_fini_rxsock(%s) over %s",
3726 3729                      vr->vvr_conf.vvc_name, pif->vvi_ifname);
3727 3730                  (void) iu_unregister_event(vrrpd_eh, pif->vvi_eid, NULL);
3728 3731                  (void) close(pif->vvi_sockfd);
3729 3732                  pif->vvi_pip = NULL;
3730 3733                  pif->vvi_sockfd = -1;
3731 3734                  pif->vvi_eid = -1;
3732 3735          } else {
3733 3736                  vrrp_log(VRRP_DBG1, "vrrpd_fini_rxsock(%s) over %s %d",
3734 3737                      vr->vvr_conf.vvc_name, pif->vvi_ifname, pif->vvi_nvr);
3735 3738          }
3736 3739          vr->vvr_pif = NULL;
3737 3740  }
3738 3741  
3739 3742  /*
3740 3743   * Create the socket which is used to send VRRP packets. Further, set
3741 3744   * the IFF_NOACCEPT flag based on the VRRP router's accept mode.
3742 3745   */
3743 3746  static vrrp_err_t
3744 3747  vrrpd_init_txsock(vrrp_vr_t *vr)
3745 3748  {
3746 3749          int             af;
3747 3750          vrrp_intf_t     *vif;
3748 3751          vrrp_err_t      err;
3749 3752  
3750 3753          vrrp_log(VRRP_DBG1, "vrrpd_init_txsock(%s)", vr->vvr_conf.vvc_name);
3751 3754  
3752 3755          if (vr->vvr_vif != NULL) {
3753 3756                  vrrp_log(VRRP_DBG1, "vrrpd_init_txsock(%s) already done on %s",
3754 3757                      vr->vvr_conf.vvc_name, vr->vvr_vif->vvi_ifname);
3755 3758                  return (VRRP_SUCCESS);
3756 3759          }
3757 3760  
3758 3761          af = vr->vvr_conf.vvc_af;
3759 3762          if ((vif = vrrpd_lookup_if(vr->vvr_vnic, af)) == NULL) {
3760 3763                  vrrp_log(VRRP_DBG1, "vrrpd_init_txsock(%s) no IP address over "
3761 3764                      "%s/%s", vr->vvr_conf.vvc_name, vr->vvr_vnic, af_str(af));
3762 3765                  return (VRRP_ENOVIRT);
3763 3766          }
3764 3767  
3765 3768          vr->vvr_vif = vif;
3766 3769          if (vr->vvr_conf.vvc_af == AF_INET)
3767 3770                  err = vrrpd_init_txsock_v4(vr);
3768 3771          else
3769 3772                  err = vrrpd_init_txsock_v6(vr);
3770 3773  
3771 3774          if (err != VRRP_SUCCESS)
3772 3775                  goto done;
3773 3776  
3774 3777          /*
3775 3778           * The interface should start with IFF_NOACCEPT flag not set, only
3776 3779           * call this function when the VRRP router requires IFF_NOACCEPT.
3777 3780           */
3778 3781          if (!vr->vvr_conf.vvc_accept)
3779 3782                  err = vrrpd_set_noaccept(vr, _B_TRUE);
3780 3783  
3781 3784  done:
3782 3785          if (err != VRRP_SUCCESS) {
3783 3786                  (void) close(vif->vvi_sockfd);
3784 3787                  vif->vvi_sockfd = -1;
3785 3788                  vr->vvr_vif = NULL;
3786 3789          }
3787 3790  
3788 3791          return (err);
3789 3792  }
3790 3793  
3791 3794  /*
3792 3795   * Create the IPv4 socket which is used to send VRRP packets. Note that
3793 3796   * the destination MAC address of VRRP advertisement must be the virtual
3794 3797   * MAC address, so we specify the output interface to be the specific VNIC.
3795 3798   */
3796 3799  static vrrp_err_t
3797 3800  vrrpd_init_txsock_v4(vrrp_vr_t *vr)
3798 3801  {
3799 3802          vrrp_intf_t *vif;       /* VNIC interface used to send packets */
3800 3803          vrrp_ip_t *vip;         /* The first IP over the VNIC */
3801 3804          int on = 1;
3802 3805          char off = 0;
3803 3806          vrrp_err_t err = VRRP_SUCCESS;
3804 3807          char abuf[INET6_ADDRSTRLEN];
3805 3808  
3806 3809          vif = vr->vvr_vif;
3807 3810          assert(vr->vvr_conf.vvc_af == AF_INET);
3808 3811          assert(vif != NULL);
3809 3812  
3810 3813          vrrp_log(VRRP_DBG1, "vrrpd_init_txsock_v4(%s) over %s",
3811 3814              vr->vvr_conf.vvc_name, vif->vvi_ifname);
3812 3815  
3813 3816          if (vif->vvi_sockfd != -1) {
3814 3817                  vrrp_log(VRRP_DBG1, "vrrpd_init_txsock_v4(%s) already done "
3815 3818                      "over %s", vr->vvr_conf.vvc_name, vif->vvi_ifname);
3816 3819                  return (VRRP_SUCCESS);
3817 3820          }
3818 3821  
3819 3822          vif->vvi_sockfd = socket(vif->vvi_af, SOCK_RAW, IPPROTO_VRRP);
3820 3823          if (vif->vvi_sockfd < 0) {
3821 3824                  vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v4(%s): socket() "
3822 3825                      "failed: %s", vr->vvr_conf.vvc_name, strerror(errno));
3823 3826                  err = VRRP_ESYS;
3824 3827                  goto done;
3825 3828          }
3826 3829  
3827 3830          /*
3828 3831           * Include the IP header, so that we can specify the IP address/ttl.
3829 3832           */
3830 3833          if (setsockopt(vif->vvi_sockfd, IPPROTO_IP, IP_HDRINCL, (char *)&on,
3831 3834              sizeof (on)) < 0) {
3832 3835                  vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v4(%s): ip_hdrincl "
3833 3836                      "failed: %s", vr->vvr_conf.vvc_name, strerror(errno));
3834 3837                  err = VRRP_ESYS;
3835 3838                  goto done;
3836 3839          }
3837 3840  
3838 3841          /*
3839 3842           * Disable multicast loopback.
3840 3843           */
3841 3844          if (setsockopt(vif->vvi_sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &off,
3842 3845              sizeof (char)) == -1) {
3843 3846                  vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v4(%s): disable "
3844 3847                      "multicast_loop failed: %s", vr->vvr_conf.vvc_name,
3845 3848                      strerror(errno));
3846 3849                  err = VRRP_ESYS;
3847 3850                  goto done;
3848 3851          }
3849 3852  
3850 3853          vip = TAILQ_FIRST(&vif->vvi_iplist);
3851 3854          /* LINTED E_CONSTANT_CONDITION */
3852 3855          VRRPADDR2STR(vif->vvi_af, &vip->vip_addr, abuf, INET6_ADDRSTRLEN,
3853 3856              _B_FALSE);
3854 3857  
3855 3858          /*
3856 3859           * Set the output interface to send the VRRP packet.
3857 3860           */
3858 3861          if (setsockopt(vif->vvi_sockfd, IPPROTO_IP, IP_MULTICAST_IF,
3859 3862              &vip->vip_addr.in4.sin_addr, sizeof (struct in_addr)) < 0) {
3860 3863                  vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v4(%s): multcast_if(%s) "
3861 3864                      "failed: %s", vr->vvr_conf.vvc_name, abuf, strerror(errno));
3862 3865                  err = VRRP_ESYS;
3863 3866          } else {
3864 3867                  vrrp_log(VRRP_DBG0, "vrrpd_init_txsock_v4(%s): multcast_if(%s) "
3865 3868                      "succeed", vr->vvr_conf.vvc_name, abuf);
3866 3869          }
3867 3870  
3868 3871  done:
3869 3872          if (err != VRRP_SUCCESS) {
3870 3873                  (void) close(vif->vvi_sockfd);
3871 3874                  vif->vvi_sockfd = -1;
3872 3875          }
3873 3876  
3874 3877          return (err);
3875 3878  }
3876 3879  
3877 3880  /*
3878 3881   * Create the IPv6 socket which is used to send VRRP packets. Note that
3879 3882   * the destination must be the virtual MAC address, so we specify the output
3880 3883   * interface to be the specific VNIC.
3881 3884   */
3882 3885  static vrrp_err_t
3883 3886  vrrpd_init_txsock_v6(vrrp_vr_t *vr)
3884 3887  {
3885 3888          vrrp_intf_t *vif;       /* VNIC interface used to send packets */
3886 3889          int off = 0, ttl = VRRP_IP_TTL;
3887 3890          vrrp_err_t err = VRRP_SUCCESS;
3888 3891  
3889 3892          vif = vr->vvr_vif;
3890 3893          assert(vr->vvr_conf.vvc_af == AF_INET6);
3891 3894          assert(vif != NULL);
3892 3895  
3893 3896          vrrp_log(VRRP_DBG1, "vrrpd_init_txsock_v6(%s) over %s",
3894 3897              vr->vvr_conf.vvc_name, vif->vvi_ifname);
3895 3898  
3896 3899          if (vif->vvi_sockfd != -1) {
3897 3900                  vrrp_log(VRRP_DBG1, "vrrpd_init_txsock_v6(%s) already done "
3898 3901                      "over %s", vr->vvr_conf.vvc_name, vif->vvi_ifname);
3899 3902                  return (VRRP_SUCCESS);
3900 3903          }
3901 3904  
3902 3905          vif->vvi_sockfd = socket(vif->vvi_af, SOCK_RAW, IPPROTO_VRRP);
3903 3906          if (vif->vvi_sockfd < 0) {
3904 3907                  vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v6(%s): socket() "
3905 3908                      "failed: %s", vr->vvr_conf.vvc_name, strerror(errno));
3906 3909                  err = VRRP_ESYS;
3907 3910                  goto done;
3908 3911          }
3909 3912  
3910 3913          /*
3911 3914           * Disable multicast loopback.
3912 3915           */
3913 3916          if (setsockopt(vif->vvi_sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
3914 3917              &off, sizeof (int)) == -1) {
3915 3918                  vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v6(%s): disable "
3916 3919                      "multicast_loop failed: %s", vr->vvr_conf.vvc_name,
3917 3920                      strerror(errno));
3918 3921                  err = VRRP_ESYS;
3919 3922                  goto done;
3920 3923          }
3921 3924  
3922 3925          /*
3923 3926           * Set the multicast TTL.
3924 3927           */
3925 3928          if (setsockopt(vif->vvi_sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
3926 3929              &ttl, sizeof (int)) == -1) {
3927 3930                  vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v6(%s): enable "
3928 3931                      "multicast_hops %d failed: %s", vr->vvr_conf.vvc_name,
3929 3932                      ttl, strerror(errno));
3930 3933                  err = VRRP_ESYS;
3931 3934                  goto done;
3932 3935          }
3933 3936  
3934 3937          /*
3935 3938           * Set the output interface to send the VRRP packet.
3936 3939           */
3937 3940          if (setsockopt(vif->vvi_sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
3938 3941              &vif->vvi_ifindex, sizeof (uint32_t)) < 0) {
3939 3942                  vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v6(%s): multicast_if(%d) "
3940 3943                      "failed: %s", vr->vvr_conf.vvc_name, vif->vvi_ifindex,
3941 3944                      strerror(errno));
3942 3945                  err = VRRP_ESYS;
3943 3946          } else {
3944 3947                  vrrp_log(VRRP_DBG1, "vrrpd_init_txsock_v6(%s): multicast_if(%d)"
3945 3948                      " succeed", vr->vvr_conf.vvc_name, vif->vvi_ifindex);
3946 3949          }
3947 3950  
3948 3951  done:
3949 3952          if (err != VRRP_SUCCESS) {
3950 3953                  (void) close(vif->vvi_sockfd);
3951 3954                  vif->vvi_sockfd = -1;
3952 3955          }
3953 3956  
3954 3957          return (err);
3955 3958  }
3956 3959  
3957 3960  /*
3958 3961   * Delete the socket which is used to send VRRP packets. Further, clear
3959 3962   * the IFF_NOACCEPT flag based on the VRRP router's accept mode.
3960 3963   */
3961 3964  static void
3962 3965  vrrpd_fini_txsock(vrrp_vr_t *vr)
3963 3966  {
3964 3967          vrrp_intf_t *vif = vr->vvr_vif;
3965 3968  
3966 3969          vrrp_log(VRRP_DBG1, "vrrpd_fini_txsock(%s)", vr->vvr_conf.vvc_name);
3967 3970  
3968 3971          if (vif != NULL) {
3969 3972                  if (!vr->vvr_conf.vvc_accept)
3970 3973                          (void) vrrpd_set_noaccept(vr, _B_FALSE);
3971 3974                  (void) close(vif->vvi_sockfd);
3972 3975                  vif->vvi_sockfd = -1;
3973 3976                  vr->vvr_vif = NULL;
3974 3977          }
3975 3978  }
3976 3979  
3977 3980  /*
3978 3981   * Given the the pseudo header cksum value (sum), caculate the cksum with
3979 3982   * the rest of VRRP packet.
3980 3983   */
3981 3984  static uint16_t
3982 3985  in_cksum(int sum, uint16_t plen, void *p)
3983 3986  {
3984 3987          int nleft;
3985 3988          uint16_t *w;
3986 3989          uint16_t answer;
3987 3990          uint16_t odd_byte = 0;
3988 3991  
3989 3992          nleft = plen;
3990 3993          w = (uint16_t *)p;
3991 3994          while (nleft > 1) {
3992 3995                  sum += *w++;
3993 3996                  nleft -= 2;
3994 3997          }
3995 3998  
3996 3999          /* mop up an odd byte, if necessary */
3997 4000          if (nleft == 1) {
3998 4001                  *(uchar_t *)(&odd_byte) = *(uchar_t *)w;
3999 4002                  sum += odd_byte;
4000 4003          }
4001 4004  
4002 4005          /*
4003 4006           * add back carry outs from top 16 bits to low 16 bits
4004 4007           */
4005 4008          sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
4006 4009          sum += (sum >> 16);                     /* add carry */
4007 4010          answer = ~sum;                          /* truncate to 16 bits */
4008 4011          return (answer == 0 ? ~0 : answer);
4009 4012  }
4010 4013  
4011 4014  /* Pseudo header for v4 */
4012 4015  struct pshv4 {
4013 4016          struct in_addr  ph4_src;
4014 4017          struct in_addr  ph4_dst;
4015 4018          uint8_t         ph4_zero;       /* always zero */
4016 4019          uint8_t         ph4_protocol;   /* protocol used, IPPROTO_VRRP */
4017 4020          uint16_t        ph4_len;        /* VRRP payload len */
4018 4021  };
4019 4022  
4020 4023  /*
4021 4024   * Checksum routine for VRRP checksum. Note that plen is the upper-layer
4022 4025   * packet length (in the host byte order), and both IP source and destination
4023 4026   * addresses are in the network byte order.
4024 4027   */
4025 4028  static uint16_t
4026 4029  vrrp_cksum4(struct in_addr *src, struct in_addr *dst, uint16_t plen,
4027 4030      vrrp_pkt_t *vp)
4028 4031  {
4029 4032          struct pshv4 ph4;
4030 4033          int nleft;
4031 4034          uint16_t *w;
4032 4035          int sum = 0;
4033 4036  
4034 4037          ph4.ph4_src = *src;
4035 4038          ph4.ph4_dst = *dst;
4036 4039          ph4.ph4_zero = 0;
4037 4040          ph4.ph4_protocol = IPPROTO_VRRP;
4038 4041          ph4.ph4_len = htons(plen);
4039 4042  
4040 4043          /*
4041 4044           *  Our algorithm is simple, using a 32 bit accumulator (sum),
4042 4045           *  we add sequential 16 bit words to it, and at the end, fold
4043 4046           *  back all the carry bits from the top 16 bits into the lower
4044 4047           *  16 bits.
4045 4048           */
4046 4049          nleft = sizeof (struct pshv4);
4047 4050          w = (uint16_t *)&ph4;
4048 4051          while (nleft > 0) {
4049 4052                  sum += *w++;
4050 4053                  nleft -= 2;
4051 4054          }
4052 4055  
4053 4056          return (in_cksum(sum, plen, vp));
4054 4057  }
4055 4058  
4056 4059  /* Pseudo header for v6 */
4057 4060  struct pshv6 {
4058 4061          struct in6_addr ph6_src;
4059 4062          struct in6_addr ph6_dst;
4060 4063          uint32_t        ph6_len;        /* VRRP payload len */
4061 4064          uint32_t        ph6_zero : 24,
4062 4065                          ph6_protocol : 8; /* protocol used, IPPROTO_VRRP */
4063 4066  };
4064 4067  
4065 4068  /*
4066 4069   * Checksum routine for VRRP checksum. Note that plen is the upper-layer
4067 4070   * packet length (in the host byte order), and both IP source and destination
4068 4071   * addresses are in the network byte order.
4069 4072   */
4070 4073  static uint16_t
4071 4074  vrrp_cksum6(struct in6_addr *src, struct in6_addr *dst, uint16_t plen,
4072 4075      vrrp_pkt_t *vp)
4073 4076  {
4074 4077          struct pshv6 ph6;
4075 4078          int nleft;
4076 4079          uint16_t *w;
4077 4080          int sum = 0;
4078 4081  
4079 4082          ph6.ph6_src = *src;
4080 4083          ph6.ph6_dst = *dst;
4081 4084          ph6.ph6_zero = 0;
4082 4085          ph6.ph6_protocol = IPPROTO_VRRP;
4083 4086          ph6.ph6_len = htonl((uint32_t)plen);
4084 4087  
4085 4088          /*
4086 4089           *  Our algorithm is simple, using a 32 bit accumulator (sum),
4087 4090           *  we add sequential 16 bit words to it, and at the end, fold
4088 4091           *  back all the carry bits from the top 16 bits into the lower
4089 4092           *  16 bits.
4090 4093           */
4091 4094          nleft = sizeof (struct pshv6);
4092 4095          w = (uint16_t *)&ph6;
4093 4096          while (nleft > 0) {
4094 4097                  sum += *w++;
4095 4098                  nleft -= 2;
4096 4099          }
4097 4100  
4098 4101          return (in_cksum(sum, plen, vp));
4099 4102  }
4100 4103  
4101 4104  vrrp_err_t
4102 4105  vrrpd_state_i2m(vrrp_vr_t *vr)
4103 4106  {
4104 4107          vrrp_err_t      err;
4105 4108  
4106 4109          vrrp_log(VRRP_DBG1, "vrrpd_state_i2m(%s)", vr->vvr_conf.vvc_name);
4107 4110  
4108 4111          vrrpd_state_trans(VRRP_STATE_INIT, VRRP_STATE_MASTER, vr);
4109 4112          if ((err = vrrpd_virtualip_update(vr, _B_FALSE)) != VRRP_SUCCESS)
4110 4113                  return (err);
4111 4114  
4112 4115          (void) vrrpd_send_adv(vr, _B_FALSE);
4113 4116  
4114 4117          vr->vvr_err = VRRP_SUCCESS;
4115 4118          vr->vvr_timeout = vr->vvr_conf.vvc_adver_int;
4116 4119          if ((vr->vvr_timer_id = iu_schedule_timer_ms(vrrpd_timerq,
4117 4120              vr->vvr_timeout, vrrp_adv_timeout, vr)) == -1) {
4118 4121                  vrrp_log(VRRP_ERR, "vrrpd_state_i2m(): unable to start timer");
4119 4122                  return (VRRP_ESYS);
4120 4123          } else {
4121 4124                  vrrp_log(VRRP_DBG1, "vrrpd_state_i2m(%s): start "
4122 4125                      "vrrp_adv_timeout(%d)", vr->vvr_conf.vvc_name,
4123 4126                      vr->vvr_timeout);
4124 4127          }
4125 4128          return (VRRP_SUCCESS);
4126 4129  }
4127 4130  
4128 4131  vrrp_err_t
4129 4132  vrrpd_state_i2b(vrrp_vr_t *vr)
4130 4133  {
4131 4134          vrrp_err_t      err;
4132 4135  
4133 4136          vrrp_log(VRRP_DBG1, "vrrpd_state_i2b(%s)", vr->vvr_conf.vvc_name);
4134 4137  
4135 4138          vrrpd_state_trans(VRRP_STATE_INIT, VRRP_STATE_BACKUP, vr);
4136 4139          if ((err = vrrpd_virtualip_update(vr, _B_FALSE)) != VRRP_SUCCESS)
4137 4140                  return (err);
4138 4141  
4139 4142          /*
4140 4143           * Reinitialize the Master advertisement interval to be the configured
4141 4144           * value.
4142 4145           */
4143 4146          vr->vvr_err = VRRP_SUCCESS;
4144 4147          vr->vvr_master_adver_int = vr->vvr_conf.vvc_adver_int;
4145 4148          vr->vvr_timeout = MASTER_DOWN_INTERVAL_VR(vr);
4146 4149          if ((vr->vvr_timer_id = iu_schedule_timer_ms(vrrpd_timerq,
4147 4150              vr->vvr_timeout, vrrp_b2m_timeout, vr)) == -1) {
4148 4151                  vrrp_log(VRRP_ERR, "vrrpd_state_i2b(): unable to set timer");
4149 4152                  return (VRRP_ESYS);
4150 4153          } else {
4151 4154                  vrrp_log(VRRP_DBG1, "vrrpd_state_i2b(%s): start "
4152 4155                      "vrrp_b2m_timeout(%d)", vr->vvr_conf.vvc_name,
4153 4156                      vr->vvr_timeout);
4154 4157          }
4155 4158          return (VRRP_SUCCESS);
4156 4159  }
4157 4160  
4158 4161  void
4159 4162  vrrpd_state_m2i(vrrp_vr_t *vr)
4160 4163  {
4161 4164          vrrp_log(VRRP_DBG1, "vrrpd_state_m2i(%s)", vr->vvr_conf.vvc_name);
4162 4165  
4163 4166          vrrpd_state_trans(VRRP_STATE_MASTER, VRRP_STATE_INIT, vr);
4164 4167          (void) vrrpd_virtualip_update(vr, _B_TRUE);
4165 4168          bzero(&vr->vvr_peer, sizeof (vrrp_peer_t));
4166 4169          (void) iu_cancel_timer(vrrpd_timerq, vr->vvr_timer_id, NULL);
4167 4170  }
4168 4171  
4169 4172  void
4170 4173  vrrpd_state_b2i(vrrp_vr_t *vr)
4171 4174  {
4172 4175          vrrp_log(VRRP_DBG1, "vrrpd_state_b2i(%s)", vr->vvr_conf.vvc_name);
4173 4176  
4174 4177          bzero(&vr->vvr_peer, sizeof (vrrp_peer_t));
4175 4178          (void) iu_cancel_timer(vrrpd_timerq, vr->vvr_timer_id, NULL);
4176 4179          vrrpd_state_trans(VRRP_STATE_BACKUP, VRRP_STATE_INIT, vr);
4177 4180          (void) vrrpd_virtualip_update(vr, _B_TRUE);
4178 4181  }
4179 4182  
4180 4183  /* ARGSUSED */
4181 4184  static void
4182 4185  vrrp_b2m_timeout(iu_tq_t *tq, void *arg)
4183 4186  {
4184 4187          vrrp_vr_t *vr = (vrrp_vr_t *)arg;
4185 4188  
4186 4189          vrrp_log(VRRP_DBG1, "vrrp_b2m_timeout(%s)", vr->vvr_conf.vvc_name);
4187 4190          (void) vrrpd_state_b2m(vr);
4188 4191  }
4189 4192  
4190 4193  /* ARGSUSED */
4191 4194  static void
4192 4195  vrrp_adv_timeout(iu_tq_t *tq, void *arg)
4193 4196  {
4194 4197          vrrp_vr_t *vr = (vrrp_vr_t *)arg;
4195 4198  
4196 4199          vrrp_log(VRRP_DBG1, "vrrp_adv_timeout(%s)", vr->vvr_conf.vvc_name);
4197 4200  
4198 4201          (void) vrrpd_send_adv(vr, _B_FALSE);
4199 4202          if ((vr->vvr_timer_id = iu_schedule_timer_ms(vrrpd_timerq,
4200 4203              vr->vvr_timeout, vrrp_adv_timeout, vr)) == -1) {
4201 4204                  vrrp_log(VRRP_ERR, "vrrp_adv_timeout(%s): start timer failed",
4202 4205                      vr->vvr_conf.vvc_name);
4203 4206          } else {
4204 4207                  vrrp_log(VRRP_DBG1, "vrrp_adv_timeout(%s): start "
4205 4208                      "vrrp_adv_timeout(%d)", vr->vvr_conf.vvc_name,
4206 4209                      vr->vvr_timeout);
4207 4210          }
4208 4211  }
4209 4212  
4210 4213  vrrp_err_t
4211 4214  vrrpd_state_b2m(vrrp_vr_t *vr)
4212 4215  {
4213 4216          vrrp_err_t      err;
4214 4217  
4215 4218          vrrp_log(VRRP_DBG1, "vrrpd_state_b2m(%s)", vr->vvr_conf.vvc_name);
4216 4219  
4217 4220          vrrpd_state_trans(VRRP_STATE_BACKUP, VRRP_STATE_MASTER, vr);
4218 4221          if ((err = vrrpd_virtualip_update(vr, _B_FALSE)) != VRRP_SUCCESS)
4219 4222                  return (err);
4220 4223          (void) vrrpd_send_adv(vr, _B_FALSE);
4221 4224  
4222 4225          vr->vvr_timeout = vr->vvr_conf.vvc_adver_int;
4223 4226          if ((vr->vvr_timer_id = iu_schedule_timer_ms(vrrpd_timerq,
4224 4227              vr->vvr_timeout, vrrp_adv_timeout, vr)) == -1) {
4225 4228                  vrrp_log(VRRP_ERR, "vrrpd_state_b2m(%s): start timer failed",
4226 4229                      vr->vvr_conf.vvc_name);
4227 4230                  return (VRRP_ESYS);
4228 4231          } else {
4229 4232                  vrrp_log(VRRP_DBG1, "vrrpd_state_b2m(%s): start "
4230 4233                      "vrrp_adv_timeout(%d)", vr->vvr_conf.vvc_name,
4231 4234                      vr->vvr_timeout);
4232 4235          }
4233 4236          return (VRRP_SUCCESS);
4234 4237  }
4235 4238  
4236 4239  vrrp_err_t
4237 4240  vrrpd_state_m2b(vrrp_vr_t *vr)
4238 4241  {
4239 4242          vrrp_err_t      err;
4240 4243  
4241 4244          vrrp_log(VRRP_DBG1, "vrrpd_state_m2b(%s)", vr->vvr_conf.vvc_name);
4242 4245  
4243 4246          vrrpd_state_trans(VRRP_STATE_MASTER, VRRP_STATE_BACKUP, vr);
4244 4247          if ((err = vrrpd_virtualip_update(vr, _B_FALSE)) != VRRP_SUCCESS)
4245 4248                  return (err);
4246 4249  
4247 4250          /*
4248 4251           * Cancel the adver_timer.
4249 4252           */
4250 4253          vr->vvr_master_adver_int = vr->vvr_peer_adver_int;
4251 4254          (void) iu_cancel_timer(vrrpd_timerq, vr->vvr_timer_id, NULL);
4252 4255          vr->vvr_timeout = MASTER_DOWN_INTERVAL_VR(vr);
4253 4256          if ((vr->vvr_timer_id = iu_schedule_timer_ms(vrrpd_timerq,
4254 4257              vr->vvr_timeout, vrrp_b2m_timeout, vr)) == -1) {
4255 4258                  vrrp_log(VRRP_ERR, "vrrpd_state_m2b(%s): start timer failed",
4256 4259                      vr->vvr_conf.vvc_name);
4257 4260          } else {
4258 4261                  vrrp_log(VRRP_DBG1, "vrrpd_state_m2b(%s) start "
4259 4262                      "vrrp_b2m_timeout(%d)", vr->vvr_conf.vvc_name,
4260 4263                      vr->vvr_timeout);
4261 4264          }
4262 4265          return (VRRP_SUCCESS);
4263 4266  }
4264 4267  
4265 4268  /*
4266 4269   * Set the IFF_NOACCESS flag on the VNIC interface of the VRRP router
4267 4270   * based on its access mode.
4268 4271   */
4269 4272  static vrrp_err_t
4270 4273  vrrpd_set_noaccept(vrrp_vr_t *vr, boolean_t on)
4271 4274  {
4272 4275          vrrp_intf_t *vif = vr->vvr_vif;
4273 4276          uint64_t curr_flags;
4274 4277          struct lifreq lifr;
4275 4278          int s;
4276 4279  
4277 4280          vrrp_log(VRRP_DBG1, "vrrpd_set_noaccept(%s, %s)",
4278 4281              vr->vvr_conf.vvc_name, on ? "on" : "off");
4279 4282  
4280 4283          /*
4281 4284           * Possibly no virtual address exists on this VRRP router yet.
4282 4285           */
4283 4286          if (vif == NULL)
4284 4287                  return (VRRP_SUCCESS);
4285 4288  
4286 4289          vrrp_log(VRRP_DBG1, "vrrpd_set_noaccept(%s, %s)",
4287 4290              vif->vvi_ifname, vrrp_state2str(vr->vvr_state));
4288 4291  
4289 4292          s = (vif->vvi_af == AF_INET) ? vrrpd_ctlsock_fd : vrrpd_ctlsock6_fd;
4290 4293          (void) strncpy(lifr.lifr_name, vif->vvi_ifname,
4291 4294              sizeof (lifr.lifr_name));
4292 4295          if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
4293 4296                  if (errno != ENXIO && errno != ENOENT) {
4294 4297                          vrrp_log(VRRP_ERR, "vrrpd_set_noaccept(): "
4295 4298                              "SIOCGLIFFLAGS on %s failed: %s",
4296 4299                              vif->vvi_ifname, strerror(errno));
4297 4300                  }
4298 4301                  return (VRRP_ESYS);
4299 4302          }
4300 4303  
4301 4304          curr_flags = lifr.lifr_flags;
4302 4305          if (on)
4303 4306                  lifr.lifr_flags |= IFF_NOACCEPT;
4304 4307          else
4305 4308                  lifr.lifr_flags &= ~IFF_NOACCEPT;
4306 4309  
4307 4310          if (lifr.lifr_flags != curr_flags) {
4308 4311                  if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
4309 4312                          if (errno != ENXIO && errno != ENOENT) {
4310 4313                                  vrrp_log(VRRP_ERR, "vrrpd_set_noaccept(%s): "
4311 4314                                      "SIOCSLIFFLAGS 0x%llx on %s failed: %s",
4312 4315                                      on ? "no_accept" : "accept",
4313 4316                                      lifr.lifr_flags, vif->vvi_ifname,
4314 4317                                      strerror(errno));
4315 4318                          }
4316 4319                          return (VRRP_ESYS);
4317 4320                  }
4318 4321          }
4319 4322          return (VRRP_SUCCESS);
4320 4323  }
4321 4324  
4322 4325  static vrrp_err_t
4323 4326  vrrpd_virtualip_updateone(vrrp_intf_t *vif, vrrp_ip_t *ip, boolean_t checkonly)
4324 4327  {
4325 4328          vrrp_state_t    state = vif->vvi_vr_state;
4326 4329          struct lifreq   lifr;
4327 4330          char            abuf[INET6_ADDRSTRLEN];
4328 4331          int             af = vif->vvi_af;
4329 4332          uint64_t        curr_flags;
4330 4333          int             s;
4331 4334  
4332 4335          assert(IS_VIRTUAL_INTF(vif));
4333 4336  
4334 4337          /* LINTED E_CONSTANT_CONDITION */
4335 4338          VRRPADDR2STR(af, &ip->vip_addr, abuf, INET6_ADDRSTRLEN, _B_FALSE);
4336 4339          vrrp_log(VRRP_DBG1, "vrrpd_virtualip_updateone(%s, %s%s)",
4337 4340              vif->vvi_ifname, abuf, checkonly ? ", checkonly" : "");
4338 4341  
4339 4342          s = (af == AF_INET) ? vrrpd_ctlsock_fd : vrrpd_ctlsock6_fd;
4340 4343          (void) strncpy(lifr.lifr_name, ip->vip_lifname,
4341 4344              sizeof (lifr.lifr_name));
4342 4345          if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
4343 4346                  if (errno != ENXIO && errno != ENOENT) {
4344 4347                          vrrp_log(VRRP_ERR, "vrrpd_virtualip_updateone(%s): "
4345 4348                              "SIOCGLIFFLAGS on %s/%s failed: %s",
4346 4349                              vif->vvi_ifname, lifr.lifr_name, abuf,
4347 4350                              strerror(errno));
4348 4351                  }
4349 4352                  return (VRRP_ESYS);
4350 4353          }
4351 4354  
4352 4355          curr_flags = lifr.lifr_flags;
4353 4356          if (state == VRRP_STATE_MASTER)
4354 4357                  lifr.lifr_flags |= IFF_UP;
4355 4358          else
4356 4359                  lifr.lifr_flags &= ~IFF_UP;
4357 4360  
4358 4361          if (lifr.lifr_flags == curr_flags)
4359 4362                  return (VRRP_SUCCESS);
4360 4363  
4361 4364          if (checkonly) {
4362 4365                  vrrp_log(VRRP_ERR, "VRRP virtual IP %s/%s was brought %s",
4363 4366                      ip->vip_lifname, abuf,
4364 4367                      state == VRRP_STATE_MASTER ? "down" : "up");
4365 4368                  return (VRRP_ESYS);
4366 4369          } else if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
4367 4370                  if (errno != ENXIO && errno != ENOENT) {
4368 4371                          vrrp_log(VRRP_ERR, "vrrpd_virtualip_updateone(%s, %s): "
4369 4372                              "bring %s %s/%s failed: %s",
4370 4373                              vif->vvi_ifname, vrrp_state2str(state),
4371 4374                              state == VRRP_STATE_MASTER ? "up" : "down",
4372 4375                              ip->vip_lifname, abuf, strerror(errno));
4373 4376                  }
4374 4377                  return (VRRP_ESYS);
4375 4378          }
4376 4379          return (VRRP_SUCCESS);
4377 4380  }
4378 4381  
4379 4382  static vrrp_err_t
4380 4383  vrrpd_virtualip_update(vrrp_vr_t *vr, boolean_t checkonly)
4381 4384  {
4382 4385          vrrp_state_t            state;
4383 4386          vrrp_intf_t             *vif = vr->vvr_vif;
4384 4387          vrrp_ip_t               *ip, *nextip;
4385 4388          char                    abuf[INET6_ADDRSTRLEN];
4386 4389          vrrp_err_t              err;
4387 4390  
4388 4391          vrrp_log(VRRP_DBG1, "vrrpd_virtualip_update(%s, %s, %s)%s",
4389 4392              vr->vvr_conf.vvc_name, vrrp_state2str(vr->vvr_state),
4390 4393              vif->vvi_ifname, checkonly ? " checkonly" : "");
4391 4394  
4392 4395          state = vr->vvr_state;
4393 4396          assert(vif != NULL);
4394 4397          assert(IS_VIRTUAL_INTF(vif));
4395 4398          assert(vif->vvi_vr_state != state);
4396 4399          vif->vvi_vr_state = state;
4397 4400          for (ip = TAILQ_FIRST(&vif->vvi_iplist); ip != NULL; ip = nextip) {
4398 4401                  nextip = TAILQ_NEXT(ip, vip_next);
4399 4402                  err = vrrpd_virtualip_updateone(vif, ip, _B_FALSE);
4400 4403                  if (!checkonly && err != VRRP_SUCCESS) {
4401 4404                          /* LINTED E_CONSTANT_CONDITION */
4402 4405                          VRRPADDR2STR(vif->vvi_af, &ip->vip_addr, abuf,
4403 4406                              INET6_ADDRSTRLEN, _B_FALSE);
4404 4407                          vrrp_log(VRRP_DBG1, "vrrpd_virtualip_update() update "
4405 4408                              "%s over %s failed", abuf, vif->vvi_ifname);
4406 4409                          vrrpd_delete_ip(vif, ip);
4407 4410                  }
4408 4411          }
4409 4412  
4410 4413          /*
4411 4414           * The IP address is deleted when it is failed to be brought
4412 4415           * up. If no IP addresses are left, delete this interface.
4413 4416           */
4414 4417          if (!checkonly && TAILQ_EMPTY(&vif->vvi_iplist)) {
4415 4418                  vrrp_log(VRRP_DBG0, "vrrpd_virtualip_update(): "
4416 4419                      "no IP left over %s", vif->vvi_ifname);
4417 4420                  vrrpd_delete_if(vif, _B_TRUE);
4418 4421                  return (VRRP_ENOVIRT);
4419 4422          }
4420 4423          return (VRRP_SUCCESS);
4421 4424  }
4422 4425  
4423 4426  void
4424 4427  vrrpd_state_trans(vrrp_state_t prev_s, vrrp_state_t s, vrrp_vr_t *vr)
4425 4428  {
4426 4429          vrrp_log(VRRP_DBG1, "vrrpd_state_trans(%s): %s --> %s",
4427 4430              vr->vvr_conf.vvc_name, vrrp_state2str(prev_s), vrrp_state2str(s));
4428 4431  
4429 4432          assert(vr->vvr_state == prev_s);
4430 4433          vr->vvr_state = s;
4431 4434          vr->vvr_prev_state = prev_s;
4432 4435          (void) gettimeofday(&vr->vvr_st_time, NULL);
4433 4436          (void) vrrpd_post_event(vr->vvr_conf.vvc_name, prev_s, s);
4434 4437  }
4435 4438  
4436 4439  static int
4437 4440  vrrpd_post_event(const char *name, vrrp_state_t prev_st, vrrp_state_t st)
4438 4441  {
4439 4442          sysevent_id_t   eid;
4440 4443          nvlist_t        *nvl = NULL;
4441 4444  
4442 4445          /*
4443 4446           * sysevent is not supported in the non-global zone
4444 4447           */
4445 4448          if (getzoneid() != GLOBAL_ZONEID)
4446 4449                  return (0);
4447 4450  
4448 4451          if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
4449 4452                  goto failed;
4450 4453  
4451 4454          if (nvlist_add_uint8(nvl, VRRP_EVENT_VERSION,
4452 4455              VRRP_EVENT_CUR_VERSION) != 0)
4453 4456                  goto failed;
4454 4457  
4455 4458          if (nvlist_add_string(nvl, VRRP_EVENT_ROUTER_NAME, name) != 0)
4456 4459                  goto failed;
4457 4460  
4458 4461          if (nvlist_add_uint8(nvl, VRRP_EVENT_STATE, st) != 0)
4459 4462                  goto failed;
4460 4463  
4461 4464          if (nvlist_add_uint8(nvl, VRRP_EVENT_PREV_STATE, prev_st) != 0)
4462 4465                  goto failed;
4463 4466  
4464 4467          if (sysevent_post_event(EC_VRRP, ESC_VRRP_STATE_CHANGE,
4465 4468              SUNW_VENDOR, VRRP_EVENT_PUBLISHER, nvl, &eid) == 0) {
4466 4469                  nvlist_free(nvl);
4467 4470                  return (0);
4468 4471          }
4469 4472  
4470 4473  failed:
4471 4474          vrrp_log(VRRP_ERR, "vrrpd_post_event(): `state change (%s --> %s)' "
4472 4475              "sysevent posting failed: %s", vrrp_state2str(prev_st),
4473 4476              vrrp_state2str(st), strerror(errno));
4474 4477  
4475 4478          nvlist_free(nvl);
4476 4479          return (-1);
4477 4480  }
4478 4481  
4479 4482  /*
4480 4483   * timeval processing functions
4481 4484   */
4482 4485  static int
4483 4486  timeval_to_milli(struct timeval tv)
4484 4487  {
4485 4488          return ((int)(tv.tv_sec * 1000 + tv.tv_usec / 1000 + 0.5));
4486 4489  }
4487 4490  
4488 4491  static struct timeval
4489 4492  timeval_delta(struct timeval t1, struct timeval t2)
4490 4493  {
4491 4494          struct timeval t;
4492 4495          t.tv_sec = t1.tv_sec - t2.tv_sec;
4493 4496          t.tv_usec = t1.tv_usec - t2.tv_usec;
4494 4497  
4495 4498          if (t.tv_usec < 0) {
4496 4499                  t.tv_usec += 1000000;
4497 4500                  t.tv_sec--;
4498 4501          }
4499 4502          return (t);
4500 4503  }
4501 4504  
4502 4505  /*
4503 4506   * print error messages to the terminal or to syslog
4504 4507   */
4505 4508  static void
4506 4509  vrrp_log(int level, char *message, ...)
4507 4510  {
4508 4511          va_list ap;
4509 4512          int log_level = -1;
4510 4513  
4511 4514          va_start(ap, message);
4512 4515  
4513 4516          if (vrrp_logflag == 0) {
4514 4517                  if (level <= vrrp_debug_level) {
4515 4518                          /*
4516 4519                           * VRRP_ERR goes to stderr, others go to stdout
4517 4520                           */
4518 4521                          FILE *out = (level <= VRRP_ERR) ? stderr : stdout;
4519 4522                          (void) fprintf(out, "vrrpd: ");
4520 4523                          /* LINTED: E_SEC_PRINTF_VAR_FMT */
4521 4524                          (void) vfprintf(out, message, ap);
4522 4525                          (void) fprintf(out, "\n");
4523 4526                          (void) fflush(out);
4524 4527                  }
4525 4528                  va_end(ap);
4526 4529                  return;
4527 4530          }
4528 4531  
4529 4532          /*
4530 4533           * translate VRRP_* to LOG_*
4531 4534           */
4532 4535          switch (level) {
4533 4536          case VRRP_ERR:
4534 4537                  log_level = LOG_ERR;
4535 4538                  break;
4536 4539          case VRRP_WARNING:
4537 4540                  log_level = LOG_WARNING;
4538 4541                  break;
4539 4542          case VRRP_NOTICE:
4540 4543                  log_level = LOG_NOTICE;
4541 4544                  break;
4542 4545          case VRRP_DBG0:
4543 4546                  log_level = LOG_INFO;
4544 4547                  break;
4545 4548          default:
4546 4549                  log_level = LOG_DEBUG;
4547 4550                  break;
4548 4551          }
4549 4552  
4550 4553          /* LINTED: E_SEC_PRINTF_VAR_FMT */
4551 4554          (void) vsyslog(log_level, message, ap);
4552 4555          va_end(ap);
4553 4556  }
  
    | 
      ↓ open down ↓ | 
    4457 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX