X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fethernet%2Finterface.c;h=46d4203cda1bb6a5ccfd5fd78e61df34fa924062;hb=bf82a66de7653921e3c25ae444d372d2eddeee9f;hp=e0d1295f69d88aadb4c78b96c1e4b984cf10e97c;hpb=d63abff00f2aa234242a76aa0a4b5a38dfe1aee2;p=vpp.git diff --git a/src/vnet/ethernet/interface.c b/src/vnet/ethernet/interface.c index e0d1295f69d..46d4203cda1 100644 --- a/src/vnet/ethernet/interface.c +++ b/src/vnet/ethernet/interface.c @@ -41,9 +41,12 @@ #include #include #include +//#include #include #include #include +#include +#include /** * @file @@ -52,7 +55,7 @@ * This file contains code to manage loopback interfaces. */ -const u8 * +static const u8 * ethernet_ip4_mcast_dst_addr (void) { const static u8 ethernet_mcast_dst_mac[] = { @@ -62,7 +65,7 @@ ethernet_ip4_mcast_dst_addr (void) return (ethernet_mcast_dst_mac); } -const u8 * +static const u8 * ethernet_ip6_mcast_dst_addr (void) { const static u8 ethernet_mcast_dst_mac[] = { @@ -141,7 +144,7 @@ ethernet_build_rewrite (vnet_main_t * vnm, vec_validate (rewrite, n_bytes - 1); h = (ethernet_header_t *) rewrite; ei = pool_elt_at_index (em->interfaces, hw->hw_instance); - clib_memcpy (h->src_address, ei->address, sizeof (h->src_address)); + clib_memcpy (h->src_address, &ei->address, sizeof (h->src_address)); if (is_p2p) { clib_memcpy (h->dst_address, sub_sw->p2p.client_mac, @@ -152,7 +155,7 @@ ethernet_build_rewrite (vnet_main_t * vnm, if (dst_address) clib_memcpy (h->dst_address, dst_address, sizeof (h->dst_address)); else - memset (h->dst_address, ~0, sizeof (h->dst_address)); /* broadcast */ + clib_memset (h->dst_address, ~0, sizeof (h->dst_address)); /* broadcast */ } if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.one_tag) @@ -194,30 +197,98 @@ ethernet_build_rewrite (vnet_main_t * vnm, void ethernet_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai) { - ip_adjacency_t *adj; - - adj = adj_get (ai); - vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index); + if ((si->type == VNET_SW_INTERFACE_TYPE_P2P) || (si->type == VNET_SW_INTERFACE_TYPE_PIPE)) { default_update_adjacency (vnm, sw_if_index, ai); } - else if (FIB_PROTOCOL_IP4 == adj->ia_nh_proto) - { - arp_update_adjacency (vnm, sw_if_index, ai); - } - else if (FIB_PROTOCOL_IP6 == adj->ia_nh_proto) - { - ip6_ethernet_update_adjacency (vnm, sw_if_index, ai); - } else { - ASSERT (0); + ip_adjacency_t *adj; + + adj = adj_get (ai); + + switch (adj->lookup_next_index) + { + case IP_LOOKUP_NEXT_GLEAN: + adj_glean_update_rewrite (ai); + break; + case IP_LOOKUP_NEXT_ARP: + case IP_LOOKUP_NEXT_REWRITE: + ip_neighbor_update (vnm, ai); + break; + case IP_LOOKUP_NEXT_BCAST: + adj_nbr_update_rewrite (ai, + ADJ_NBR_REWRITE_FLAG_COMPLETE, + ethernet_build_rewrite + (vnm, + adj->rewrite_header.sw_if_index, + adj->ia_link, + VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST)); + break; + case IP_LOOKUP_NEXT_MCAST: + { + /* + * Construct a partial rewrite from the known ethernet mcast dest MAC + */ + u8 *rewrite; + u8 offset; + + rewrite = ethernet_build_rewrite + (vnm, + sw_if_index, + adj->ia_link, + (adj->ia_nh_proto == FIB_PROTOCOL_IP6 ? + ethernet_ip6_mcast_dst_addr () : + ethernet_ip4_mcast_dst_addr ())); + + /* + * Complete the remaining fields of the adj's rewrite to direct the + * complete of the rewrite at switch time by copying in the IP + * dst address's bytes. + * Ofset is 2 bytes into the destintation address. + */ + offset = vec_len (rewrite) - 2; + adj_mcast_update_rewrite (ai, rewrite, offset); + + break; + } + case IP_LOOKUP_NEXT_DROP: + case IP_LOOKUP_NEXT_PUNT: + case IP_LOOKUP_NEXT_LOCAL: + case IP_LOOKUP_NEXT_MCAST_MIDCHAIN: + case IP_LOOKUP_NEXT_MIDCHAIN: + case IP_LOOKUP_NEXT_ICMP_ERROR: + case IP_LOOKUP_N_NEXT: + ASSERT (0); + break; + } } } +static void +ethernet_interface_address_copy (ethernet_interface_address_t * dst, + const u8 * mac) +{ + clib_memcpy (&dst->mac, (u8 *) mac, sizeof (dst->mac)); + /* + * ethernet dataplane loads mac as u64, makes sure the last 2 bytes are 0 + * for comparison purpose + */ + dst->zero = 0; +} + +static void +ethernet_set_mac (vnet_hw_interface_t * hi, ethernet_interface_t * ei, + const u8 * mac_address) +{ + vec_validate (hi->hw_address, sizeof (mac_address_t) - 1); + clib_memcpy (hi->hw_address, mac_address, sizeof (mac_address_t)); + ethernet_interface_address_copy (&ei->address, mac_address); +} + static clib_error_t * ethernet_mac_change (vnet_hw_interface_t * hi, const u8 * old_address, const u8 * mac_address) @@ -228,20 +299,36 @@ ethernet_mac_change (vnet_hw_interface_t * hi, em = ðernet_main; ei = pool_elt_at_index (em->interfaces, hi->hw_instance); - vec_validate (hi->hw_address, - STRUCT_SIZE_OF (ethernet_header_t, src_address) - 1); - clib_memcpy (hi->hw_address, mac_address, vec_len (hi->hw_address)); + ethernet_set_mac (hi, ei, mac_address); - clib_memcpy (ei->address, (u8 *) mac_address, sizeof (ei->address)); - ethernet_arp_change_mac (hi->sw_if_index); - ethernet_ndp_change_mac (hi->sw_if_index); + { + ethernet_address_change_ctx_t *cb; + vec_foreach (cb, em->address_change_callbacks) + cb->function (em, hi->sw_if_index, cb->function_opaque); + } return (NULL); } +static clib_error_t * +ethernet_set_max_frame_size (vnet_main_t *vnm, vnet_hw_interface_t *hi, + u32 frame_size) +{ + ethernet_interface_t *ei = + pool_elt_at_index (ethernet_main.interfaces, hi->hw_instance); + + if (ei->cb.set_max_frame_size) + return ei->cb.set_max_frame_size (vnm, hi, frame_size); + + return vnet_error ( + VNET_ERR_UNSUPPORTED, + "underlying driver doesn't support changing Max Frame Size"); +} + /* *INDENT-OFF* */ VNET_HW_INTERFACE_CLASS (ethernet_hw_interface_class) = { .name = "Ethernet", + .tx_hash_fn_type = VNET_HASH_FN_TYPE_ETHERNET, .format_address = format_ethernet_address, .format_header = format_ethernet_header_with_length, .unformat_hw_address = unformat_ethernet_address, @@ -249,6 +336,7 @@ VNET_HW_INTERFACE_CLASS (ethernet_hw_interface_class) = { .build_rewrite = ethernet_build_rewrite, .update_adjacency = ethernet_update_adjacency, .mac_addr_change_function = ethernet_mac_change, + .set_max_frame_size = ethernet_set_max_frame_size, }; /* *INDENT-ON* */ @@ -273,50 +361,41 @@ unformat_ethernet_interface (unformat_input_t * input, va_list * args) return 0; } -clib_error_t * -ethernet_register_interface (vnet_main_t * vnm, - u32 dev_class_index, - u32 dev_instance, - u8 * address, - u32 * hw_if_index_return, - ethernet_flag_change_function_t flag_change) +u32 +vnet_eth_register_interface (vnet_main_t *vnm, + vnet_eth_interface_registration_t *r) { ethernet_main_t *em = ðernet_main; ethernet_interface_t *ei; vnet_hw_interface_t *hi; - clib_error_t *error = 0; u32 hw_if_index; pool_get (em->interfaces, ei); - ei->flag_change = flag_change; + clib_memcpy (&ei->cb, &r->cb, sizeof (vnet_eth_if_callbacks_t)); - hw_if_index = vnet_register_interface - (vnm, - dev_class_index, dev_instance, - ethernet_hw_interface_class.index, ei - em->interfaces); - *hw_if_index_return = hw_if_index; + hw_if_index = vnet_register_interface ( + vnm, r->dev_class_index, r->dev_instance, + ethernet_hw_interface_class.index, ei - em->interfaces); hi = vnet_get_hw_interface (vnm, hw_if_index); ethernet_setup_node (vnm->vlib_main, hi->output_node_index); - hi->min_packet_bytes = hi->min_supported_packet_bytes = - ETHERNET_MIN_PACKET_BYTES; - hi->max_packet_bytes = hi->max_supported_packet_bytes = - ETHERNET_MAX_PACKET_BYTES; - - /* Standard default ethernet MTU. */ - vnet_sw_interface_set_mtu (vnm, hi->sw_if_index, 9000); - - clib_memcpy (ei->address, address, sizeof (ei->address)); - vec_add (hi->hw_address, address, sizeof (ei->address)); - - if (error) - { - pool_put (em->interfaces, ei); - return error; - } - return error; + hi->min_frame_size = ETHERNET_MIN_PACKET_BYTES; + hi->frame_overhead = + r->frame_overhead ? + r->frame_overhead : + sizeof (ethernet_header_t) + 2 * sizeof (ethernet_vlan_header_t); + hi->max_frame_size = r->max_frame_size ? + r->max_frame_size : + ethernet_main.default_mtu + hi->frame_overhead; + ; + + /* Default ethernet MTU, 9000 unless set by ethernet_config see below */ + vnet_sw_interface_set_mtu (vnm, hi->sw_if_index, em->default_mtu); + + ethernet_set_mac (hi, ei, r->address); + return hw_if_index; } void @@ -373,15 +452,41 @@ ethernet_set_flags (vnet_main_t * vnm, u32 hw_if_index, u32 flags) ethernet_main_t *em = ðernet_main; vnet_hw_interface_t *hi; ethernet_interface_t *ei; + u32 opn_flags = flags & ETHERNET_INTERFACE_FLAGS_SET_OPN_MASK; hi = vnet_get_hw_interface (vnm, hw_if_index); ASSERT (hi->hw_class_index == ethernet_hw_interface_class.index); ei = pool_elt_at_index (em->interfaces, hi->hw_instance); - if (ei->flag_change) - return ei->flag_change (vnm, hi, flags); - return (u32) ~ 0; + + /* preserve status bits and update last set operation bits */ + ei->flags = (ei->flags & ETHERNET_INTERFACE_FLAGS_STATUS_MASK) | opn_flags; + + if (ei->cb.flag_change) + { + switch (opn_flags) + { + case ETHERNET_INTERFACE_FLAG_DEFAULT_L3: + if (hi->caps & VNET_HW_IF_CAP_MAC_FILTER) + { + if (ei->cb.flag_change (vnm, hi, opn_flags) != ~0) + { + ei->flags |= ETHERNET_INTERFACE_FLAG_STATUS_L3; + return 0; + } + ei->flags &= ~ETHERNET_INTERFACE_FLAG_STATUS_L3; + return ~0; + } + /* fall through */ + case ETHERNET_INTERFACE_FLAG_ACCEPT_ALL: + ei->flags &= ~ETHERNET_INTERFACE_FLAG_STATUS_L3; + return ei->cb.flag_change (vnm, hi, opn_flags); + default: + return ~0; + } + } + return ~0; } /** @@ -405,7 +510,7 @@ simulated_ethernet_interface_tx (vlib_main_t * vm, u32 new_tx_sw_if_index = ~0; n_left_from = frame->n_vectors; - from = vlib_frame_args (frame); + from = vlib_frame_vector_args (frame); vlib_get_buffers (vm, from, bufs, n_left_from); b = bufs; @@ -413,10 +518,10 @@ simulated_ethernet_interface_tx (vlib_main_t * vm, /* Ordinarily, this is the only config lookup. */ config = l2input_intf_config (vnet_buffer (b[0])->sw_if_index[VLIB_TX]); - next_index = - config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT : - VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT; - new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0; + next_index = (l2_input_is_bridge (config) ? + VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT : + VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT); + new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0; new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX]; while (n_left_from >= 4) @@ -496,10 +601,10 @@ simulated_ethernet_interface_tx (vlib_main_t * vm, { config = l2input_intf_config (vnet_buffer (b[0])->sw_if_index[VLIB_TX]); - next_index = - config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT : - VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT; - new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0; + next_index = (l2_input_is_bridge (config) ? + VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT : + VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT); + new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0; new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX]; } next[0] = next_index; @@ -519,11 +624,11 @@ simulated_ethernet_interface_tx (vlib_main_t * vm, { config = l2input_intf_config (vnet_buffer (b[1])->sw_if_index[VLIB_TX]); - next_index = - config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT : - VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT; + next_index = (l2_input_is_bridge (config) ? + VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT : + VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT); new_rx_sw_if_index = vnet_buffer (b[1])->sw_if_index[VLIB_TX]; - new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0; + new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0; } next[1] = next_index; vnet_buffer (b[1])->sw_if_index[VLIB_RX] = new_rx_sw_if_index; @@ -542,11 +647,11 @@ simulated_ethernet_interface_tx (vlib_main_t * vm, { config = l2input_intf_config (vnet_buffer (b[2])->sw_if_index[VLIB_TX]); - next_index = - config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT : - VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT; + next_index = (l2_input_is_bridge (config) ? + VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT : + VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT); new_rx_sw_if_index = vnet_buffer (b[2])->sw_if_index[VLIB_TX]; - new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0; + new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0; } next[2] = next_index; vnet_buffer (b[2])->sw_if_index[VLIB_RX] = new_rx_sw_if_index; @@ -565,11 +670,11 @@ simulated_ethernet_interface_tx (vlib_main_t * vm, { config = l2input_intf_config (vnet_buffer (b[3])->sw_if_index[VLIB_TX]); - next_index = - config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT : - VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT; + next_index = (l2_input_is_bridge (config) ? + VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT : + VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT); new_rx_sw_if_index = vnet_buffer (b[3])->sw_if_index[VLIB_TX]; - new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0; + new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0; } next[3] = next_index; vnet_buffer (b[3])->sw_if_index[VLIB_RX] = new_rx_sw_if_index; @@ -593,10 +698,10 @@ simulated_ethernet_interface_tx (vlib_main_t * vm, { config = l2input_intf_config (vnet_buffer (b[0])->sw_if_index[VLIB_TX]); - next_index = - config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT : - VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT; - new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0; + next_index = (l2_input_is_bridge (config) ? + VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT : + VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT); + new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0; new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX]; } next[0] = next_index; @@ -657,9 +762,6 @@ VNET_DEVICE_CLASS (ethernet_simulated_device_class) = { }; /* *INDENT-ON* */ -VLIB_DEVICE_TX_FUNCTION_MULTIARCH (ethernet_simulated_device_class, - simulated_ethernet_interface_tx); - /* * Maintain a bitmap of allocated loopback instance numbers. */ @@ -738,19 +840,17 @@ vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address, { vnet_main_t *vnm = vnet_get_main (); vlib_main_t *vm = vlib_get_main (); - clib_error_t *error; u32 instance; u8 address[6]; u32 hw_if_index; vnet_hw_interface_t *hw_if; u32 slot; - int rv = 0; ASSERT (sw_if_indexp); *sw_if_indexp = (u32) ~ 0; - memset (address, 0, sizeof (address)); + clib_memset (address, 0, sizeof (address)); /* * Allocate a loopback instance. Either select on dynamically @@ -776,18 +876,11 @@ vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address, address[5] = instance; } - error = ethernet_register_interface - (vnm, - ethernet_simulated_device_class.index, instance, address, &hw_if_index, - /* flag change */ 0); - - if (error) - { - rv = VNET_API_ERROR_INVALID_REGISTRATION; - clib_error_report (error); - return rv; - } - + vnet_eth_interface_registration_t eir = {}; + eir.dev_class_index = ethernet_simulated_device_class.index; + eir.dev_instance = instance; + eir.address = address; + hw_if_index = vnet_eth_register_interface (vnm, &eir); hw_if = vnet_get_hw_interface (vnm, hw_if_index); slot = vlib_node_add_named_next_with_slot (vm, hw_if->tx_node_index, @@ -822,7 +915,7 @@ create_simulated_ethernet_interfaces (vlib_main_t * vm, u8 is_specified = 0; u32 user_instance = 0; - memset (mac_address, 0, sizeof (mac_address)); + clib_memset (mac_address, 0, sizeof (mac_address)); while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -893,6 +986,47 @@ ethernet_get_interface (ethernet_main_t * em, u32 hw_if_index) index ? pool_elt_at_index (em->interfaces, i->hw_instance) : 0); } +mac_address_t * +ethernet_interface_add_del_address (ethernet_main_t * em, + u32 hw_if_index, const u8 * address, + u8 is_add) +{ + ethernet_interface_t *ei = ethernet_get_interface (em, hw_if_index); + ethernet_interface_address_t *if_addr = 0; + int found = 0; + + /* return if there is not an ethernet interface for this hw interface */ + if (!ei) + return 0; + + /* determine whether the address is configured on the interface */ + vec_foreach (if_addr, ei->secondary_addrs) + { + if (ethernet_mac_address_equal (if_addr->mac.bytes, address)) + { + found = 1; + break; + } + } + + if (is_add) + { + if (!found) + { + /* address not found yet: add it */ + vec_add2 (ei->secondary_addrs, if_addr, 1); + ethernet_interface_address_copy (if_addr, address); + } + return &if_addr->mac; + } + + /* delete case */ + if (found) + vec_delete (ei->secondary_addrs, 1, if_addr - ei->secondary_addrs); + + return 0; +} + int vnet_delete_loopback_interface (u32 sw_if_index) { @@ -913,6 +1047,48 @@ vnet_delete_loopback_interface (u32 sw_if_index) return 0; } +int +vnet_create_sub_interface (u32 sw_if_index, u32 id, + u32 flags, u16 inner_vlan_id, u16 outer_vlan_id, + u32 * sub_sw_if_index) +{ + vnet_main_t *vnm = vnet_get_main (); + vnet_interface_main_t *im = &vnm->interface_main; + vnet_hw_interface_t *hi; + u64 sup_and_sub_key = ((u64) (sw_if_index) << 32) | (u64) id; + vnet_sw_interface_t template; + uword *p; + u64 *kp; + + hi = vnet_get_sup_hw_interface (vnm, sw_if_index); + + p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key); + if (p) + { + return (VNET_API_ERROR_VLAN_ALREADY_EXISTS); + } + + clib_memset (&template, 0, sizeof (template)); + template.type = VNET_SW_INTERFACE_TYPE_SUB; + template.flood_class = VNET_FLOOD_CLASS_NORMAL; + template.sup_sw_if_index = sw_if_index; + template.sub.id = id; + template.sub.eth.raw_flags = flags; + template.sub.eth.outer_vlan_id = outer_vlan_id; + template.sub.eth.inner_vlan_id = inner_vlan_id; + + if (vnet_create_sw_interface (vnm, &template, sub_sw_if_index)) + return (VNET_API_ERROR_UNSPECIFIED); + + kp = clib_mem_alloc (sizeof (*kp)); + *kp = sup_and_sub_key; + + hash_set (hi->sub_interface_sw_if_index_by_id, id, *sub_sw_if_index); + hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, *sub_sw_if_index); + + return (0); +} + int vnet_delete_sub_interface (u32 sw_if_index) { @@ -1050,6 +1226,36 @@ VLIB_CLI_COMMAND (delete_sub_interface_command, static) = { }; /* *INDENT-ON* */ +/* ethernet { ... } configuration. */ +/*? + * + * @cfgcmd{default-mtu <n>} + * Specify the default mtu in the range of 64-9000. The default is 9000 bytes. + * + */ +static clib_error_t * +ethernet_config (vlib_main_t * vm, unformat_input_t * input) +{ + ethernet_main_t *em = ðernet_main; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "default-mtu %u", &em->default_mtu)) + { + if (em->default_mtu < 64 || em->default_mtu > 9000) + return clib_error_return (0, "default MTU must be >=64, <=9000"); + } + else + { + return clib_error_return (0, "unknown input '%U'", + format_unformat_error, input); + } + } + return 0; +} + +VLIB_CONFIG_FUNCTION (ethernet_config, "ethernet"); + /* * fd.io coding-style-patch-verification: ON *