/*
* Copyright (c) 2016 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.
*/
/**
* @brief
*
*/
#ifndef __REPLICATE_DPO_H__
#define __REPLICATE_DPO_H__
#include
@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.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) 2017 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.
*/
#include <stdint.h>
#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
#include <vnet/plugin/plugin.h>
#include <vpp/app/version.h>
#include <vppinfra/hash.h>
#include <vnet/bonding/node.h>
#include <lacp/node.h>
#include <vpp/stats/stat_segment.h>
lacp_main_t lacp_main;
/*
* Generate lacp pdu
*/
static void
lacp_fill_pdu (lacp_pdu_t * lacpdu, slave_if_t * sif)
{
/* Actor TLV */
lacpdu->actor.port_info = sif->actor;
/* Partner TLV */
lacpdu->partner.port_info = sif->partner;
}
/*
* send a lacp pkt on an ethernet interface
*/
static void
lacp_send_ethernet_lacp_pdu (slave_if_t * sif)
{
lacp_main_t *lm = &lacp_main;
u32 *to_next;
ethernet_lacp_pdu_t *h0;
vnet_hw_interface_t *hw;
u32 bi0;
vlib_buffer_t *b0;
vlib_frame_t *f;
vlib_main_t *vm = lm->vlib_main;
vnet_main_t *vnm = lm->vnet_main;
/*
* see lacp_periodic_init() to understand what's already painted
* into the buffer by the packet template mechanism
*/
h0 = vlib_packet_template_get_packet
(vm, &lm->packet_templates[sif->packet_template_index], &bi0);
if (!h0)
return;
/* Add the interface's ethernet source address */
hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
clib_memcpy (h0->ethernet.src_address, hw->hw_address,
vec_len (hw->hw_address));
lacp_fill_pdu (&h0->lacp, sif);
/* Set the outbound packet length */
b0 = vlib_get_buffer (vm, bi0);
b0->current_length = sizeof (ethernet_lacp_pdu_t);
b0->current_data = 0;
b0->total_length_not_including_first_buffer = 0;
/* And the outbound interface */
vnet_buffer (b0)->sw_if_index[VLIB_TX] = hw->sw_if_index;
/* And output the packet on the correct interface */
f = vlib_get_frame_to_node (vm, hw->output_node_index);
to_next = vlib_frame_vector_args (f);
to_next[0] = bi0;
f->n_vectors = 1;
vlib_put_frame_to_node (vm, hw->output_node_index, f);
sif->last_lacpdu_sent_time = vlib_time_now (lm->vlib_main);
sif->pdu_sent++;
}
/*
* Decide which lacp packet template to use
*/
static int
lacp_pick_packet_template (slave_if_t * sif)
{
sif->packet_template_index = LACP_PACKET_TEMPLATE_ETHERNET;
return 0;
}
void
lacp_send_lacp_pdu (vlib_main_t * vm, slave_if_t * sif)
{
if ((sif->mode != BOND_MODE_LACP) || (sif->port_enabled == 0))
{
lacp_stop_timer (&sif->periodic_timer);
return;
}
if (sif->packet_template_index == (u8) ~ 0)
{
/* If we don't know how to talk to this peer, don't try again */
if (lacp_pick_packet_template (sif))
{
lacp_stop_timer (&sif->periodic_timer);
return;
}
}
switch (sif->packet_template_index)
{
case LACP_PACKET_TEMPLATE_ETHERNET:
lacp_send_ethernet_lacp_pdu (sif);
break;
default:
ASSERT (0);
}
}
void
lacp_periodic (vlib_main_t * vm)
{
bond_main_t *bm = &bond_main;
lacp_main_t *lm = &lacp_main;
slave_if_t *sif;
bond_if_t *bif;
u8 actor_state, partner_state;
/* *INDENT-OFF* */
pool_foreach (sif, bm->neighbors,
({
if (sif->port_enabled == 0)
continue;
actor_state = sif->actor.state;
partner_state = sif->partner.state;
if (lacp_timer_is_running (sif->current_while_timer) &&
lacp_timer_is_expired (lm->vlib_main, sif->current_while_timer))
{
lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
LACP_RX_EVENT_TIMER_EXPIRED, &sif->rx_state);
}
if (lacp_timer_is_running (sif->periodic_timer) &&
lacp_timer_is_expired (lm->vlib_main, sif->periodic_timer))
{
lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
LACP_PTX_EVENT_TIMER_EXPIRED, &sif->ptx_state);
}
if (lacp_timer_is_running (sif->wait_while_timer) &&
lacp_timer_is_expired (lm->vlib_main, sif->wait_while_timer))
{
sif->ready_n = 1;
lacp_stop_timer (&sif->wait_while_timer);
lacp_selection_logic (vm, sif);
}
if (actor_state != sif->actor.state)
{
bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
[sif->sw_if_index].actor_state,
sif->actor.state);
}
if (partner_state != sif->partner.state)
{
bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
[sif->sw_if_index].partner_state,
sif->partner.state);
}
}));
/* *INDENT-ON* */
}
static void
lacp_interface_enable_disable (vlib_main_t * vm, bond_if_t * bif,
slave_if_t * sif, u8 enable)
{
lacp_main_t *lm = &lacp_main;
uword port_number;
if (enable)
{
lacp_create_periodic_process ();
port_number = clib_bitmap_first_clear (bif->port_number_bitmap);
bif->port_number_bitmap = clib_bitmap_set (bif->port_number_bitmap,
port_number, 1);
// bitmap starts at 0. Our port number starts at 1.
lacp_init_neighbor (sif, bif->hw_address, port_number + 1, sif->group);
lacp_init_state_machines (vm, sif);
lm->lacp_int++;
if (lm->lacp_int == 1)
{
vlib_process_signal_event (vm, lm->lacp_process_node_index,
LACP_PROCESS_EVENT_START, 0);
}
}
else
{
ASSERT (lm->lacp_int >= 1);
if (lm->lacp_int == 0)
{
/* *INDENT-OFF* */
ELOG_TYPE_DECLARE (e) =
{
.format = "lacp-int-en-dis: BUG lacp_int == 0",
};
/* *INDENT-ON* */
ELOG_DATA (&vlib_global_main.elog_main, e);
}
else
{
lm->lacp_int--;
if (lm->lacp_int == 0)
vlib_process_signal_event (vm, lm->lacp_process_node_index,
LACP_PROCESS_EVENT_STOP, 0);
}
}
}
static clib_error_t *
lacp_periodic_init (vlib_main_t * vm)
{
lacp_main_t *lm = &lacp_main;
ethernet_lacp_pdu_t h;
ethernet_marker_pdu_t m;
u8 dst[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 };
/* initialize binary API */
lacp_plugin_api_hookup (vm);
/* Create the ethernet lacp packet template */
clib_memset (&h, 0, sizeof (h));
memcpy (h.ethernet.dst_address, dst, sizeof (h.ethernet.dst_address));
/* leave src address blank (fill in at send time) */
h.ethernet.type = htons (ETHERNET_TYPE_SLOW_PROTOCOLS);
h.lacp.subtype = LACP_SUBTYPE;
h.lacp.version_number = LACP_ACTOR_LACP_VERSION;
/* Actor TLV */
h.lacp.actor.tlv_type = LACP_ACTOR_INFORMATION;
h.lacp.actor.tlv_length = sizeof (lacp_actor_partner_t);
/* Partner TLV */
h.lacp.partner.tlv_type = LACP_PARTNER_INFORMATION;
h.lacp.partner.tlv_length = sizeof (lacp_actor_partner_t);
/* Collector TLV */
h.lacp.collector.tlv_type = LACP_COLLECTOR_INFORMATION;
h.lacp.collector.tlv_length = sizeof (lacp_collector_t);
h.lacp.collector.max_delay = 0;
/* Terminator TLV */
h.lacp.terminator.tlv_type = LACP_TERMINATOR_INFORMATION;
h.lacp.terminator.tlv_length = 0;
vlib_packet_template_init
(vm, &lm->packet_templates[LACP_PACKET_TEMPLATE_ETHERNET],
/* data */ &h,
sizeof (h),
/* alloc chunk size */ 8,
"lacp-ethernet");
/* Create the ethernet marker protocol packet template */
clib_memset (&m, 0, sizeof (m));
memcpy (m.ethernet.dst_address, dst, sizeof (m.ethernet.dst_address));
/* leave src address blank (fill in at send time) */
m.ethernet.type = htons (ETHERNET_TYPE_SLOW_PROTOCOLS);
m.marker.subtype = MARKER_SUBTYPE;
m.marker.version_number = MARKER_PROTOCOL_VERSION;
m.marker.marker_info.tlv_length = sizeof (marker_information_t);
/* Terminator TLV */
m.marker.terminator.tlv_type = MARKER_TERMINATOR_INFORMATION;
m.marker.terminator.tlv_length = 0;
vlib_packet_template_init
(vm, &lm->marker_packet_templates[MARKER_PACKET_TEMPLATE_ETHERNET],
/* data */ &m,
sizeof (m),
/* alloc chunk size */ 8,
"marker-ethernet");
bond_register_callback (lacp_interface_enable_disable);
return 0;
}
int
lacp_machine_dispatch (lacp_machine_t * machine, vlib_main_t * vm,
slave_if_t * sif, int event, int *state)
{
lacp_fsm_state_t *transition;
int rc = 0;
transition = &machine->tables[*state].state_table[event];
LACP_DBG2 (sif, event, *state, machine, transition);
*state = transition->next_state;
if (transition->action)
rc = (*transition->action) ((void *) vm, (void *) sif);
return rc;
}
void
lacp_init_neighbor (slave_if_t * sif, u8 * hw_address, u16 port_number,
u32 group)
{
lacp_stop_timer (&sif->wait_while_timer);
lacp_stop_timer (&sif->current_while_timer);
lacp_stop_timer (&sif->actor_churn_timer);
lacp_stop_timer (&sif->partner_churn_timer);
lacp_stop_timer (&sif->periodic_timer);
lacp_stop_timer (&sif->last_lacpdu_sent_time);
lacp_stop_timer (&sif->last_lacpdu_recd_time);
lacp_stop_timer (&sif->last_marker_pdu_sent_time);
lacp_stop_timer (&sif->last_marker_pdu_recd_time);
sif->lacp_enabled = 1;
sif->loopback_port = 0;
sif->ready = 0;
sif->ready_n = 0;
sif->port_moved = 0;
sif->ntt = 0;
sif->selected = LACP_PORT_UNSELECTED;
sif->actor.state = LACP_STATE_AGGREGATION;
if (sif->ttl_in_seconds == LACP_SHORT_TIMOUT_TIME)
sif->actor.state |= LACP_STATE_LACP_TIMEOUT;
if (sif->is_passive == 0)
sif->actor.state |= LACP_STATE_LACP_ACTIVITY;
clib_memcpy (sif->actor.system, hw_address, 6);
sif->actor.system_priority = htons (LACP_DEFAULT_SYSTEM_PRIORITY);
sif->actor.key = htons (group);
sif->actor.port_number = htons (port_number);
sif->actor.port_priority = htons (LACP_DEFAULT_PORT_PRIORITY);
sif->partner.system_priority = htons (LACP_DEFAULT_SYSTEM_PRIORITY);
sif->partner.key = htons (group);
sif->partner.port_number = htons (port_number);
sif->partner.port_priority = htons (LACP_DEFAULT_PORT_PRIORITY);
sif->partner.state = 0;
sif->actor_admin = sif->actor;
sif->partner_admin = sif->partner;
}
void
lacp_init_state_machines (vlib_main_t * vm, slave_if_t * sif)
{
bond_main_t *bm = &bond_main;
bond_if_t *bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
lacp_init_tx_machine (vm, sif);
lacp_init_mux_machine (vm, sif);
lacp_init_ptx_machine (vm, sif);
lacp_init_rx_machine (vm, sif);
stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
[sif->sw_if_index].actor_state,
sif->actor.state);
stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
[sif->sw_if_index].partner_state,
sif->partner.state);
}
VLIB_INIT_FUNCTION (lacp_periodic_init);
static clib_error_t *
lacp_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
{
lacp_main_t *lm = &lacp_main;
slave_if_t *sif;
vlib_main_t *vm = lm->vlib_main;
sif = bond_get_slave_by_sw_if_index (sw_if_index);
if (sif)
{
if (sif->lacp_enabled == 0)
return 0;
/* port_enabled is both admin up and hw link up */
sif->port_enabled = ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) &&
vnet_sw_interface_is_link_up (vnm, sw_if_index));
if (sif->port_enabled == 0)
{
lacp_init_neighbor (sif, sif->actor_admin.system,
ntohs (sif->actor_admin.port_number),
ntohs (sif->actor_admin.key));
lacp_init_state_machines (vm, sif);
}
}
return 0;
}
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (lacp_sw_interface_up_down);
static clib_error_t *
lacp_hw_interface_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
{
lacp_main_t *lm = &lacp_main;
slave_if_t *sif;
vnet_sw_interface_t *sw;
vlib_main_t *vm = lm->vlib_main;
sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
sif = bond_get_slave_by_sw_if_index (sw->sw_if_index);
if (sif)
{
if (sif->lacp_enabled == 0)
return 0;
/* port_enabled is both admin up and hw link up */
sif->port_enabled = ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) &&
vnet_sw_interface_is_admin_up (vnm,
sw->sw_if_index));
if (sif->port_enabled == 0)
{
lacp_init_neighbor (sif, sif->actor_admin.system,
ntohs (sif->actor_admin.port_number),
ntohs (sif->actor_admin.key));
lacp_init_state_machines (vm, sif);
}
}
return 0;
}
VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lacp_hw_interface_up_down);
/* *INDENT-OFF* */
VLIB_PLUGIN_REGISTER () = {
.version = VPP_BUILD_VER,
.description = "Link Aggregation Control Protocol (LACP)",
};
/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/