ethernet_type_t type;
uword n_bytes = sizeof (h[0]);
u8 *rewrite = NULL;
+ u8 is_p2p = 0;
+ if ((sub_sw->type == VNET_SW_INTERFACE_TYPE_P2P) ||
+ (sub_sw->type == VNET_SW_INTERFACE_TYPE_PIPE))
+ is_p2p = 1;
if (sub_sw != sup_sw)
{
if (sub_sw->sub.eth.flags.one_tag)
{
n_bytes += 2 * (sizeof (ethernet_vlan_header_t));
}
- // Check for encaps that are not supported for L3 interfaces
- if (!(sub_sw->sub.eth.flags.exact_match) ||
- (sub_sw->sub.eth.flags.default_sub) ||
- (sub_sw->sub.eth.flags.outer_vlan_id_any) ||
- (sub_sw->sub.eth.flags.inner_vlan_id_any))
+ else if (PREDICT_FALSE (is_p2p))
{
- return 0;
+ n_bytes = sizeof (ethernet_header_t);
+ }
+ if (PREDICT_FALSE (!is_p2p))
+ {
+ // Check for encaps that are not supported for L3 interfaces
+ if (!(sub_sw->sub.eth.flags.exact_match) ||
+ (sub_sw->sub.eth.flags.default_sub) ||
+ (sub_sw->sub.eth.flags.outer_vlan_id_any) ||
+ (sub_sw->sub.eth.flags.inner_vlan_id_any))
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ n_bytes = sizeof (ethernet_header_t);
}
}
#define _(a,b) case VNET_LINK_##a: type = ETHERNET_TYPE_##b; break
_(IP4, IP4);
_(IP6, IP6);
- _(MPLS, MPLS_UNICAST);
+ _(MPLS, MPLS);
_(ARP, ARP);
#undef _
default:
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));
- if (dst_address)
- clib_memcpy (h->dst_address, dst_address, sizeof (h->dst_address));
+ if (is_p2p)
+ {
+ clib_memcpy (h->dst_address, sub_sw->p2p.client_mac,
+ sizeof (h->dst_address));
+ }
else
- memset (h->dst_address, ~0, sizeof (h->dst_address)); /* broadcast */
+ {
+ 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 */
+ }
- if (sub_sw->sub.eth.flags.one_tag)
+ if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.one_tag)
{
ethernet_vlan_header_t *outer = (void *) (h + 1);
outer->type = clib_host_to_net_u16 (type);
}
- else if (sub_sw->sub.eth.flags.two_tags)
+ else if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.two_tags)
{
ethernet_vlan_header_t *outer = (void *) (h + 1);
ethernet_vlan_header_t *inner = (void *) (outer + 1);
adj = adj_get (ai);
- if (FIB_PROTOCOL_IP4 == adj->ia_nh_proto)
+ 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);
}
ETHERNET_MIN_PACKET_BYTES;
hi->max_packet_bytes = hi->max_supported_packet_bytes =
ETHERNET_MAX_PACKET_BYTES;
- hi->per_packet_overhead_bytes =
- /* preamble */ 8 + /* inter frame gap */ 12;
/* Standard default ethernet MTU. */
- hi->max_l3_packet_bytes[VLIB_RX] = hi->max_l3_packet_bytes[VLIB_TX] = 9000;
+ vnet_sw_interface_set_mtu (vnm, hi->sw_if_index, 9000);
clib_memcpy (ei->address, address, sizeof (ei->address));
- vec_free (hi->hw_address);
vec_add (hi->hw_address, address, sizeof (ei->address));
if (error)
}
}
pool_put_index (em->vlan_pool, main_intf->dot1q_vlans);
+ main_intf->dot1q_vlans = 0;
}
if (main_intf->dot1ad_vlans)
{
}
}
pool_put_index (em->vlan_pool, main_intf->dot1ad_vlans);
+ main_intf->dot1ad_vlans = 0;
}
vnet_delete_hw_interface (vnm, hw_if_index);
u32 next_index = VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
u32 i, next_node_index, bvi_flag, sw_if_index;
u32 n_pkts = 0, n_bytes = 0;
- u32 cpu_index = vm->cpu_index;
+ u32 thread_index = vm->thread_index;
vnet_main_t *vnm = vnet_get_main ();
vnet_interface_main_t *im = &vnm->interface_main;
vlib_node_main_t *nm = &vm->node_main;
/* increment TX interface stat */
vlib_increment_combined_counter (im->combined_sw_if_counters +
- VNET_INTERFACE_COUNTER_TX, cpu_index,
- sw_if_index, n_pkts, n_bytes);
+ VNET_INTERFACE_COUNTER_TX,
+ thread_index, sw_if_index, n_pkts,
+ n_bytes);
}
return n_left_from;
};
/* *INDENT-ON* */
+
+/*
+ * Maintain a bitmap of allocated loopback instance numbers.
+ */
+#define LOOPBACK_MAX_INSTANCE (16 * 1024)
+
+static u32
+loopback_instance_alloc (u8 is_specified, u32 want)
+{
+ ethernet_main_t *em = ðernet_main;
+
+ /*
+ * Check for dynamically allocaetd instance number.
+ */
+ if (!is_specified)
+ {
+ u32 bit;
+
+ bit = clib_bitmap_first_clear (em->bm_loopback_instances);
+ if (bit >= LOOPBACK_MAX_INSTANCE)
+ {
+ return ~0;
+ }
+ em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
+ bit, 1);
+ return bit;
+ }
+
+ /*
+ * In range?
+ */
+ if (want >= LOOPBACK_MAX_INSTANCE)
+ {
+ return ~0;
+ }
+
+ /*
+ * Already in use?
+ */
+ if (clib_bitmap_get (em->bm_loopback_instances, want))
+ {
+ return ~0;
+ }
+
+ /*
+ * Grant allocation request.
+ */
+ em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
+ want, 1);
+
+ return want;
+}
+
+static int
+loopback_instance_free (u32 instance)
+{
+ ethernet_main_t *em = ðernet_main;
+
+ if (instance >= LOOPBACK_MAX_INSTANCE)
+ {
+ return -1;
+ }
+
+ if (clib_bitmap_get (em->bm_loopback_instances, instance) == 0)
+ {
+ return -1;
+ }
+
+ em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
+ instance, 0);
+ return 0;
+}
+
int
-vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address)
+vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address,
+ u8 is_specified, u32 user_instance)
{
vnet_main_t *vnm = vnet_get_main ();
vlib_main_t *vm = vlib_get_main ();
clib_error_t *error;
- static u32 instance;
+ u32 instance;
u8 address[6];
u32 hw_if_index;
vnet_hw_interface_t *hw_if;
memset (address, 0, sizeof (address));
+ /*
+ * Allocate a loopback instance. Either select on dynamically
+ * or try to use the desired user_instance number.
+ */
+ instance = loopback_instance_alloc (is_specified, user_instance);
+ if (instance == ~0)
+ {
+ return VNET_API_ERROR_INVALID_REGISTRATION;
+ }
+
/*
* Default MAC address (dead:0000:0000 + instance) is allocated
* if zero mac_address is configured. Otherwise, user-configurable MAC
error = ethernet_register_interface
(vnm,
- ethernet_simulated_device_class.index, instance++, address, &hw_if_index,
+ ethernet_simulated_device_class.index, instance, address, &hw_if_index,
/* flag change */ 0);
if (error)
{
vnet_sw_interface_t *si = vnet_get_hw_sw_interface (vnm, hw_if_index);
*sw_if_indexp = si->sw_if_index;
+
+ /* By default don't flood to loopbacks, as packets just keep
+ * coming back ... If this loopback becomes a BVI, we'll change it */
+ si->flood_class = VNET_FLOOD_CLASS_NO_FLOOD;
}
return 0;
int rv;
u32 sw_if_index;
u8 mac_address[6];
+ u8 is_specified = 0;
+ u32 user_instance = 0;
memset (mac_address, 0, sizeof (mac_address));
{
if (unformat (input, "mac %U", unformat_ethernet_address, mac_address))
;
+ if (unformat (input, "instance %d", &user_instance))
+ is_specified = 1;
else
break;
}
- rv = vnet_create_loopback_interface (&sw_if_index, mac_address);
+ rv = vnet_create_loopback_interface (&sw_if_index, mac_address,
+ is_specified, user_instance);
if (rv)
return clib_error_return (0, "vnet_create_loopback_interface failed");
*
* @cliexpar
* The following two command syntaxes are equivalent:
- * @cliexcmd{loopback create-interface [mac <mac-addr>]}
- * @cliexcmd{create loopback interface [mac <mac-addr>]}
+ * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
+ * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
* Example of how to create a loopback interface:
* @cliexcmd{loopback create-interface}
?*/
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (create_simulated_ethernet_interface_command, static) = {
.path = "loopback create-interface",
- .short_help = "loopback create-interface [mac <mac-addr>]",
+ .short_help = "loopback create-interface [mac <mac-addr>] [instance <instance>]",
.function = create_simulated_ethernet_interfaces,
};
/* *INDENT-ON* */
*
* @cliexpar
* The following two command syntaxes are equivalent:
- * @cliexcmd{loopback create-interface [mac <mac-addr>]}
- * @cliexcmd{create loopback interface [mac <mac-addr>]}
+ * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
+ * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
* Example of how to create a loopback interface:
* @cliexcmd{create loopback interface}
?*/
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (create_loopback_interface_command, static) = {
.path = "create loopback interface",
- .short_help = "create loopback interface [mac <mac-addr>]",
+ .short_help = "create loopback interface [mac <mac-addr>] [instance <instance>]",
.function = create_simulated_ethernet_interfaces,
};
/* *INDENT-ON* */
{
vnet_main_t *vnm = vnet_get_main ();
vnet_sw_interface_t *si;
+ u32 hw_if_index;
+ vnet_hw_interface_t *hw;
+ u32 instance;
if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
return VNET_API_ERROR_INVALID_SW_IF_INDEX;
si = vnet_get_sw_interface (vnm, sw_if_index);
- ethernet_delete_interface (vnm, si->hw_if_index);
+ hw_if_index = si->hw_if_index;
+ hw = vnet_get_hw_interface (vnm, hw_if_index);
+ instance = hw->dev_instance;
+
+ if (loopback_instance_free (instance) < 0)
+ {
+ return VNET_API_ERROR_INVALID_SW_IF_INDEX;
+ }
+
+ ethernet_delete_interface (vnm, hw_if_index);
return 0;
}
vnet_delete_sub_interface (u32 sw_if_index)
{
vnet_main_t *vnm = vnet_get_main ();
+ vnet_sw_interface_t *si;
int rv = 0;
if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
return VNET_API_ERROR_INVALID_SW_IF_INDEX;
-
- vnet_interface_main_t *im = &vnm->interface_main;
- vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
-
- if (si->type == VNET_SW_INTERFACE_TYPE_SUB)
+ si = vnet_get_sw_interface (vnm, sw_if_index);
+ if (si->type == VNET_SW_INTERFACE_TYPE_SUB ||
+ si->type == VNET_SW_INTERFACE_TYPE_PIPE ||
+ si->type == VNET_SW_INTERFACE_TYPE_P2P)
{
- vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
+ vnet_interface_main_t *im = &vnm->interface_main;
+ vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
u64 sup_and_sub_key =
((u64) (si->sup_sw_if_index) << 32) | (u64) si->sub.id;
-
- hash_unset_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
+ hash_unset_mem_free (&im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
+ hash_unset (hi->sub_interface_sw_if_index_by_id, si->sub.id);
vnet_delete_sw_interface (vnm, sw_if_index);
}
else
- {
- rv = VNET_API_ERROR_INVALID_SUB_SW_IF_INDEX;
- }
+ rv = VNET_API_ERROR_INVALID_SUB_SW_IF_INDEX;
+
return rv;
}