aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/vrrp/vrrp.h
blob: c93259219598b68242ca3f6b1191af9dc6458866 (plain)
1
2
3
4
5
6
7
8
9
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
# Copyright (c) 2015 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
/*
 * vrrp.h - vrrp plug-in header file
 *
 * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 */
#ifndef __included_vrrp_h__
#define __included_vrrp_h__

#include <vnet/vnet.h>
#include <vnet/ip/ip.h>
#include <vnet/ethernet/ethernet.h>

#include <vppinfra/hash.h>
#include <vppinfra/error.h>

/* VRRP configuration */
typedef enum vrrp_vr_flags
{
  VRRP_VR_PREEMPT = 0x1,
  VRRP_VR_ACCEPT = 0x2,
  VRRP_VR_UNICAST = 0x4,
  VRRP_VR_IPV6 = 0x8,
} vrrp_vr_flags_t;

typedef struct vrrp_vr_key
{
  u32 sw_if_index;
  u8 vr_id;
  u8 is_ipv6;
} vrrp_vr_key_t;

/* *INDENT-OFF* */
typedef CLIB_PACKED
(struct vrrp4_arp_key {
  union {
    struct {
      u32 sw_if_index;
      ip4_address_t addr;
    };
    u64 as_u64;
  };
}) vrrp4_arp_key_t;
/* *INDENT-ON* */

/* *INDENT-OFF* */
typedef CLIB_PACKED
(struct vrrp6_nd_key {
  u32 sw_if_index;
  ip6_address_t addr;
}) vrrp6_nd_key_t;
/* *INDENT-ON* */

typedef struct vrrp_vr_tracking_if
{
  u32 sw_if_index;
  u8 priority;
} vrrp_vr_tracking_if_t;

typedef struct vrrp_vr_tracking
{
  vrrp_vr_tracking_if_t *interfaces;
  u32 interfaces_dec;
} vrrp_vr_tracking_t;

typedef struct vrrp_vr_config
{
  u32 sw_if_index;
  u8 vr_id;
  u8 priority;
  u16 adv_interval;
  vrrp_vr_flags_t flags;
  ip46_address_t *vr_addrs;
  ip46_address_t *peer_addrs;
} vrrp_vr_config_t;

#define foreach_vrrp_vr_state		\
_(0, INIT, "Initialize")		\
_(1, BACKUP, "Backup")			\
_(2, MASTER, "Master")			\
_(3, INTF_DOWN, "Interface Down")

/* VRRP runtime data */
typedef enum vrrp_vr_state
{
#define _(v,f,n) VRRP_VR_STATE_##f = v,
  foreach_vrrp_vr_state
#undef _
} vrrp_vr_state_t;

typedef struct vrrp_vr_runtime
{
  vrrp_vr_state_t state;
  u16 master_adv_int;
  u16 skew;
  u16 master_down_int;
  mac_address_t mac;
  f64 last_sent;
  u32 timer_index;
} vrrp_vr_runtime_t;

/* Per-VR data */
typedef struct vrrp_vr
{
  vrrp_vr_config_t config;
  vrrp_vr_runtime_t runtime;
  vrrp_vr_tracking_t tracking;
} vrrp_vr_t;

/* Timers */
typedef enum vrrp_vr_timer_type
{
  VRRP_VR_TIMER_ADV,
  VRRP_VR_TIMER_MASTER_DOWN,
} vrrp_vr_timer_type_t;

typedef struct vrrp_vr_timer
{
  u32 vr_index;
  f64 expire_time;		/* monotonic, relative to vlib_time_now() */
  vrrp_vr_timer_type_t type;
} vrrp_vr_timer_t;

typedef struct
{
  /* vectors of vr indices which are configured on this interface
   * 0 -> ipv4, 1 -> ipv6 */
  u32 *vr_indices[2];

  /* vector of VR indices which track the state of this interface
   * 0 -> ipv4, 1*/
  u32 *tracking_vrs[2];

  /* multicast adjacency indices. 0 -> ipv4, 1 -> ipv6 */
  adj_index_t mcast_adj_index[2];

  /* number of VRs in master state on sw intf. 0 -> ipv4, 1 -> ipv6 */
  u8 n_master_vrs[2];

} vrrp_intf_t;

typedef struct
{
  /* API message ID base */
  u16 msg_id_base;

  /* pool of VRs */
  vrrp_vr_t *vrs;

  /* pool of timers and ordered vector of pool indices */
  vrrp_vr_timer_t *vr_timers;
  u32 *pending_timers;

  /* number of running VRs - don't register for VRRP proto if not running */
  u16 n_vrs_started;

  /* hash mapping a VR key to a pool entry */
  mhash_t vr_index_by_key;

  /* hashes mapping sw_if_index and address to a vr index */
  uword *vrrp4_arp_lookup;
  uword *vrrp6_nd_lookup;

  /* vector of interface data indexed by sw_if_index */
  vrrp_intf_t *vrrp_intfs;

  /* convenience */
  vlib_main_t *vlib_main;
  vnet_main_t *vnet_main;
  ethernet_main_t *ethernet_main;

  u32 intf_output_node_idx;
} vrrp_main_t;

extern vrrp_main_t vrrp_main;

extern vlib_node_registration_t vrrp_node;
extern vlib_node_registration_t vrrp_periodic_node;

/* Periodic function events */
#define VRRP_EVENT_VR_TIMER_UPDATE 1
#define VRRP_EVENT_VR_STOP 2
#define VRRP_EVENT_PERIODIC_ENABLE_DISABLE 3

clib_error_t *vrrp_plugin_api_hookup (vlib_main_t * vm);

int vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t * conf);
int vrrp_vr_start_stop (u8 is_start, vrrp_vr_key_t * vr_key);
extern u8 *format_vrrp_vr (u8 * s, va_list * args);
extern u8 *format_vrrp_vr_key (u8 * s, va_list * args);
extern u8 *format_vrrp_vr_state (u8 * s, va_list * args);
extern u8 *format_vrrp_packet_hdr (u8 * s, va_list * args);
void vrrp_vr_timer_set (vrrp_vr_t * vr, vrrp_vr_timer_type_t type);
void vrrp_vr_timer_cancel (vrrp_vr_t * vr);
void vrrp_vr_transition (vrrp_vr_t * vr, vrrp_vr_state_t new_state,
			 void *data);
int vrrp_vr_set_peers (vrrp_vr_key_t * key, ip46_address_t * peers);
int vrrp_vr_multicast_group_join (vrrp_vr_t * vr);
int vrrp_adv_send (vrrp_vr_t * vr, int shutdown);
int vrrp_garp_or_na_send (vrrp_vr_t * vr);
u16 vrrp_adv_csum (void *l3_hdr, void *payload, u8 is_ipv6, u16 len);
int vrrp_vr_tracking_if_add_del (vrrp_vr_t * vr, u32 sw_if_index,
				 u8 priority, u8 is_add);
int vrrp_vr_tracking_ifs_add_del (vrrp_vr_t * vr,
				  vrrp_vr_tracking_if_t * track_ifs,
				  u8 is_add);
void vrrp_vr_event (vrrp_vr_t * vr, vrrp_vr_state_t new_state);


always_inline void
vrrp_vr_skew_compute (vrrp_vr_t * vr)
{
  vrrp_vr_config_t *vrc = &vr->config;
  vrrp_vr_runtime_t *vrt = &vr->runtime;

  vrt->skew = (((256 - vrc->priority) * vrt->master_adv_int) / 256);
}

always_inline void
vrrp_vr_master_down_compute (vrrp_vr_t * vr)
{
  vrrp_vr_runtime_t *vrt = &vr->runtime;

  vrt->master_down_int = (3 * vrt->master_adv_int) + vrt->skew;
}

always_inline vrrp_vr_t *
vrrp_vr_lookup (u32 sw_if_index, u8 vr_id, u8 is_ipv6)
{
  vrrp_main_t *vmp = &vrrp_main;
  vrrp_vr_key_t key;
  uword *p;

  clib_memset (&key, 0, sizeof (key));

  key.sw_if_index = sw_if_index;
  key.vr_id = vr_id;
  key.is_ipv6 = (is_ipv6 != 0);

  p = mhash_get (&vmp->vr_index_by_key, &key);
  if (p)
    return pool_elt_at_index (vmp->vrs, p[0]);

  return 0;
}

always_inline vrrp_vr_t *
vrrp_vr_lookup_index (u32 vr_index)
{
  vrrp_main_t *vmp = &vrrp_main;

  if (pool_is_free_index (vmp->vrs, vr_index))
    return 0;

  return pool_elt_at_index (vmp->vrs, vr_index);
}

always_inline u32
vrrp_vr_lookup_address (u32 sw_if_index, u8 is_ipv6, void *addr)
{
  vrrp_main_t *vmp = &vrrp_main;
  uword *p;
  vrrp4_arp_key_t key4;
  vrrp6_nd_key_t key6;

  if (is_ipv6)
    {
      key6.sw_if_index = sw_if_index;
      key6.addr = ((ip6_address_t *) addr)[0];
      p = hash_get_mem (vmp->vrrp6_nd_lookup, &key6);
    }
  else
    {
      key4.sw_if_index = sw_if_index;
      key4.addr = ((ip4_address_t *) addr)[0];
      p = hash_get (vmp->vrrp4_arp_lookup, key4.as_u64);
    }

  if (p)
    return p[0];

  return ~0;
}

always_inline vrrp_intf_t *
vrrp_intf_get (u32 sw_if_index)
{
  vrrp_main_t *vrm = &vrrp_main;

  if (sw_if_index == ~0)
    return NULL;

  vec_validate (vrm->vrrp_intfs, sw_if_index);
  return vec_elt_at_index (vrm->vrrp_intfs, sw_if_index);
}

always_inline int
vrrp_intf_num_vrs (u32 sw_if_index, u8 is_ipv6)
{
  vrrp_intf_t *intf = vrrp_intf_get (sw_if_index);

  if (intf)
    return vec_len (intf->vr_indices[is_ipv6]);

  return 0;
}

always_inline u8
vrrp_vr_is_ipv6 (vrrp_vr_t * vr)
{
  return ((vr->config.flags & VRRP_VR_IPV6) != 0);
}

always_inline u8
vrrp_vr_is_unicast (vrrp_vr_t * vr)
{
  return ((vr->config.flags & VRRP_VR_UNICAST) != 0);
}

always_inline u8
vrrp_vr_is_owner (vrrp_vr_t * vr)
{
  return (vr->config.priority == 255);
}

always_inline u8
vrrp_vr_n_vr_addrs (vrrp_vr_t * vr)
{
  return vec_len (vr->config.vr_addrs);
}

always_inline u8
vrrp_vr_n_peer_addrs (vrrp_vr_t * vr)
{
  return vec_len (vr->config.peer_addrs);
}

always_inline u8
vrrp_vr_accept_mode_enabled (vrrp_vr_t * vr)
{
  return ((vr->config.flags & VRRP_VR_ACCEPT) != 0);
}

always_inline u32
vrrp_vr_index (vrrp_vr_t * vr)
{
  vrrp_main_t *vmp = &vrrp_main;

  return vr - vmp->vrs;
}

always_inline u8
vrrp_vr_priority (vrrp_vr_t * vr)
{
  u8 rv;

  if (vr->tracking.interfaces_dec < (u32) vr->config.priority)
    rv = vr->config.priority - vr->tracking.interfaces_dec;
  else
    rv = 1;

  return rv;
}

#endif /* __included_vrrp_h__ */

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */