diff options
-rw-r--r-- | src/plugins/vrrp/node.c | 11 | ||||
-rw-r--r-- | src/plugins/vrrp/vrrp.c | 75 |
2 files changed, 48 insertions, 38 deletions
diff --git a/src/plugins/vrrp/node.c b/src/plugins/vrrp/node.c index a916bcc03ff..0cd5b59ac58 100644 --- a/src/plugins/vrrp/node.c +++ b/src/plugins/vrrp/node.c @@ -334,11 +334,18 @@ vrrp_arp_nd_next (vlib_buffer_t * b, u32 * next_index, u32 * vr_index, if (*vr_index == ~0) return; - /* only reply if the VR is in the master state */ vr = vrrp_vr_lookup_index (*vr_index); if (!vr || vr->runtime.state != VRRP_VR_STATE_MASTER) - return; + { + /* RFC 5798 - section 6.4.2 - Backup "MUST NOT respond" to ARP/ND. + * So we must drop the request rather than allowing it to continue + * on the feature arc. + */ + *next_index = VRRP_ARP_INPUT_NEXT_DROP; + return; + } + /* RFC 5798 section 6.4.3: Master "MUST respond" to ARP/ND. */ eth = ethernet_buffer_get_header (b); rewrite = ethernet_build_rewrite (vnm, sw_if_index, link_type, eth->src_address); diff --git a/src/plugins/vrrp/vrrp.c b/src/plugins/vrrp/vrrp.c index 564cdb0551f..eb988d323c9 100644 --- a/src/plugins/vrrp/vrrp.c +++ b/src/plugins/vrrp/vrrp.c @@ -144,11 +144,7 @@ vrrp_vr_transition_intf (vrrp_vr_t * vr, vrrp_vr_state_t new_state) u8 is_ipv6 = vrrp_vr_is_ipv6 (vr); u32 *vr_index; int n_master_accept = 0; - - /* 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)) - return; + int n_started = 0; if (is_ipv6) { @@ -167,46 +163,53 @@ vrrp_vr_transition_intf (vrrp_vr_t * vr, vrrp_vr_state_t new_state) intf = vrrp_intf_get (vr->config.sw_if_index); - if (new_state == VRRP_VR_STATE_MASTER) - { - intf->n_master_vrs[is_ipv6]++; - if (intf->n_master_vrs[is_ipv6] == 1) - vnet_feature_enable_disable (arc_name, node_name, - vr->config.sw_if_index, 1, NULL, 0); - } - else - { - if (intf->n_master_vrs[is_ipv6] == 1) - vnet_feature_enable_disable (arc_name, node_name, - vr->config.sw_if_index, 0, NULL, 0); - /* If the count were already 0, leave it at 0 */ - if (intf->n_master_vrs[is_ipv6]) - intf->n_master_vrs[is_ipv6]--; - } + /* Check other VRs on this intf to see if features need to be toggled */ + vec_foreach (vr_index, intf->vr_indices[is_ipv6]) + { + vrrp_vr_t *intf_vr = vrrp_vr_lookup_index (*vr_index); - /* accept mode enabled, count the other master VRs w/ accept mode on intf */ - if (vrrp_vr_accept_mode_enabled (vr)) - { - vec_foreach (vr_index, intf->vr_indices[is_ipv6]) - { - vrrp_vr_t *intf_vr = vrrp_vr_lookup_index (*vr_index); + if (intf_vr == vr) + continue; - if (intf_vr == vr) - continue; + if (intf_vr->runtime.state == VRRP_VR_STATE_INIT) + continue; - if (vrrp_vr_accept_mode_enabled (intf_vr) && - (intf_vr->runtime.state == VRRP_VR_STATE_MASTER)) - n_master_accept++; - } + n_started++; + + if ((intf_vr->runtime.state == VRRP_VR_STATE_MASTER) && + vrrp_vr_accept_mode_enabled (intf_vr)) + n_master_accept++; + } - /* If no others, enable or disable the feature based on new state */ - if (!n_master_accept) + /* If entering/leaving init state, start/stop ARP or ND feature if no other + * VRs are active on the interface. + */ + if (((vr->runtime.state == VRRP_VR_STATE_INIT) || + (new_state == VRRP_VR_STATE_INIT)) && (n_started == 0)) + vnet_feature_enable_disable (arc_name, node_name, + vr->config.sw_if_index, + (new_state != VRRP_VR_STATE_INIT), NULL, 0); + + /* Special housekeeping when entering/leaving master mode */ + if ((vr->runtime.state == VRRP_VR_STATE_MASTER) || + (new_state == VRRP_VR_STATE_MASTER)) + { + /* Maintain count of master state VRs on interface */ + if (new_state == VRRP_VR_STATE_MASTER) + intf->n_master_vrs[is_ipv6]++; + else if (intf->n_master_vrs[is_ipv6] > 0) + intf->n_master_vrs[is_ipv6]--; + + /* If accept mode is enabled and no other master on intf has accept + * mode enabled, enable/disable feature node to avoid spurious drops by + * spoofing check. + */ + if (vrrp_vr_accept_mode_enabled (vr) && !n_master_accept) vnet_feature_enable_disable (mc_arc_name, mc_node_name, vr->config.sw_if_index, (new_state == VRRP_VR_STATE_MASTER), NULL, 0); } - } /* If accept mode enabled, add/remove VR addresses from interface */ |