diff options
Diffstat (limited to 'src/plugins/vrrp')
-rw-r--r-- | src/plugins/vrrp/node.c | 60 | ||||
-rw-r--r-- | src/plugins/vrrp/setup.pg | 20 | ||||
-rw-r--r-- | src/plugins/vrrp/vrrp.api | 51 | ||||
-rw-r--r-- | src/plugins/vrrp/vrrp.c | 321 | ||||
-rw-r--r-- | src/plugins/vrrp/vrrp.h | 47 | ||||
-rw-r--r-- | src/plugins/vrrp/vrrp_all_api_h.h | 11 | ||||
-rw-r--r-- | src/plugins/vrrp/vrrp_api.c | 114 | ||||
-rw-r--r-- | src/plugins/vrrp/vrrp_cli.c | 20 | ||||
-rw-r--r-- | src/plugins/vrrp/vrrp_msg_enum.h | 23 | ||||
-rw-r--r-- | src/plugins/vrrp/vrrp_packet.c | 36 | ||||
-rw-r--r-- | src/plugins/vrrp/vrrp_packet.h | 9 | ||||
-rw-r--r-- | src/plugins/vrrp/vrrp_periodic.c | 2 | ||||
-rw-r--r-- | src/plugins/vrrp/vrrp_test.c | 173 |
13 files changed, 739 insertions, 148 deletions
diff --git a/src/plugins/vrrp/node.c b/src/plugins/vrrp/node.c index 7ba18c4f75c..d5594ae0e43 100644 --- a/src/plugins/vrrp/node.c +++ b/src/plugins/vrrp/node.c @@ -86,22 +86,16 @@ typedef enum VRRP_INPUT_N_NEXT, } vrrp_next_t; -typedef struct vrrp_input_process_args -{ - u32 vr_index; - vrrp_header_t *pkt; -} vrrp_input_process_args_t; - /* Given a VR and a pointer to the VRRP header of an incoming packet, * compare the local src address to the peers. Return < 0 if the local * address < the peer address, 0 if they're equal, > 0 if * the local address > the peer address */ static int -vrrp_vr_addr_cmp (vrrp_vr_t * vr, vrrp_header_t * pkt) +vrrp_vr_addr_cmp (vrrp_vr_t *vr, ip46_address_t *peer_addr) { vrrp_vr_config_t *vrc = &vr->config; - void *peer_addr, *local_addr; + void *peer_addr_bytes, *local_addr; ip46_address_t addr; int addr_size; @@ -109,7 +103,7 @@ vrrp_vr_addr_cmp (vrrp_vr_t * vr, vrrp_header_t * pkt) if (vrrp_vr_is_ipv6 (vr)) { - peer_addr = &(((ip6_header_t *) pkt) - 1)->src_address; + peer_addr_bytes = &peer_addr->ip6; local_addr = &addr.ip6; addr_size = 16; ip6_address_copy (local_addr, @@ -117,25 +111,26 @@ vrrp_vr_addr_cmp (vrrp_vr_t * vr, vrrp_header_t * pkt) } else { - peer_addr = &(((ip4_header_t *) pkt) - 1)->src_address; + peer_addr_bytes = &peer_addr->ip4; local_addr = &addr.ip4; addr_size = 4; fib_sas4_get (vrc->sw_if_index, NULL, local_addr); } - return memcmp (local_addr, peer_addr, addr_size); + return memcmp (local_addr, peer_addr_bytes, addr_size); } static void -vrrp_input_process_master (vrrp_vr_t * vr, vrrp_header_t * pkt) +vrrp_input_process_master (vrrp_vr_t *vr, vrrp_input_process_args_t *args) { /* received priority 0, another VR is shutting down. send an adv and * remain in the master state */ - if (pkt->priority == 0) + if (args->priority == 0) { clib_warning ("Received shutdown message from a peer on VR %U", format_vrrp_vr_key, vr); + vrrp_incr_stat_counter (VRRP_STAT_COUNTER_PRIO0_RCVD, vr->stat_index); vrrp_adv_send (vr, 0); vrrp_vr_timer_set (vr, VRRP_VR_TIMER_ADV); return; @@ -146,11 +141,11 @@ vrrp_input_process_master (vrrp_vr_t * vr, vrrp_header_t * pkt) * - received priority == adjusted priority and peer addr > local addr * allow the local VR to be preempted by the peer */ - if ((pkt->priority > vrrp_vr_priority (vr)) || - ((pkt->priority == vrrp_vr_priority (vr)) && - (vrrp_vr_addr_cmp (vr, pkt) < 0))) + if ((args->priority > vrrp_vr_priority (vr)) || + ((args->priority == vrrp_vr_priority (vr)) && + (vrrp_vr_addr_cmp (vr, &args->src_addr) < 0))) { - vrrp_vr_transition (vr, VRRP_VR_STATE_BACKUP, pkt); + vrrp_vr_transition (vr, VRRP_VR_STATE_BACKUP, args); return; } @@ -163,16 +158,17 @@ vrrp_input_process_master (vrrp_vr_t * vr, vrrp_header_t * pkt) /* RFC 5798 section 6.4.2 */ static void -vrrp_input_process_backup (vrrp_vr_t * vr, vrrp_header_t * pkt) +vrrp_input_process_backup (vrrp_vr_t *vr, vrrp_input_process_args_t *args) { vrrp_vr_config_t *vrc = &vr->config; vrrp_vr_runtime_t *vrt = &vr->runtime; /* master shutting down, ready for election */ - if (pkt->priority == 0) + if (args->priority == 0) { clib_warning ("Master for VR %U is shutting down", format_vrrp_vr_key, vr); + vrrp_incr_stat_counter (VRRP_STAT_COUNTER_PRIO0_RCVD, vr->stat_index); vrt->master_down_int = vrt->skew; vrrp_vr_timer_set (vr, VRRP_VR_TIMER_MASTER_DOWN); return; @@ -180,10 +176,9 @@ vrrp_input_process_backup (vrrp_vr_t * vr, vrrp_header_t * pkt) /* no preempt set or adv from a higher priority router, update timers */ if (!(vrc->flags & VRRP_VR_PREEMPT) || - (pkt->priority >= vrrp_vr_priority (vr))) + (args->priority >= vrrp_vr_priority (vr))) { - vrt->master_adv_int = clib_net_to_host_u16 (pkt->rsvd_and_max_adv_int); - vrt->master_adv_int &= ((u16) 0x0fff); /* ignore rsvd bits */ + vrt->master_adv_int = args->max_adv_int; vrrp_vr_skew_compute (vr); vrrp_vr_master_down_compute (vr); @@ -208,19 +203,21 @@ vrrp_input_process (vrrp_input_process_args_t * args) return; } + vrrp_incr_stat_counter (VRRP_STAT_COUNTER_ADV_RCVD, vr->stat_index); + switch (vr->runtime.state) { case VRRP_VR_STATE_INIT: return; case VRRP_VR_STATE_BACKUP: /* this is usually the only state an advertisement should be received */ - vrrp_input_process_backup (vr, args->pkt); + vrrp_input_process_backup (vr, args); break; case VRRP_VR_STATE_MASTER: /* might be getting preempted. or have a misbehaving peer */ clib_warning ("Received advertisement for master VR %U", format_vrrp_vr_key, vr); - vrrp_input_process_master (vr, args->pkt); + vrrp_input_process_master (vr, args); break; default: clib_warning ("Received advertisement for VR %U in unknown state %d", @@ -489,7 +486,6 @@ VLIB_NODE_FN (vrrp4_arp_input_node) (vlib_main_t * vm, return vrrp_arp_nd_input_inline (vm, node, frame, 0 /* is_ipv6 */ ); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (vrrp4_arp_input_node) = { .name = "vrrp4-arp-input", @@ -522,7 +518,6 @@ VLIB_NODE_FN (vrrp6_nd_input_node) (vlib_main_t * vm, return vrrp_arp_nd_input_inline (vm, node, frame, 1 /* is_ipv6 */); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (vrrp6_nd_input_node) = { .name = "vrrp6-nd-input", @@ -586,6 +581,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, addr_len = 16; payload_len0 = clib_net_to_host_u16 (ip6->payload_length); vlib_buffer_advance (b0, sizeof (*ip6)); + clib_memcpy_fast (&args0.src_addr.ip6, &ip6->src_address, addr_len); } else { @@ -596,6 +592,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, addr_len = 4; payload_len0 = clib_net_to_host_u16 (ip4->length) - sizeof(*ip4); vlib_buffer_advance (b0, sizeof (*ip4)); + clib_memcpy_fast (&args0.src_addr.ip4, &ip4->src_address, addr_len); } next0 = VRRP_INPUT_NEXT_DROP; @@ -612,6 +609,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (*ttl0 != 255) { error0 = VRRP_ERROR_BAD_TTL; + vrrp_incr_err_counter (VRRP_ERR_COUNTER_TTL); goto trace; } @@ -619,6 +617,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if ((vrrp0->vrrp_version_and_type >> 4) != 3) { error0 = VRRP_ERROR_NOT_VERSION_3; + vrrp_incr_err_counter (VRRP_ERR_COUNTER_VERSION); goto trace; } @@ -627,6 +626,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, ((u32) vrrp0->n_addrs) * addr_len) { error0 = VRRP_ERROR_INCOMPLETE_PKT; + vrrp_incr_err_counter (VRRP_ERR_COUNTER_PKT_LEN); goto trace; } @@ -634,6 +634,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (rx_csum0 != vrrp_adv_csum (ip0, vrrp0, is_ipv6, payload_len0)) { error0 = VRRP_ERROR_BAD_CHECKSUM; + vrrp_incr_err_counter (VRRP_ERR_COUNTER_CHKSUM); goto trace; } @@ -643,6 +644,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vrrp0->vr_id, is_ipv6))) { error0 = VRRP_ERROR_UNKNOWN_VR; + vrrp_incr_err_counter (VRRP_ERR_COUNTER_VRID); goto trace; } @@ -651,12 +653,14 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (vrrp0->n_addrs != vec_len (vr0->config.vr_addrs)) { error0 = VRRP_ERROR_ADDR_MISMATCH; + vrrp_incr_err_counter (VRRP_ERR_COUNTER_ADDR_LIST); goto trace; } /* signal main thread to process contents of packet */ args0.vr_index = vr0 - vmp->vrs; - args0.pkt = vrrp0; + args0.priority = vrrp0->priority; + args0.max_adv_int = vrrp_adv_int_from_packet (vrrp0); vl_api_rpc_call_main_thread (vrrp_input_process, (u8 *) &args0, sizeof (args0)); @@ -693,7 +697,6 @@ VLIB_NODE_FN (vrrp4_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node, return vrrp_input_inline (vm, node, frame, 0); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (vrrp4_input_node) = { .name = "vrrp4-input", @@ -1098,7 +1101,6 @@ vrrp_input_init (vlib_main_t *vm) VLIB_INIT_FUNCTION (vrrp_input_init); -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/vrrp/setup.pg b/src/plugins/vrrp/setup.pg index 9275fcc46c6..6328448d79e 100644 --- a/src/plugins/vrrp/setup.pg +++ b/src/plugins/vrrp/setup.pg @@ -7,14 +7,14 @@ set int state loop0 up comment { Packet generator script. Src MAC 00:de:ad:be:ef:01 } comment { Dst mac 01:ba:db:ab:be:01 ethtype 0800 } -packet-generator new { - name simple - limit 1 - size 128-128 - interface loop0 - node vrrp - data { - hex 0x00deadbeef0001badbabbe010800 - incrementing 30 - } +packet-generator new { \ + name simple \ + limit 1 \ + size 128-128 \ + interface loop0 \ + node vrrp \ + data { \ + hex 0x00deadbeef0001badbabbe010800 \ + incrementing 30 \ + } \ } diff --git a/src/plugins/vrrp/vrrp.api b/src/plugins/vrrp/vrrp.api index a34b06ffc57..03193e99a2c 100644 --- a/src/plugins/vrrp/vrrp.api +++ b/src/plugins/vrrp/vrrp.api @@ -5,7 +5,7 @@ * */ -option version = "1.0.1"; +option version = "1.1.1"; import "vnet/interface_types.api"; import "vnet/ip/ip_types.api"; @@ -60,6 +60,55 @@ autoreply define vrrp_vr_add_del { vl_api_address_t addrs[n_addrs]; }; +/** @brief Replace an existing VRRP virtual router in-place or create a new one + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param vrrp_index - an existing VRRP entry to replace, or 0xffffffff to crate a new one + @param sw_if_index - interface backed up by this vr + @param vr_id - the VR ID advertised by this vr + @param priority - the priority advertised for this vr + @param interval - interval between advertisements in centiseconds + @param flags - bit flags for booleans - preempt, accept, unicast, ipv6 + @param n_addrs - number of addresses being backed up by this vr + @param addrs - the addresses backed up by this vr +*/ +define vrrp_vr_update { + u32 client_index; + u32 context; + u32 vrrp_index; + vl_api_interface_index_t sw_if_index; + u8 vr_id; + u8 priority; + u16 interval; + vl_api_vrrp_vr_flags_t flags; + u8 n_addrs; + vl_api_address_t addrs[n_addrs]; +}; + +/** + * @brief Reply to a VRRP add/replace + * @param context - returned sender context, to match reply w/ request + * @param vrrp_index - index of the updated or newly created VRRP instance + * @param retval 0 - no error + */ +define vrrp_vr_update_reply { + u32 context; + i32 retval; + u32 vrrp_index; +}; + +/** + * @brief Delete an existing VRRP instance + * @param client_index - opaque cookie to identify the sender + * @param context - returned sender context, to match reply w/ request + * @param vrrp_index - index of the VRRP instance to delete + */ +autoreply define vrrp_vr_del { + u32 client_index; + u32 context; + u32 vrrp_index; +}; + /** \brief VRRP: dump virtual router data @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/plugins/vrrp/vrrp.c b/src/plugins/vrrp/vrrp.c index 5ee011cceb1..fb0659605c7 100644 --- a/src/plugins/vrrp/vrrp.c +++ b/src/plugins/vrrp/vrrp.c @@ -32,6 +32,97 @@ static const mac_address_t ipv6_vmac = { .bytes = {0x00, 0x00, 0x5e, 0x00, 0x02, 0x00} }; +vlib_simple_counter_main_t vrrp_errs[] = { + /* Total number of VRRP packets received with invalid checksum */ + { + .name = "CHKSUM_ERRS", + .stat_segment_name = "/net/vrrp/chksum-errs", + }, + /* Total number of VRRP packets received with unknown or unsupported version + */ + { + .name = "VERSION_ERRS", + .stat_segment_name = "/net/vrrp/version-errs", + }, + /* Total number of VRRP packets received with invalid VRID */ + { + .name = "VRID_ERRS", + .stat_segment_name = "/net/vrrp/vrid-errs", + }, + /* Total number of VRRP packets received with TTL/Hop limit != 255 */ + { + .name = "TTL_ERRS", + .stat_segment_name = "/net/vrrp/ttl-errs", + }, + /* Number of packets received with an address list not matching the locally + configured one */ + { + .name = "ADDR_LIST_ERRS", + .stat_segment_name = "/net/vrrp/addr-list-errs", + }, + /* Number of packets received with a length less than the VRRP header */ + { + .name = "PACKET_LEN_ERRS", + .stat_segment_name = "/net/vrrp/packet-len-errs", + }, +}; + +void +vrrp_incr_err_counter (vrrp_err_counter_t err_type) +{ + if (err_type >= VRRP_ERR_COUNTER_MAX) + { + clib_warning ("Attempt to increse error counter of unknown type %u", + err_type); + return; + } + vlib_increment_simple_counter (&vrrp_errs[err_type], + vlib_get_main ()->thread_index, 0, 1); +} + +// per-VRRP statistics + +/* Number of times a VRRP instance has transitioned to master */ +vlib_simple_counter_main_t vrrp_stats[] = { + { + .name = "MASTER_TRANS", + .stat_segment_name = "/net/vrrp/master-trans", + }, + /* Number of VRRP advertisements sent by a VRRP instance */ + { + .name = "ADV_SENT", + .stat_segment_name = "/net/vrrp/adv-sent", + }, + /* Number of VRRP advertisements received by a VRRP instance */ + { + .name = "ADV_RCVD", + .stat_segment_name = "/net/vrrp/adv-rcvd", + }, + /* Number of VRRP priority-0 packets sent by a VRRP instance */ + { + .name = "PRIO0_SENT", + .stat_segment_name = "/net/vrrp/prio0-sent", + }, + /* Number of VRRP priority-0 packets received by a VRRP instance */ + { + .name = "PRIO0_RCVD", + .stat_segment_name = "/net/vrrp/prio0-rcvd", + }, +}; + +void +vrrp_incr_stat_counter (vrrp_stat_counter_t stat_type, u32 stat_index) +{ + if (stat_type >= VRRP_STAT_COUNTER_MAX) + { + clib_warning ("Attempt to increse stat counter of unknown type %u", + stat_type); + return; + } + vlib_increment_simple_counter ( + &vrrp_stats[stat_type], vlib_get_main ()->thread_index, stat_index, 1); +} + typedef struct { vrrp_vr_key_t key; @@ -227,9 +318,6 @@ vrrp_vr_transition_addrs (vrrp_vr_t * vr, vrrp_vr_state_t new_state) if (vrrp_vr_is_owner (vr)) return; - if (vrrp_vr_is_unicast (vr)) - return; - /* only need to do something if entering or leaving master state */ if ((vr->runtime.state != VRRP_VR_STATE_MASTER) && (new_state != VRRP_VR_STATE_MASTER)) @@ -293,6 +381,7 @@ vrrp_vr_transition (vrrp_vr_t * vr, vrrp_vr_state_t new_state, void *data) if (new_state == VRRP_VR_STATE_MASTER) { + vrrp_incr_stat_counter (VRRP_STAT_COUNTER_MASTER_TRANS, vr->stat_index); /* RFC 5798 sec 6.4.1 (105) - startup event for VR with priority 255 * sec 6.4.2 (365) - master down timer fires on backup VR */ @@ -313,9 +402,10 @@ vrrp_vr_transition (vrrp_vr_t * vr, vrrp_vr_state_t new_state, void *data) if (vr->runtime.state == VRRP_VR_STATE_MASTER) { - vrrp_header_t *pkt = data; - vr->runtime.master_adv_int = vrrp_adv_int_from_packet (pkt); + vrrp_input_process_args_t *args = data; + if (args) + vr->runtime.master_adv_int = args->max_adv_int; } else /* INIT, INTF_DOWN */ vr->runtime.master_adv_int = vr->config.adv_interval; @@ -384,10 +474,9 @@ static int vrrp_intf_enable_disable_mcast (u8 enable, u32 sw_if_index, u8 is_ipv6) { vrrp_main_t *vrm = &vrrp_main; - vrrp_vr_t *vr; vrrp_intf_t *intf; - u32 fib_index; - u32 n_vrs = 0; + u32 fib_index, i; + u32 n_vrs_in_fib = 0; const mfib_prefix_t *vrrp_prefix; fib_protocol_t proto; vnet_link_t link_type; @@ -422,30 +511,29 @@ vrrp_intf_enable_disable_mcast (u8 enable, u32 sw_if_index, u8 is_ipv6) via_itf.frp_proto = fib_proto_to_dpo (proto); fib_index = mfib_table_get_index_for_sw_if_index (proto, sw_if_index); - /* *INDENT-OFF* */ - pool_foreach (vr, vrm->vrs) - { - if (vrrp_vr_is_ipv6 (vr) == is_ipv6) - n_vrs++; - } - /* *INDENT-ON* */ + vec_foreach_index (i, vrm->vrrp_intfs) + { + if (mfib_table_get_index_for_sw_if_index (proto, i) != fib_index) + continue; + + n_vrs_in_fib += vrrp_intf_num_vrs (i, is_ipv6); + } if (enable) { - /* If this is the first VR configured, add the local mcast routes */ - if (n_vrs == 1) - mfib_table_entry_path_update (fib_index, vrrp_prefix, MFIB_SOURCE_API, - &for_us); + /* ensure that the local mcast route exists */ + mfib_table_entry_path_update (fib_index, vrrp_prefix, MFIB_SOURCE_API, + MFIB_ENTRY_FLAG_NONE, &for_us); mfib_table_entry_path_update (fib_index, vrrp_prefix, MFIB_SOURCE_API, - &via_itf); + MFIB_ENTRY_FLAG_NONE, &via_itf); intf->mcast_adj_index[! !is_ipv6] = adj_mcast_add_or_lock (proto, link_type, sw_if_index); } else { /* Remove mcast local routes if this is the last VR being deleted */ - if (n_vrs == 0) + if (n_vrs_in_fib == 0) mfib_table_entry_path_remove (fib_index, vrrp_prefix, MFIB_SOURCE_API, &for_us); @@ -509,7 +597,7 @@ vrrp_vr_valid_addrs_owner (vrrp_vr_config_t * vr_conf) } static int -vrrp_vr_valid_addrs_unused (vrrp_vr_config_t * vr_conf) +vrrp_vr_valid_addrs_unused (vrrp_vr_config_t *vr_conf, index_t vrrp_index) { ip46_address_t *vr_addr; u8 is_ipv6 = (vr_conf->flags & VRRP_VR_IPV6) != 0; @@ -521,7 +609,7 @@ vrrp_vr_valid_addrs_unused (vrrp_vr_config_t * vr_conf) addr = (is_ipv6) ? (void *) &vr_addr->ip6 : (void *) &vr_addr->ip4; vr_index = vrrp_vr_lookup_address (vr_conf->sw_if_index, is_ipv6, addr); - if (vr_index != ~0) + if (vr_index != ~0 && vrrp_index != vr_index) return VNET_API_ERROR_ADDRESS_IN_USE; } @@ -529,7 +617,7 @@ vrrp_vr_valid_addrs_unused (vrrp_vr_config_t * vr_conf) } static int -vrrp_vr_valid_addrs (vrrp_vr_config_t * vr_conf) +vrrp_vr_valid_addrs (vrrp_vr_config_t *vr_conf, index_t vrrp_index) { int ret = 0; @@ -539,7 +627,7 @@ vrrp_vr_valid_addrs (vrrp_vr_config_t * vr_conf) return ret; /* make sure no other VR has already configured any of the VR addresses */ - ret = vrrp_vr_valid_addrs_unused (vr_conf); + ret = vrrp_vr_valid_addrs_unused (vr_conf, vrrp_index); return ret; } @@ -574,7 +662,7 @@ vrrp_vr_addr_add_del (vrrp_vr_t * vr, u8 is_add, ip46_address_t * vr_addr) { if (!ip46_address_cmp (addr, vr_addr)) { - vec_del1 (vr->config.vr_addrs, vr->config.vr_addrs - addr); + vec_del1 (vr->config.vr_addrs, addr - vr->config.vr_addrs); break; } } @@ -596,7 +684,7 @@ vrrp_vr_addr_add_del (vrrp_vr_t * vr, u8 is_add, ip46_address_t * vr_addr) { if (!ip46_address_cmp (addr, vr_addr)) { - vec_del1 (vr->config.vr_addrs, vr->config.vr_addrs - addr); + vec_del1 (vr->config.vr_addrs, addr - vr->config.vr_addrs); break; } } @@ -617,9 +705,153 @@ vrrp_vr_addrs_add_del (vrrp_vr_t * vr, u8 is_add, ip46_address_t * vr_addrs) } } +int +vrrp_vr_update (index_t *vrrp_index, vrrp_vr_config_t *vr_conf) +{ + index_t index = *vrrp_index; + vrrp_main_t *vrm = &vrrp_main; + vrrp_vr_t *vr = NULL; + vrrp_vr_key_t key = { 0 }; + uint8_t must_restart = 0; + int ret = 0; + + /* no valid index -> create and return allocated index */ + if (index == INDEX_INVALID) + { + return vrrp_vr_add_del (1, vr_conf, vrrp_index); + } + /* update: lookup vrrp instance */ + if (pool_is_free_index (vrm->vrs, index)) + return (VNET_API_ERROR_NO_SUCH_ENTRY); + + /* fetch existing VR */ + vr = pool_elt_at_index (vrm->vrs, index); + + /* populate key */ + key.vr_id = vr->config.vr_id; + key.is_ipv6 = !!(vr->config.flags & VRRP_VR_IPV6); + ; + key.sw_if_index = vr->config.sw_if_index; + + /* Do not allow changes to the keys of the VRRP instance */ + if (vr_conf->vr_id != key.vr_id || vr_conf->sw_if_index != key.sw_if_index || + !!(vr_conf->flags & VRRP_VR_IPV6) != key.is_ipv6) + { + clib_warning ("Attempt to change VR ID, IP version or interface index " + "for VRRP instance with index %u", + index); + return VNET_API_ERROR_INVALID_ARGUMENT; + } + + /* were IPvX addresses included ? */ + if (!vec_len (vr_conf->vr_addrs)) + { + clib_warning ("Conf of VR %u for IPv%d on sw_if_index %u " + " does not contain IP addresses", + key.vr_id, key.is_ipv6 ? 6 : 4, key.sw_if_index); + return VNET_API_ERROR_INVALID_SRC_ADDRESS; + } + + /* Make sure the addresses are ok to use */ + if ((ret = vrrp_vr_valid_addrs (vr_conf, index)) < 0) + return ret; + + /* stop it if needed */ + must_restart = (vr->runtime.state != VRRP_VR_STATE_INIT); + if (must_restart) + vrrp_vr_start_stop (0, &key); + + /* overwrite new config */ + vr->config.priority = vr_conf->priority; + vr->config.adv_interval = vr_conf->adv_interval; + vr->config.flags = vr_conf->flags; + + /* check if any address has changed */ + ip46_address_t *vr_addr, *conf_addr; + uint8_t found; + vec_foreach (vr_addr, vr->config.vr_addrs) + { + found = 0; + vec_foreach (conf_addr, vr_conf->vr_addrs) + { + if (ip46_address_is_equal (vr_addr, conf_addr)) + { + found = 1; + break; + } + } + if (!found) + { + vrrp_vr_addr_add_del (vr, 0, vr_addr); + } + } + vec_foreach (conf_addr, vr_conf->vr_addrs) + { + found = 0; + vec_foreach (vr_addr, vr->config.vr_addrs) + { + if (ip46_address_is_equal (vr_addr, conf_addr)) + { + found = 1; + break; + } + } + if (!found) + { + vrrp_vr_addr_add_del (vr, 1, conf_addr); + } + } + + /* restart it if needed */ + if (must_restart) + vrrp_vr_start_stop (1, &key); + + return 0; +} + +static void +vrrp_vr_del_common (vrrp_vr_t *vr, vrrp_vr_key_t *key) +{ + vrrp_main_t *vrm = &vrrp_main; + ip46_address_t *vr_addrs_del_copy; + + vrrp_vr_timer_cancel (vr); + vrrp_vr_tracking_ifs_add_del (vr, vr->tracking.interfaces, 0); + vr_addrs_del_copy = vec_dup (vr->config.vr_addrs); + vrrp_vr_addrs_add_del (vr, 0, vr_addrs_del_copy); + mhash_unset (&vrm->vr_index_by_key, key, 0); + vec_free (vr_addrs_del_copy); + vec_free (vr->config.peer_addrs); + vec_free (vr->config.vr_addrs); + vec_free (vr->tracking.interfaces); + pool_put (vrm->vrs, vr); +} + +int +vrrp_vr_del (index_t vrrp_index) +{ + vrrp_main_t *vrm = &vrrp_main; + vrrp_vr_key_t key; + vrrp_vr_t *vr = 0; + + if (pool_is_free_index (vrm->vrs, vrrp_index)) + { + return (VNET_API_ERROR_NO_SUCH_ENTRY); + } + else + { + vr = pool_elt_at_index (vrm->vrs, vrrp_index); + key.sw_if_index = vr->config.sw_if_index; + key.vr_id = vr->config.vr_id; + key.is_ipv6 = vrrp_vr_is_ipv6 (vr); + vrrp_vr_del_common (vr, &key); + return 0; + } +} + /* Action function shared between message handler and debug CLI */ int -vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t * vr_conf) +vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t *vr_conf, index_t *ret_index) { vrrp_main_t *vrm = &vrrp_main; vnet_main_t *vnm = vnet_get_main (); @@ -661,7 +893,7 @@ vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t * vr_conf) } /* Make sure the addresses are ok to use */ - if ((ret = vrrp_vr_valid_addrs (vr_conf)) < 0) + if ((ret = vrrp_vr_valid_addrs (vr_conf, INDEX_INVALID)) < 0) return ret; pool_get_zero (vrm->vrs, vr); @@ -679,6 +911,20 @@ vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t * vr_conf) vr->runtime.mac = (key.is_ipv6) ? ipv6_vmac : ipv4_vmac; vr->runtime.mac.bytes[5] = vr_conf->vr_id; + /* recall pool index for stats */ + vr->stat_index = vr_index; + /* and return it if we were asked to */ + if (ret_index != NULL) + { + *ret_index = vr_index; + } + /* allocate & reset stats */ + for (int i = 0; i < VRRP_STAT_COUNTER_MAX; i++) + { + vlib_validate_simple_counter (&vrrp_stats[i], vr_index); + vlib_zero_simple_counter (&vrrp_stats[i], vr_index); + } + mhash_set (&vrm->vr_index_by_key, &key, vr_index, 0); } else @@ -692,13 +938,7 @@ vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t * vr_conf) vr_index = p[0]; vr = pool_elt_at_index (vrm->vrs, vr_index); - - vrrp_vr_tracking_ifs_add_del (vr, vr->tracking.interfaces, is_add); - vrrp_vr_addrs_add_del (vr, is_add, vr->config.vr_addrs); - mhash_unset (&vrm->vr_index_by_key, &key, 0); - vec_free (vr->config.vr_addrs); - vec_free (vr->tracking.interfaces); - pool_put (vrm->vrs, vr); + vrrp_vr_del_common (vr, &key); } vrrp_intf_vr_add_del (is_add, vr_conf->sw_if_index, vr_index, key.is_ipv6); @@ -1266,19 +1506,24 @@ vrrp_init (vlib_main_t * vm) vrrp_ip6_delegate_id = ip6_link_delegate_register (&vrrp_ip6_delegate_vft); + /* allocate & reset error counters */ + for (int i = 0; i < VRRP_ERR_COUNTER_MAX; i++) + { + vlib_validate_simple_counter (&vrrp_errs[i], 0); + vlib_zero_simple_counter (&vrrp_errs[i], 0); + } + return error; } VLIB_INIT_FUNCTION (vrrp_init); -/* *INDENT-OFF* */ VLIB_PLUGIN_REGISTER () = { .version = VPP_BUILD_VER, .description = "VRRP v3 (RFC 5798)", }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/vrrp/vrrp.h b/src/plugins/vrrp/vrrp.h index c9325921959..acab7440ead 100644 --- a/src/plugins/vrrp/vrrp.h +++ b/src/plugins/vrrp/vrrp.h @@ -33,7 +33,6 @@ typedef struct vrrp_vr_key u8 is_ipv6; } vrrp_vr_key_t; -/* *INDENT-OFF* */ typedef CLIB_PACKED (struct vrrp4_arp_key { union { @@ -44,15 +43,12 @@ typedef CLIB_PACKED 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 { @@ -108,6 +104,7 @@ typedef struct vrrp_vr vrrp_vr_config_t config; vrrp_vr_runtime_t runtime; vrrp_vr_tracking_t tracking; + u32 stat_index; } vrrp_vr_t; /* Timers */ @@ -185,9 +182,46 @@ extern vlib_node_registration_t vrrp_periodic_node; #define VRRP_EVENT_VR_STOP 2 #define VRRP_EVENT_PERIODIC_ENABLE_DISABLE 3 +/* global error counter types */ +#define foreach_vrrp_err_counter \ + _ (CHKSUM, 0) \ + _ (VERSION, 1) \ + _ (VRID, 2) \ + _ (TTL, 3) \ + _ (ADDR_LIST, 4) \ + _ (PKT_LEN, 5) + +typedef enum vrrp_err_counter_ +{ +#define _(sym, val) VRRP_ERR_COUNTER_##sym = val, + foreach_vrrp_err_counter +#undef _ +} vrrp_err_counter_t; + +#define VRRP_ERR_COUNTER_MAX 6 + +/* per-instance stats */ +#define foreach_vrrp_stat_counter \ + _ (MASTER_TRANS, 0) \ + _ (ADV_SENT, 1) \ + _ (ADV_RCVD, 2) \ + _ (PRIO0_SENT, 3) \ + _ (PRIO0_RCVD, 4) + +typedef enum vrrp_stat_counter_ +{ +#define _(sym, val) VRRP_STAT_COUNTER_##sym = val, + foreach_vrrp_stat_counter +#undef _ +} vrrp_stat_counter_t; + +#define VRRP_STAT_COUNTER_MAX 5 + 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_add_del (u8 is_add, vrrp_vr_config_t *conf, index_t *ret_index); +int vrrp_vr_update (index_t *vrrp_index, vrrp_vr_config_t *vr_conf); +int vrrp_vr_del (index_t vrrp_index); 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); @@ -209,6 +243,9 @@ int vrrp_vr_tracking_ifs_add_del (vrrp_vr_t * vr, u8 is_add); void vrrp_vr_event (vrrp_vr_t * vr, vrrp_vr_state_t new_state); +// stats +void vrrp_incr_err_counter (vrrp_err_counter_t err_type); +void vrrp_incr_stat_counter (vrrp_stat_counter_t stat_type, u32 stat_index); always_inline void vrrp_vr_skew_compute (vrrp_vr_t * vr) diff --git a/src/plugins/vrrp/vrrp_all_api_h.h b/src/plugins/vrrp/vrrp_all_api_h.h deleted file mode 100644 index 4f45909de70..00000000000 --- a/src/plugins/vrrp/vrrp_all_api_h.h +++ /dev/null @@ -1,11 +0,0 @@ - -/* - * vrrp_all_api_h.h - vrrp plug-in api #include file - * - * Copyright 2019-2020 Rubicon Communications, LLC (Netgate) - * - * SPDX-License-Identifier: Apache-2.0 - * - */ -/* Include the generated file, see BUILT_SOURCES in Makefile.am */ -#include <vrrp/vrrp.api.h> diff --git a/src/plugins/vrrp/vrrp_api.c b/src/plugins/vrrp/vrrp_api.c index 9a206fa6cdc..e31e0a74c14 100644 --- a/src/plugins/vrrp/vrrp_api.c +++ b/src/plugins/vrrp/vrrp_api.c @@ -25,6 +25,109 @@ /* API message handlers */ static void +vl_api_vrrp_vr_update_t_handler (vl_api_vrrp_vr_update_t *mp) +{ + vl_api_vrrp_vr_update_reply_t *rmp; + vrrp_vr_config_t vr_conf; + u32 api_flags; + u32 vrrp_index = INDEX_INVALID; + ip46_address_t *addrs = 0; + int rv; + + VALIDATE_SW_IF_INDEX (mp); + + api_flags = htonl (mp->flags); + + clib_memset (&vr_conf, 0, sizeof (vr_conf)); + + vr_conf.sw_if_index = ntohl (mp->sw_if_index); + vr_conf.vr_id = mp->vr_id; + vr_conf.priority = mp->priority; + vr_conf.adv_interval = ntohs (mp->interval); + + if (api_flags & VRRP_API_VR_PREEMPT) + vr_conf.flags |= VRRP_VR_PREEMPT; + + if (api_flags & VRRP_API_VR_ACCEPT) + vr_conf.flags |= VRRP_VR_ACCEPT; + + if (api_flags & VRRP_API_VR_UNICAST) + vr_conf.flags |= VRRP_VR_UNICAST; + + if (api_flags & VRRP_API_VR_IPV6) + vr_conf.flags |= VRRP_VR_IPV6; + + int i; + for (i = 0; i < mp->n_addrs; i++) + { + ip46_address_t *addr; + void *src, *dst; + int len; + + vec_add2 (addrs, addr, 1); + + if (ntohl (mp->addrs[i].af) == ADDRESS_IP4) + { + src = &mp->addrs[i].un.ip4; + dst = &addr->ip4; + len = sizeof (addr->ip4); + } + else + { + src = &mp->addrs[i].un.ip6; + dst = &addr->ip6; + len = sizeof (addr->ip6); + } + + clib_memcpy (dst, src, len); + } + + vr_conf.vr_addrs = addrs; + + if (vr_conf.priority == 0) + { + clib_warning ("VR priority must be > 0"); + rv = VNET_API_ERROR_INVALID_VALUE; + } + else if (vr_conf.adv_interval == 0) + { + clib_warning ("VR advertisement interval must be > 0"); + rv = VNET_API_ERROR_INVALID_VALUE; + } + else if (vr_conf.vr_id == 0) + { + clib_warning ("VR ID must be > 0"); + rv = VNET_API_ERROR_INVALID_VALUE; + } + else + { + vrrp_index = ntohl (mp->vrrp_index); + rv = vrrp_vr_update (&vrrp_index, &vr_conf); + } + + vec_free (addrs); + + BAD_SW_IF_INDEX_LABEL; + // clang-format off + REPLY_MACRO2 (VL_API_VRRP_VR_UPDATE_REPLY, + ({ + rmp->vrrp_index = htonl (vrrp_index); + })); + // clang-format on +} + +static void +vl_api_vrrp_vr_del_t_handler (vl_api_vrrp_vr_del_t *mp) +{ + vl_api_vrrp_vr_del_reply_t *rmp; + int rv; + + rv = vrrp_vr_del (ntohl (mp->vrrp_index)); + + REPLY_MACRO (VL_API_VRRP_VR_DEL_REPLY); +} + +static void vl_api_vrrp_vr_add_del_t_handler (vl_api_vrrp_vr_add_del_t * mp) { vl_api_vrrp_vr_add_del_reply_t *rmp; @@ -103,7 +206,7 @@ vl_api_vrrp_vr_add_del_t_handler (vl_api_vrrp_vr_add_del_t * mp) rv = VNET_API_ERROR_INVALID_VALUE; } else - rv = vrrp_vr_add_del (mp->is_add, &vr_conf); + rv = vrrp_vr_add_del (mp->is_add, &vr_conf, NULL); vec_free (addrs); @@ -215,7 +318,6 @@ vl_api_vrrp_vr_dump_t_handler (vl_api_vrrp_vr_dump_t * mp) sw_if_index = htonl (mp->sw_if_index); - /* *INDENT-OFF* */ pool_foreach (vr, vmp->vrs) { if (sw_if_index && (sw_if_index != ~0) && @@ -224,7 +326,6 @@ vl_api_vrrp_vr_dump_t_handler (vl_api_vrrp_vr_dump_t * mp) send_vrrp_vr_details (vr, reg, mp->context); } - /* *INDENT-ON* */ } static void @@ -363,7 +464,6 @@ vl_api_vrrp_vr_peer_dump_t_handler (vl_api_vrrp_vr_peer_dump_t * mp) return; } - /* *INDENT-OFF* */ pool_foreach (vr, vmp->vrs) { if (!vec_len (vr->config.peer_addrs)) @@ -372,7 +472,6 @@ vl_api_vrrp_vr_peer_dump_t_handler (vl_api_vrrp_vr_peer_dump_t * mp) send_vrrp_vr_details (vr, reg, mp->context); } - /* *INDENT-ON* */ } static void @@ -467,7 +566,6 @@ vl_api_vrrp_vr_track_if_dump_t_handler (vl_api_vrrp_vr_track_if_dump_t * mp) return; } - /* *INDENT-OFF* */ pool_foreach (vr, vmp->vrs) { if (!vec_len (vr->tracking.interfaces)) @@ -476,7 +574,6 @@ vl_api_vrrp_vr_track_if_dump_t_handler (vl_api_vrrp_vr_track_if_dump_t * mp) send_vrrp_vr_track_if_details (vr, reg, mp->context); } - /* *INDENT-ON* */ } static void @@ -510,14 +607,12 @@ vrrp_vr_event (vrrp_vr_t * vr, vrrp_vr_state_t new_state) vpe_client_registration_t *reg; vl_api_registration_t *vl_reg; - /* *INDENT-OFF* */ pool_foreach (reg, vam->vrrp_vr_events_registrations) { vl_reg = vl_api_client_index_to_registration (reg->client_index); if (vl_reg) send_vrrp_vr_event (reg, vl_reg, vr, new_state); } - /* *INDENT-ON* */ } pub_sub_handler (vrrp_vr_events, VRRP_VR_EVENTS); @@ -535,7 +630,6 @@ vrrp_plugin_api_hookup (vlib_main_t * vm) return 0; } -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/vrrp/vrrp_cli.c b/src/plugins/vrrp/vrrp_cli.c index a154a11a8fa..fb52da474fa 100644 --- a/src/plugins/vrrp/vrrp_cli.c +++ b/src/plugins/vrrp/vrrp_cli.c @@ -102,7 +102,7 @@ vrrp_vr_add_del_command_fn (vlib_main_t * vm, vr_conf.adv_interval = (u16) interval; vr_conf.vr_addrs = addrs; - rv = vrrp_vr_add_del (is_add, &vr_conf); + rv = vrrp_vr_add_del (is_add, &vr_conf, NULL); switch (rv) { @@ -151,7 +151,6 @@ vrrp_vr_add_command_fn (vlib_main_t * vm, unformat_input_t * input, return vrrp_vr_add_del_command_fn (vm, input, cmd, 1 /* is_add */ ); } -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (vrrp_vr_add_command, static) = { .path = "vrrp vr add", @@ -159,7 +158,6 @@ VLIB_CLI_COMMAND (vrrp_vr_add_command, static) = "vrrp vr add <interface> [vr_id <n>] [ipv6] [priority <value>] [interval <value>] [no_preempt] [accept_mode] [unicast] [<ip_addr> ...]", .function = vrrp_vr_add_command_fn, }; -/* *INDENT-ON* */ static clib_error_t * vrrp_vr_del_command_fn (vlib_main_t * vm, unformat_input_t * input, @@ -168,14 +166,12 @@ vrrp_vr_del_command_fn (vlib_main_t * vm, unformat_input_t * input, return vrrp_vr_add_del_command_fn (vm, input, cmd, 0 /* is_add */ ); } -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (vrrp_vr_del_command, static) = { .path = "vrrp vr del", .short_help = "vrrp vr del <interface> [vr_id <n>] [ipv6]", .function = vrrp_vr_del_command_fn, }; -/* *INDENT-ON* */ static clib_error_t * vrrp_show_vr_command_fn (vlib_main_t * vm, @@ -208,7 +204,6 @@ vrrp_show_vr_command_fn (vlib_main_t * vm, return 0; } -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (vrrp_show_vr_command, static) = { .path = "show vrrp vr", @@ -216,7 +211,6 @@ VLIB_CLI_COMMAND (vrrp_show_vr_command, static) = "show vrrp vr [(<intf_name>|sw_if_index <n>)]", .function = vrrp_show_vr_command_fn, }; -/* *INDENT-ON* */ static clib_error_t * vrrp_proto_start_stop_command_fn (vlib_main_t * vm, @@ -242,6 +236,8 @@ vrrp_proto_start_stop_command_fn (vlib_main_t * vm, if (unformat (input, "%U", unformat_vnet_sw_interface, vmp->vnet_main, &sw_if_index)) ; + else if (unformat (input, "sw_if_index %u", &sw_if_index)) + ; else if (unformat (input, "vr_id %u", &vr_id)) ; else if (unformat (input, "ipv6")) @@ -311,6 +307,8 @@ vrrp_peers_command_fn (vlib_main_t * vm, unformat_input_t * input, if (unformat (input, "%U", unformat_vnet_sw_interface, vmp->vnet_main, &sw_if_index)) ; + else if (unformat (input, "sw_if_index %u", &sw_if_index)) + ; else if (unformat (input, "vr_id %u", &vr_id)) ; else if (unformat (input, "ipv6")) @@ -373,7 +371,6 @@ done: return ret; } -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (vrrp_proto_start_stop_command, static) = { .path = "vrrp proto", @@ -381,9 +378,7 @@ VLIB_CLI_COMMAND (vrrp_proto_start_stop_command, static) = "vrrp proto (start|stop) (<intf_name>|sw_if_index <n>) vr_id <n> [ipv6]", .function = vrrp_proto_start_stop_command_fn, }; -/* *INDENT-ON* */ -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (vrrp_peers_command, static) = { .path = "vrrp peers", @@ -391,7 +386,6 @@ VLIB_CLI_COMMAND (vrrp_peers_command, static) = "vrrp peers (<intf_name>|sw_if_index <n>) vr_id <n> [ipv6] <peer1_addr> [<peer2_addr> ...]", .function = vrrp_peers_command_fn, }; -/* *INDENT-ON* */ static clib_error_t * vrrp_vr_track_if_command_fn (vlib_main_t * vm, @@ -418,6 +412,8 @@ vrrp_vr_track_if_command_fn (vlib_main_t * vm, if (unformat (input, "%U", unformat_vnet_sw_interface, vmp->vnet_main, &sw_if_index)) ; + else if (unformat (input, "sw_if_index %u", &sw_if_index)) + ; else if (unformat (input, "add")) is_add = 1; else if (unformat (input, "del")) @@ -487,7 +483,6 @@ done: return ret; } -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (vrrp_vr_track_if_command, static) = { .path = "vrrp vr track-if", @@ -495,7 +490,6 @@ VLIB_CLI_COMMAND (vrrp_vr_track_if_command, static) = "vrrp vr track-if (add|del) (<intf_name>|sw_if_index <n>) vr_id <n> [ipv6] track-index <n> priority <n> [ track-index <n> priority <n> ...]", .function = vrrp_vr_track_if_command_fn, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/vrrp/vrrp_msg_enum.h b/src/plugins/vrrp/vrrp_msg_enum.h deleted file mode 100644 index 48ae619205a..00000000000 --- a/src/plugins/vrrp/vrrp_msg_enum.h +++ /dev/null @@ -1,23 +0,0 @@ - -/* - * vrrp_msg_enum.h - vrrp plug-in message enumeration - * - * Copyright 2019-2020 Rubicon Communications, LLC (Netgate) - * - * SPDX-License-Identifier: Apache-2.0 - * - */ -#ifndef included_vrrp_msg_enum_h -#define included_vrrp_msg_enum_h - -#include <vppinfra/byte_order.h> - -#define vl_msg_id(n,h) n, -typedef enum { -#include <vrrp/vrrp_all_api_h.h> - /* We'll want to know how many messages IDs we need... */ - VL_MSG_FIRST_AVAILABLE, -} vl_msg_id_t; -#undef vl_msg_id - -#endif /* included_vrrp_msg_enum_h */ diff --git a/src/plugins/vrrp/vrrp_packet.c b/src/plugins/vrrp/vrrp_packet.c index 84bd3701edb..69e635f811a 100644 --- a/src/plugins/vrrp/vrrp_packet.c +++ b/src/plugins/vrrp/vrrp_packet.c @@ -115,6 +115,10 @@ vrrp_adv_l3_build (vrrp_vr_t * vr, vlib_buffer_t * b, * this is the first address on the interface. */ src4 = ip_interface_get_first_ip (vr->config.sw_if_index, 1); + if (!src4) + { + return -1; + } ip4->src_address.as_u32 = src4->as_u32; ip4->length = clib_host_to_net_u16 (sizeof (*ip4) + vrrp_adv_payload_len (vr)); @@ -332,7 +336,12 @@ vrrp_adv_send (vrrp_vr_t * vr, int shutdown) else vrrp_adv_l2_build_multicast (vr, b); - vrrp_adv_l3_build (vr, b, dst); + if (-1 == vrrp_adv_l3_build (vr, b, dst)) + { + vlib_frame_free (vm, to_frame); + vlib_buffer_free (vm, bi, n_buffers); + return -1; + } vrrp_adv_payload_build (vr, b, shutdown); vlib_buffer_reset (b); @@ -344,6 +353,12 @@ vrrp_adv_send (vrrp_vr_t * vr, int shutdown) vlib_put_frame_to_node (vm, node_index, to_frame); + vrrp_incr_stat_counter (VRRP_STAT_COUNTER_ADV_SENT, vr->stat_index); + if (shutdown) + { + vrrp_incr_stat_counter (VRRP_STAT_COUNTER_PRIO0_SENT, vr->stat_index); + } + vec_free (bi); return 0; @@ -523,6 +538,8 @@ vrrp_garp_or_na_send (vrrp_vr_t * vr) vlib_put_frame_to_node (vm, vmp->intf_output_node_idx, to_frame); + vec_free (bi); + return 0; } @@ -536,8 +553,8 @@ static const ip4_header_t igmp_ip4_mcast = { .dst_address = {.as_u8 = IGMP4_MCAST_ADDR_AS_U8,}, }; -static void -vrrp_igmp_pkt_build (vrrp_vr_t * vr, vlib_buffer_t * b) +static int +vrrp_igmp_pkt_build (vrrp_vr_t *vr, vlib_buffer_t *b) { ip4_header_t *ip4; u8 *ip4_options; @@ -550,6 +567,10 @@ vrrp_igmp_pkt_build (vrrp_vr_t * vr, vlib_buffer_t * b) /* Use the source address advertisements will use to join mcast group */ src4 = ip_interface_get_first_ip (vr->config.sw_if_index, 1); + if (!src4) + { + return -1; + } ip4->src_address.as_u32 = src4->as_u32; vlib_buffer_chain_increase_length (b, b, sizeof (*ip4)); @@ -592,6 +613,7 @@ vrrp_igmp_pkt_build (vrrp_vr_t * vr, vlib_buffer_t * b) ~ip_csum_fold (ip_incremental_checksum (0, report, payload_len)); vlib_buffer_reset (b); + return 0; } /* multicast listener report packet format for ethernet. */ @@ -731,7 +753,13 @@ vrrp_vr_multicast_group_join (vrrp_vr_t * vr) } else { - vrrp_igmp_pkt_build (vr, b); + if (-1 == vrrp_igmp_pkt_build (vr, b)) + { + clib_warning ("IGMP packet build failed for %U", format_vrrp_vr_key, + vr); + vlib_buffer_free (vm, &bi, 1); + return -1; + } node_index = ip4_rewrite_mcast_node.index; } diff --git a/src/plugins/vrrp/vrrp_packet.h b/src/plugins/vrrp/vrrp_packet.h index 1cbf62d7c72..d5725b6a1a5 100644 --- a/src/plugins/vrrp/vrrp_packet.h +++ b/src/plugins/vrrp/vrrp_packet.h @@ -47,6 +47,15 @@ vrrp_adv_int_from_packet (vrrp_header_t * pkt) return clib_net_to_host_u16 (pkt->rsvd_and_max_adv_int) & ((u16) 0x0fff); } +/* Fields from VRRP advertisement packets needed by main thread */ +typedef struct vrrp_input_process_args +{ + u32 vr_index; + ip46_address_t src_addr; + u8 priority; + u8 max_adv_int; +} vrrp_input_process_args_t; + #endif /* __included_vrrp_packet_h__ */ /* diff --git a/src/plugins/vrrp/vrrp_periodic.c b/src/plugins/vrrp/vrrp_periodic.c index 9c1b76ae59d..5f9d7ae938e 100644 --- a/src/plugins/vrrp/vrrp_periodic.c +++ b/src/plugins/vrrp/vrrp_periodic.c @@ -210,14 +210,12 @@ vrrp_periodic_process (vlib_main_t * vm, return 0; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (vrrp_periodic_node) = { .function = vrrp_periodic_process, .type = VLIB_NODE_TYPE_PROCESS, .name = "vrrp-periodic-process", .process_log2_n_stack_bytes = 17, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/vrrp/vrrp_test.c b/src/plugins/vrrp/vrrp_test.c index 199f5417f1a..d2f79f65c3f 100644 --- a/src/plugins/vrrp/vrrp_test.c +++ b/src/plugins/vrrp/vrrp_test.c @@ -19,8 +19,7 @@ uword unformat_sw_if_index (unformat_input_t * input, va_list * args); #include <vnet/format_fns.h> #include <vrrp/vrrp.api_enum.h> #include <vrrp/vrrp.api_types.h> -#include <vpp/api/vpe.api_types.h> - +#include <vlibmemory/vlib.api_types.h> typedef struct { @@ -36,6 +35,176 @@ vrrp_test_main_t vrrp_test_main; #include <vlibapi/vat_helper_macros.h> static int +api_vrrp_vr_update (vat_main_t *vam) +{ + unformat_input_t *i = vam->input; + u32 sw_if_index = ~0; + u32 vr_id, priority, interval, vrrp_index; + u8 is_ipv6, no_preempt, accept_mode, vr_unicast; + u8 n_addrs4, n_addrs6; + vl_api_vrrp_vr_update_t *mp; + vl_api_address_t *api_addr; + ip46_address_t *ip_addr, *ip_addrs = 0; + ip46_address_t addr; + int ret = 0; + + interval = priority = 100; + n_addrs4 = n_addrs6 = 0; + vr_id = is_ipv6 = no_preempt = accept_mode = vr_unicast = 0; + vrrp_index = INDEX_INVALID; + + clib_memset (&addr, 0, sizeof (addr)); + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %u", &sw_if_index)) + ; + else if (unformat (i, "vr_id %u", &vr_id)) + ; + else if (unformat (i, "vrrp_index %u", &vrrp_index)) + ; + else if (unformat (i, "ipv6")) + is_ipv6 = 1; + else if (unformat (i, "priority %u", &priority)) + ; + else if (unformat (i, "interval %u", &interval)) + ; + else if (unformat (i, "no_preempt")) + no_preempt = 1; + else if (unformat (i, "accept_mode")) + accept_mode = 1; + else if (unformat (i, "unicast")) + vr_unicast = 1; + else if (unformat (i, "%U", unformat_ip4_address, &addr.ip4)) + { + vec_add1 (ip_addrs, addr); + n_addrs4++; + clib_memset (&addr, 0, sizeof (addr)); + } + else if (unformat (i, "%U", unformat_ip6_address, &addr.ip6)) + { + vec_add1 (ip_addrs, addr); + n_addrs6++; + clib_memset (&addr, 0, sizeof (addr)); + } + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("Interface not set\n"); + ret = -99; + } + else if (n_addrs4 && (n_addrs6 || is_ipv6)) + { + errmsg ("Address family mismatch\n"); + ret = -99; + } + + if (ret) + goto done; + + /* Construct the API message */ + M2 (VRRP_VR_UPDATE, mp, vec_len (ip_addrs) * sizeof (*api_addr)); + + mp->vrrp_index = htonl (vrrp_index); + mp->sw_if_index = ntohl (sw_if_index); + mp->vr_id = vr_id; + mp->priority = priority; + mp->interval = htons (interval); + mp->flags = VRRP_API_VR_PREEMPT; /* preempt by default */ + + if (no_preempt) + mp->flags &= ~VRRP_API_VR_PREEMPT; + + if (accept_mode) + mp->flags |= VRRP_API_VR_ACCEPT; + + if (vr_unicast) + mp->flags |= VRRP_API_VR_UNICAST; + + if (is_ipv6) + mp->flags |= VRRP_API_VR_IPV6; + + mp->flags = htonl (mp->flags); + + mp->n_addrs = n_addrs4 + n_addrs6; + api_addr = mp->addrs; + + vec_foreach (ip_addr, ip_addrs) + { + void *src, *dst; + int len; + + if (is_ipv6) + { + api_addr->af = ADDRESS_IP6; + src = &ip_addr->ip6; + dst = &api_addr->un.ip6; + len = sizeof (api_addr->un.ip6); + } + else + { + api_addr->af = ADDRESS_IP4; + src = &ip_addr->ip4; + dst = &api_addr->un.ip4; + len = sizeof (api_addr->un.ip4); + } + clib_memcpy (dst, src, len); + api_addr++; + } + + /* send it... */ + S (mp); + + /* Wait for a reply... */ + W (ret); + +done: + vec_free (ip_addrs); + + return ret; +} + +static void +vl_api_vrrp_vr_update_reply_t_handler (vl_api_vrrp_vr_update_reply_t *mp) +{ +} + +static int +api_vrrp_vr_del (vat_main_t *vam) +{ + unformat_input_t *i = vam->input; + vl_api_vrrp_vr_del_t *mp; + u32 vrrp_index = INDEX_INVALID; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "vrrp_index %u", &vrrp_index)) + ; + else + break; + } + + /* Construct the API message */ + M (VRRP_VR_DEL, mp); + mp->vrrp_index = htonl (vrrp_index); + + /* send it... */ + S (mp); + + /* Wait for a reply... */ + W (ret); + + return ret; +} + +static int api_vrrp_vr_add_del (vat_main_t * vam) { unformat_input_t *i = vam->input; |