aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/vrrp/vrrp.h
blob: c93259219598b68242ca3f6b1191af9dc6458866 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151<
/*
 *------------------------------------------------------------------
 * Copyright (c) 2009 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.
 *------------------------------------------------------------------
 */

#ifndef __included_svm_common_h__
#define __included_svm_common_h__

#include <stdarg.h>
#include <pthread.h>
#include <vppinfra/types.h>

#define SVM_VERSION ((1<<16) | 1)	/* set to declare region ready. */

#define SVM_FLAGS_MHEAP (1<<0)	/* region contains an mheap */
#define SVM_FLAGS_FILE  (1<<1)	/* region backed by one or more files */
#define SVM_FLAGS_NODATA (1<<2)	/* region will be further subdivided */
#define SVM_FLAGS_NEED_DATA_INIT (1<<3)

#define SVM_PVT_MHEAP_SIZE (128<<10)	/* region's private mheap (128k) */

typedef struct svm_region_
{
  volatile uword version;
  pthread_mutex_t mutex;
  pthread_cond_t condvar;
  int .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 */
/*
 * 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:
 */