* This file contains code to manage loopback interfaces.
*/
+const u8 *
+ethernet_ip4_mcast_dst_addr (void)
+{
+ const static u8 ethernet_mcast_dst_mac[] = {
+ 0x1, 0x0, 0x5e, 0x0, 0x0, 0x0,
+ };
+
+ return (ethernet_mcast_dst_mac);
+}
+
+const u8 *
+ethernet_ip6_mcast_dst_addr (void)
+{
+ const static u8 ethernet_mcast_dst_mac[] = {
+ 0x33, 0x33, 0x00, 0x0, 0x0, 0x0,
+ };
+
+ return (ethernet_mcast_dst_mac);
+}
+
/**
* @brief build a rewrite string to use for sending packets of type 'link_type'
* to 'dst_address'
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)
+ 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)
+ {
+ 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);
}
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)
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_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)
+ if (si->type == VNET_SW_INTERFACE_TYPE_SUB ||
+ si->type == VNET_SW_INTERFACE_TYPE_P2P)
{
vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
u64 sup_and_sub_key =