Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b1500e9fff | |||
| 9736d6f328 | |||
| 49ab961abf | |||
| fa729ec6cd | |||
| bc69426737 | |||
| 82103e9fe1 | |||
| 5ac8c6f1f3 | |||
| d4b5fdde42 | |||
| 6d52257a2d | |||
| 42382f5427 | |||
| 93dd1da259 | |||
| a37c63c6d8 | |||
| ecbca13d7e | |||
| 7037fde018 | |||
| 53b5233057 | |||
| 369dc2c67a | |||
| e0db09034a | |||
| 201c8e4d2a | |||
| 4ee279b03e | |||
| 4e4d3fd016 | |||
| 5e69119cdd | |||
| ab572152d9 | |||
| 550da2b75a | |||
| aecb10b97f | |||
| af3022f0e8 | |||
| 449f34e2f3 | |||
| e2e3c38be6 | |||
| 77d12df8eb | |||
| bc69eca2ab | |||
| 61f368a80f | |||
| 0f878da203 | |||
| 89c12dbe23 | |||
| 11974e5f5a | |||
| 8b4221ee8f | |||
| 04d4d92f96 | |||
| be955ef316 | |||
| 63f9e7cc0e | |||
| d3088e94ec | |||
| d657203443 | |||
| 00b060a778 | |||
| a3674c0e18 | |||
| 06107a7243 | |||
| 0762fbc46e | |||
| b5898d2f77 | |||
| 8337806b5f | |||
| 765ef37670 | |||
| b8e9009400 |
@@ -2,3 +2,4 @@
|
||||
host=gerrit.fd.io
|
||||
port=29418
|
||||
project=vpp
|
||||
defaultbranch=stable/2005
|
||||
|
||||
+749
-1
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ Google Sanitizers
|
||||
|
||||
VPP is instrumented to support `Google Sanitizers <https://github.com/google/sanitizers>`_.
|
||||
As of today, only `AddressSanitizer <https://github.com/google/sanitizers/wiki/AddressSanitizer>`_
|
||||
is supported and only for the heap.
|
||||
is supported, only for GCC and only for the heap.
|
||||
|
||||
AddressSanitizer
|
||||
================
|
||||
@@ -20,19 +20,19 @@ build option, so all VPP targets should be supported. For example:
|
||||
.. code-block:: console
|
||||
|
||||
# build a debug image with ASan support:
|
||||
$ make rebuild VPP_EXTRA_CMAKE_ARGS=-DENABLE_SANITIZE_ADDR=ON
|
||||
$ make rebuild VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON CC=gcc-8
|
||||
....
|
||||
|
||||
# build a release image with ASan support:
|
||||
$ make rebuild-release VPP_EXTRA_CMAKE_ARGS=-DENABLE_SANITIZE_ADDR=ON
|
||||
$ make rebuild-release VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON CC=gcc-8
|
||||
....
|
||||
|
||||
# build packages in debug mode with ASan support:
|
||||
$ make pkg-deb-debug VPP_EXTRA_CMAKE_ARGS=-DENABLE_SANITIZE_ADDR=ON
|
||||
$ make pkg-deb-debug VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON CC=gcc-8
|
||||
....
|
||||
|
||||
# run GBP plugin tests in debug mode with ASan
|
||||
$ make test-debug TEST=test_gbp VPP_EXTRA_CMAKE_ARGS=-DENABLE_SANITIZE_ADDR=ON
|
||||
$ make test-debug TEST=test_gbp VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON CC=gcc-8
|
||||
....
|
||||
|
||||
Once VPP has been built with ASan support you can use it as usual including
|
||||
|
||||
@@ -4,6 +4,7 @@ Test Framework Documentation {#test_framework_doc}
|
||||
PyDoc generated documentation for the "make test" framework is available for
|
||||
the following releases:
|
||||
|
||||
- [Test framework documentation for VPP 20.05](https://docs.fd.io/vpp/20.05/vpp_make_test/html)
|
||||
- [Test framework documentation for VPP 20.01](https://docs.fd.io/vpp/20.01/vpp_make_test/html)
|
||||
- [Test framework documentation for VPP 19.08](https://docs.fd.io/vpp/19.08/vpp_make_test/html)
|
||||
- [Test framework documentation for VPP 19.04](https://docs.fd.io/vpp/19.04/vpp_make_test/html)
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
---
|
||||
title: Home
|
||||
---
|
||||
|
||||
# VPP Status
|
||||
|
||||
### Here's the version...
|
||||
|
||||
VPP version: <div id="VPPversion"></div>
|
||||
|
||||
build date: <div id="VPPbuilddate"></div>
|
||||
|
||||
<div id="like_button_container"></div>
|
||||
|
||||
### Show Interface
|
||||
|
||||
<p>Enter the interface name, then click "Submit" to display interface stats:</p>
|
||||
|
||||
<input id="ifacename" type="text"></input>
|
||||
<button onclick="getStats()">Get Stats</button>
|
||||
|
||||
<div id="ifacestats"></div>
|
||||
|
||||
{{< rawhtml >}}
|
||||
|
||||
<script>
|
||||
function getStats() {
|
||||
var url="http://192.168.10.1:1234/interface_stats.json?";
|
||||
var iface=document.getElementById("ifacename").value;
|
||||
url=url.concat(iface);
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
mode: 'no-cors',
|
||||
cache: 'no-cache',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(function(obj) {
|
||||
console.log(obj)
|
||||
var result=obj.interface_stats.name;
|
||||
result = result.concat(": rx-pkts: ");
|
||||
result = result.concat(obj.interface_stats.rx_packets);
|
||||
result = result.concat(" rx-bytes: ");
|
||||
result = result.concat(obj.interface_stats.rx_bytes);
|
||||
result = result.concat(": tx-pkts: ");
|
||||
result = result.concat(obj.interface_stats.tx_packets);
|
||||
result = result.concat(" tx-bytes: ");
|
||||
result = result.concat(obj.interface_stats.tx_bytes);
|
||||
result = result.concat(" drops: ");
|
||||
result = result.concat(obj.interface_stats.drops);
|
||||
result = result.concat(" ip4: ");
|
||||
result = result.concat(obj.interface_stats.ip4);
|
||||
result = result.concat(" ip6: ");
|
||||
result = result.concat(obj.interface_stats.ip6);
|
||||
|
||||
document.getElementById("ifacestats").innerHTML=result;
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error);
|
||||
})}
|
||||
// unconditionally populate vpp version info ->
|
||||
fetch('http://192.168.10.1:1234/version.json', {
|
||||
method: 'GET',
|
||||
mode: 'no-cors',
|
||||
cache: 'no-cache',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(function(obj) {
|
||||
document.getElementById("VPPbuilddate").innerHTML=obj.vpp_details.build_date;
|
||||
document.getElementById("VPPversion").innerHTML=obj.vpp_details.version;
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error);
|
||||
});
|
||||
</script>
|
||||
|
||||
{{< /rawhtml >}}
|
||||
@@ -2605,10 +2605,12 @@ ixge_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hw, u32 flags)
|
||||
|
||||
old = r->filter_control;
|
||||
|
||||
if (flags & ETHERNET_INTERFACE_FLAG_ACCEPT_ALL)
|
||||
if (flags == ETHERNET_INTERFACE_FLAG_ACCEPT_ALL)
|
||||
r->filter_control = old | (1 << 9) /* unicast promiscuous */ ;
|
||||
else
|
||||
else if (flags == ETHERNET_INTERFACE_FLAGS_DEFAULT_L3)
|
||||
r->filter_control = old & ~(1 << 9);
|
||||
else
|
||||
return ~0;
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
+28
-17
@@ -1125,25 +1125,29 @@ avf_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hw, u32 flags)
|
||||
vlib_main_t *vm = vlib_get_main ();
|
||||
avf_main_t *am = &avf_main;
|
||||
avf_device_t *ad = vec_elt_at_index (am->devices, hw->dev_instance);
|
||||
if (ETHERNET_INTERFACE_FLAG_CONFIG_PROMISC (flags))
|
||||
clib_error_t *error;
|
||||
u8 promisc_enabled;
|
||||
|
||||
switch (flags)
|
||||
{
|
||||
clib_error_t *error;
|
||||
int promisc_enabled = (flags & ETHERNET_INTERFACE_FLAG_ACCEPT_ALL) != 0;
|
||||
u32 new_flags = promisc_enabled ?
|
||||
ad->flags | AVF_DEVICE_F_PROMISC : ad->flags & ~AVF_DEVICE_F_PROMISC;
|
||||
|
||||
if (new_flags == ad->flags)
|
||||
return flags;
|
||||
|
||||
if ((error = avf_config_promisc_mode (vm, ad, promisc_enabled)))
|
||||
{
|
||||
avf_log_err (ad, "%s: %U", format_clib_error, error);
|
||||
clib_error_free (error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ad->flags = new_flags;
|
||||
case ETHERNET_INTERFACE_FLAG_DEFAULT_L3:
|
||||
ad->flags &= ~AVF_DEVICE_F_PROMISC;
|
||||
break;
|
||||
case ETHERNET_INTERFACE_FLAG_ACCEPT_ALL:
|
||||
ad->flags |= AVF_DEVICE_F_PROMISC;
|
||||
break;
|
||||
default:
|
||||
return ~0;
|
||||
}
|
||||
|
||||
promisc_enabled = ((ad->flags & AVF_DEVICE_F_PROMISC) != 0);
|
||||
if ((error = avf_config_promisc_mode (vm, ad, promisc_enabled)))
|
||||
{
|
||||
avf_log_err (ad, "%s: %U", format_clib_error, error);
|
||||
clib_error_free (error);
|
||||
return ~0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1470,6 +1474,13 @@ avf_create_if (vlib_main_t * vm, avf_create_if_args_t * args)
|
||||
if (error)
|
||||
goto error;
|
||||
|
||||
/* Indicate ability to support L3 DMAC filtering and
|
||||
* initialize interface to L3 non-promisc mode */
|
||||
vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, ad->hw_if_index);
|
||||
hi->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_MAC_FILTER;
|
||||
ethernet_set_flags (vnm, ad->hw_if_index,
|
||||
ETHERNET_INTERFACE_FLAG_DEFAULT_L3);
|
||||
|
||||
vnet_sw_interface_t *sw = vnet_get_hw_sw_interface (vnm, ad->hw_if_index);
|
||||
args->sw_if_index = ad->sw_if_index = sw->sw_if_index;
|
||||
|
||||
|
||||
@@ -76,7 +76,8 @@ openssl_ops_enc_cbc (vlib_main_t * vm, vnet_crypto_op_t * ops[],
|
||||
int out_len = 0;
|
||||
int iv_len;
|
||||
|
||||
if (op->op == VNET_CRYPTO_OP_3DES_CBC_ENC)
|
||||
if (op->op == VNET_CRYPTO_OP_3DES_CBC_ENC
|
||||
|| op->op == VNET_CRYPTO_OP_DES_CBC_ENC)
|
||||
iv_len = 8;
|
||||
else
|
||||
iv_len = 16;
|
||||
|
||||
@@ -91,6 +91,7 @@ dpdk_buffer_pool_init (vlib_main_t * vm, vlib_buffer_pool_t * bp)
|
||||
rte_mempool_set_ops_byname (nmp, "vpp-no-cache", NULL);
|
||||
|
||||
/* Call the mempool priv initializer */
|
||||
memset (&priv, 0, sizeof (priv));
|
||||
priv.mbuf_data_room_size = VLIB_BUFFER_PRE_DATA_SIZE +
|
||||
vlib_buffer_get_default_data_size (vm);
|
||||
priv.mbuf_priv_size = VLIB_BUFFER_HDR_SIZE;
|
||||
|
||||
@@ -113,30 +113,33 @@ dpdk_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi, u32 flags)
|
||||
{
|
||||
dpdk_main_t *dm = &dpdk_main;
|
||||
dpdk_device_t *xd = vec_elt_at_index (dm->devices, hi->dev_instance);
|
||||
u32 old = 0;
|
||||
u32 old = (xd->flags & DPDK_DEVICE_FLAG_PROMISC) != 0;
|
||||
|
||||
if (ETHERNET_INTERFACE_FLAG_CONFIG_PROMISC (flags))
|
||||
{
|
||||
old = (xd->flags & DPDK_DEVICE_FLAG_PROMISC) != 0;
|
||||
|
||||
if (flags & ETHERNET_INTERFACE_FLAG_ACCEPT_ALL)
|
||||
xd->flags |= DPDK_DEVICE_FLAG_PROMISC;
|
||||
else
|
||||
xd->flags &= ~DPDK_DEVICE_FLAG_PROMISC;
|
||||
|
||||
if (xd->flags & DPDK_DEVICE_FLAG_ADMIN_UP)
|
||||
{
|
||||
if (xd->flags & DPDK_DEVICE_FLAG_PROMISC)
|
||||
rte_eth_promiscuous_enable (xd->port_id);
|
||||
else
|
||||
rte_eth_promiscuous_disable (xd->port_id);
|
||||
}
|
||||
}
|
||||
else if (ETHERNET_INTERFACE_FLAG_CONFIG_MTU (flags))
|
||||
switch (flags)
|
||||
{
|
||||
case ETHERNET_INTERFACE_FLAG_DEFAULT_L3:
|
||||
/* set to L3/non-promisc mode */
|
||||
xd->flags &= ~DPDK_DEVICE_FLAG_PROMISC;
|
||||
break;
|
||||
case ETHERNET_INTERFACE_FLAG_ACCEPT_ALL:
|
||||
xd->flags |= DPDK_DEVICE_FLAG_PROMISC;
|
||||
break;
|
||||
case ETHERNET_INTERFACE_FLAG_MTU:
|
||||
xd->port_conf.rxmode.max_rx_pkt_len = hi->max_packet_bytes;
|
||||
dpdk_device_setup (xd);
|
||||
return 0;
|
||||
default:
|
||||
return ~0;
|
||||
}
|
||||
|
||||
if (xd->flags & DPDK_DEVICE_FLAG_ADMIN_UP)
|
||||
{
|
||||
if (xd->flags & DPDK_DEVICE_FLAG_PROMISC)
|
||||
rte_eth_promiscuous_enable (xd->port_id);
|
||||
else
|
||||
rte_eth_promiscuous_disable (xd->port_id);
|
||||
}
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
@@ -737,6 +740,12 @@ dpdk_lib_init (dpdk_main_t * dm)
|
||||
hi->max_packet_bytes = mtu;
|
||||
hi->max_supported_packet_bytes = max_rx_frame;
|
||||
hi->numa_node = xd->cpu_socket;
|
||||
|
||||
/* Indicate ability to support L3 DMAC filtering and
|
||||
* initialize interface to L3 non-promisc mode */
|
||||
hi->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_MAC_FILTER;
|
||||
ethernet_set_flags (dm->vnet_main, xd->hw_if_index,
|
||||
ETHERNET_INTERFACE_FLAG_DEFAULT_L3);
|
||||
}
|
||||
|
||||
if (dm->conf->no_tx_checksum_offload == 0)
|
||||
|
||||
@@ -1118,10 +1118,11 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
|
||||
{
|
||||
if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
|
||||
{
|
||||
udp0->src_port = s0->out2in.port;
|
||||
if (PREDICT_FALSE (udp0->checksum))
|
||||
{
|
||||
old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
|
||||
new_port0 = udp0->src_port = s0->out2in.port;
|
||||
new_port0 = udp0->src_port;
|
||||
sum0 = udp0->checksum;
|
||||
sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address /* changed member */
|
||||
);
|
||||
@@ -1325,10 +1326,11 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
|
||||
{
|
||||
if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
|
||||
{
|
||||
udp1->src_port = s1->out2in.port;
|
||||
if (PREDICT_FALSE (udp1->checksum))
|
||||
{
|
||||
old_port1 = vnet_buffer (b1)->ip.reass.l4_src_port;
|
||||
new_port1 = udp1->src_port = s1->out2in.port;
|
||||
new_port1 = udp1->src_port;
|
||||
sum1 = udp1->checksum;
|
||||
sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t, dst_address /* changed member */
|
||||
);
|
||||
@@ -1567,10 +1569,11 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
|
||||
{
|
||||
if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
|
||||
{
|
||||
udp0->src_port = s0->out2in.port;
|
||||
if (PREDICT_FALSE (udp0->checksum))
|
||||
{
|
||||
old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
|
||||
new_port0 = udp0->src_port = s0->out2in.port;
|
||||
new_port0 = udp0->src_port;
|
||||
sum0 = udp0->checksum;
|
||||
sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address /* changed member */
|
||||
);
|
||||
|
||||
@@ -386,7 +386,6 @@ slow_path_ed (snat_main_t * sm,
|
||||
{
|
||||
nat_elog_notice ("addresses exhausted");
|
||||
b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
|
||||
nat_free_session_data (sm, s, thread_index, 0);
|
||||
nat_ed_session_delete (sm, s, thread_index, 1);
|
||||
return NAT_NEXT_DROP;
|
||||
}
|
||||
|
||||
@@ -493,6 +493,7 @@ snat_ipfix_header_create (flow_report_main_t * frm,
|
||||
u32 stream_index;
|
||||
ip4_header_t *ip;
|
||||
udp_header_t *udp;
|
||||
vlib_main_t *vm = vlib_get_main ();
|
||||
|
||||
stream_index = clib_atomic_fetch_or(&silm->stream_index, 0);
|
||||
stream = &frm->streams[stream_index];
|
||||
@@ -521,7 +522,7 @@ snat_ipfix_header_create (flow_report_main_t * frm,
|
||||
|
||||
h->export_time = clib_host_to_net_u32 ((u32)
|
||||
(((f64) frm->unix_time_0) +
|
||||
(vlib_time_now (frm->vlib_main) -
|
||||
(vlib_time_now (vm) -
|
||||
frm->vlib_time_0)));
|
||||
|
||||
sequence_number = clib_atomic_fetch_add (&stream->sequence_number, 1);
|
||||
|
||||
@@ -4712,6 +4712,53 @@ class TestNAT44EndpointDependent(MethodHolder):
|
||||
sessions = self.statistics.get_counter('/nat44/total-sessions')
|
||||
self.assertEqual(sessions[0][0], 3)
|
||||
|
||||
def test_dynamic_out_of_ports(self):
|
||||
""" NAT44 dynamic translation test: out of ports """
|
||||
|
||||
flags = self.config_flags.NAT_IS_INSIDE
|
||||
self.vapi.nat44_interface_add_del_feature(
|
||||
sw_if_index=self.pg0.sw_if_index,
|
||||
flags=flags, is_add=1)
|
||||
self.vapi.nat44_interface_add_del_feature(
|
||||
sw_if_index=self.pg1.sw_if_index,
|
||||
is_add=1)
|
||||
|
||||
nat_config = self.vapi.nat_show_config()
|
||||
self.assertEqual(1, nat_config.endpoint_dependent)
|
||||
|
||||
# in2out and no NAT addresses added
|
||||
err_old = self.statistics.get_err_counter(
|
||||
'/err/nat44-ed-in2out-slowpath/out of ports')
|
||||
|
||||
pkts = self.create_stream_in(self.pg0, self.pg1)
|
||||
self.pg0.add_stream(pkts)
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.pg_start()
|
||||
self.pg1.get_capture(0, timeout=1)
|
||||
|
||||
err_new = self.statistics.get_err_counter(
|
||||
'/err/nat44-ed-in2out-slowpath/out of ports')
|
||||
|
||||
self.assertEqual(err_new - err_old, len(pkts))
|
||||
|
||||
# in2out after NAT addresses added
|
||||
self.nat44_add_address(self.nat_addr)
|
||||
|
||||
err_old = self.statistics.get_err_counter(
|
||||
'/err/nat44-ed-in2out-slowpath/out of ports')
|
||||
|
||||
pkts = self.create_stream_in(self.pg0, self.pg1)
|
||||
self.pg0.add_stream(pkts)
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.pg_start()
|
||||
capture = self.pg1.get_capture(len(pkts))
|
||||
self.verify_capture_out(capture)
|
||||
|
||||
err_new = self.statistics.get_err_counter(
|
||||
'/err/nat44-ed-in2out-slowpath/out of ports')
|
||||
|
||||
self.assertEqual(err_new, err_old)
|
||||
|
||||
def test_dynamic_output_feature_vrf(self):
|
||||
""" NAT44 dynamic translation test: output-feature, VRF"""
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ rdma_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hw, u32 flags)
|
||||
|
||||
switch (flags)
|
||||
{
|
||||
case 0:
|
||||
case ETHERNET_INTERFACE_FLAG_DEFAULT_L3:
|
||||
return rdma_dev_set_ucast (rd);
|
||||
case ETHERNET_INTERFACE_FLAG_ACCEPT_ALL:
|
||||
return rdma_dev_set_promisc (rd);
|
||||
@@ -339,9 +339,18 @@ rdma_async_event_cleanup (rdma_device_t * rd)
|
||||
static clib_error_t *
|
||||
rdma_register_interface (vnet_main_t * vnm, rdma_device_t * rd)
|
||||
{
|
||||
return ethernet_register_interface (vnm, rdma_device_class.index,
|
||||
rd->dev_instance, rd->hwaddr.bytes,
|
||||
&rd->hw_if_index, rdma_flag_change);
|
||||
clib_error_t *err =
|
||||
ethernet_register_interface (vnm, rdma_device_class.index,
|
||||
rd->dev_instance, rd->hwaddr.bytes,
|
||||
&rd->hw_if_index, rdma_flag_change);
|
||||
|
||||
/* Indicate ability to support L3 DMAC filtering and
|
||||
* initialize interface to L3 non-promisc mode */
|
||||
vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, rd->hw_if_index);
|
||||
hi->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_MAC_FILTER;
|
||||
ethernet_set_flags (vnm, rd->hw_if_index,
|
||||
ETHERNET_INTERFACE_FLAG_DEFAULT_L3);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -3,22 +3,29 @@ SRv6 Mobile User Plane Plugins {#srv6_mobile_plugin_doc}
|
||||
|
||||
# Introduction
|
||||
|
||||
This plugin module can provide the stateless mobile user plane protocols translation between GTP-U and SRv6. The functions of the translation take advantage of SRv6 network programmability.
|
||||
This plugin module can provide the stateless mobile user plane protocols translation between GTP-U and SRv6. The plugin also provides FIB table lookup for an IPv4/IPv6 packet encapsulated in GTP-U. These plugin functions take advantage of SRv6 network programmability.
|
||||
|
||||
[SRv6 Mobile User Plane](https://tools.ietf.org/html/draft-ietf-dmm-srv6-mobile-uplane) defines the user plane protocol using SRv6
|
||||
including following stateless translation functions:
|
||||
|
||||
- **T.M.GTP4.D:**
|
||||
- **T.M.GTP4.D:**
|
||||
GTP-U over UDP/IPv4 -> SRv6
|
||||
- **End.M.GTP4.E:**
|
||||
- **End.M.GTP4.E:**
|
||||
SRv6 -> GTP-U over UDP/IPv4
|
||||
- **End.M.GTP6.D:**
|
||||
- **End.M.GTP6.D:**
|
||||
GTP-U over UDP/IPv6 -> SRv6
|
||||
- **End.M.GTP6.E:**
|
||||
- **End.M.GTP6.E:**
|
||||
SRv6 -> GTP-U over UDP/IPv6
|
||||
|
||||
These functions benefit user plane(overlay) to be able to utilize data plane(underlay) networks properly. And also it benefits data plane to be able to handle user plane in routing paradigm.
|
||||
|
||||
In addition to the above functions, the plugin supports following functions:
|
||||
|
||||
- **T.M.GTP4.DT{4|6|46}:**
|
||||
FIB table lookup for IPv4/IP6 encapsulated in GTP-U over UDP/IPv4
|
||||
- **End.M.GTP6.DT{4|6|46}:**
|
||||
FIB table lookup for IPv4/IP6 encapsulated in GTP-U over UDP/IPv6
|
||||
|
||||
Noted that the prefix of function names follow naming convention of SRv6 network programming. "T" means transit function, "End" means end function, "M" means Mobility specific function. The suffix "D" and "E" mean that "decapsulation" and "encapsulation" respectively.
|
||||
|
||||
|
||||
@@ -138,5 +145,57 @@ For example, the below command configures the SID prefix 2001:db8::/64 with `end
|
||||
sr localsid prefix 2001:db8::/64 behavior end.m.gtp6.e
|
||||
```
|
||||
|
||||
## FIB Table Lookup for Inner IPv4/IPv6 packet
|
||||
|
||||
SRv6 Mobile functions of `t.m.gtp4.dt*` and `end.m.gtp6.dt*` support decapsulating outer IP/UDP/GTP-U headers and forwarding inner IP packet based on specific fib table.
|
||||
|
||||
In case of the both outer and inner IP address families are IPv4, `t.m.gtp4.dt4` function supports GTP-U decapsulation and fib lookup for inner IPv4 with an associated steering policy and the following parameters:
|
||||
|
||||
- SID: A SRv6 SID to represents the function
|
||||
- FIB: fib-table number for inner IPv4 packet lookup and forwarding
|
||||
|
||||
The following command instantiates a new T.M.GTP4.DT4 function.
|
||||
|
||||
```
|
||||
sr policy add bsid SID behavior t.m.gtp4.dt4 fib-table FIB
|
||||
```
|
||||
|
||||
For example, the below commands configure D5:: as the SID instantiates `t.m.gtp4.dt4` function. A steering policy for packets destine to 172.20.0.1 binds to the SID.
|
||||
|
||||
```
|
||||
sr steer l3 172.20.0.1/32 via bsid D5::
|
||||
sr policy add bsid D5:: behavior t.m.gtp4.dt4 fib-table 0
|
||||
```
|
||||
|
||||
In addition, inner IPv6, or mix of IPv4 and IPv6 inner packet cases require the function to be configured with local-fib table.
|
||||
|
||||
- LOCAL-FIB: fib-table number for lookup and forward GTP-U packet based on outer IP destination address
|
||||
|
||||
This is inner IPv6 case specific. The reason is that GTP-U encapsulates link local IPv6 packet for NDP (Neighber Discovery Protocol). Outer GTP-U header should be kept until the packets reach to the node responsible for NDP handling. It is typically UPF(User Plane Function) node.
|
||||
|
||||
The following command instantiate a new T.M.GTP4.DT6 function.
|
||||
|
||||
```
|
||||
sr policy add bsid D5:: behavior t.m.gtp4.dt6 fib-table 0 local-fib-table LOCAL-FIB
|
||||
```
|
||||
|
||||
Following example configures fib 0 for inner packet and fib 1 for outer GTP-U packet forwarding:
|
||||
|
||||
```
|
||||
sr policy add bsid D5:: behavior t.m.gtp4.dt6 fib-table 0 local-fib-table 1
|
||||
```
|
||||
|
||||
If you need to suport both IPv4 and IPv6 inner packet lookup with just one SID, you can configure `t.m.gtp4.dt46` function:
|
||||
|
||||
```
|
||||
sr policy add bsid D5:: behavior t.m.gtp4.dt46 fib-table 0 local-fib-table 1
|
||||
```
|
||||
|
||||
In case of GTP-U over IPv6 case, `end.m.gtp6.dt4`, `end.m.gtp6.dt6` and `end.m.gtp6.dt46` functions support inner IPv4, IPv6 and IPv4/IPv6 lookup and forwarding respectively. Specifiyng fib table for inner IP packet forwarding is required as same as GTP-U over IPv4 case, and local-fib table for inner IPv6 and IPv4/IPv6 cases as well.
|
||||
|
||||
```
|
||||
sr localsid prefix D::/64 behavior end.m.gtp6.dt46 fib-table 0 local-fib-table 0
|
||||
```
|
||||
|
||||
To run some demo setup please refer to: @subpage srv6_mobile_runner_doc
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <vnet/vnet.h>
|
||||
#include <vnet/pg/pg.h>
|
||||
#include <vppinfra/error.h>
|
||||
#include <vppinfra/mpcap.h>
|
||||
#include <vnet/mpcap.h>
|
||||
#include <vnet/ethernet/ethernet.h>
|
||||
|
||||
static mpcap_main_t test_mpcap_main = {
|
||||
|
||||
@@ -637,6 +637,32 @@ tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
|
||||
TCP_TEST ((sb->rxt_sacked == 300), "last rxt sacked bytes %d",
|
||||
sb->rxt_sacked);
|
||||
|
||||
/*
|
||||
* Restart
|
||||
*/
|
||||
scoreboard_clear (sb);
|
||||
vec_reset_length (tc->rcv_opts.sacks);
|
||||
|
||||
/*
|
||||
* Broken sacks:
|
||||
* block.start > snd_nxt
|
||||
* && block.start < blk.end
|
||||
* && block.end <= snd_nxt
|
||||
*/
|
||||
tc->flags = 0;
|
||||
block.start = 2147483647;
|
||||
block.end = 4294967295;
|
||||
vec_add1 (tc->rcv_opts.sacks, block);
|
||||
tc->snd_una = tc->snd_nxt = 1969067947;
|
||||
|
||||
tcp_rcv_sacks (tc, tc->snd_una);
|
||||
|
||||
/*
|
||||
* Clear
|
||||
*/
|
||||
scoreboard_clear (sb);
|
||||
vec_reset_length (tc->rcv_opts.sacks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -2901,7 +2901,7 @@ unformat_nsh_address (unformat_input_t * input, va_list * args)
|
||||
return unformat (input, "SPI:%d SI:%d", &nsh->spi, &nsh->si);
|
||||
}
|
||||
|
||||
u8 *
|
||||
static u8 *
|
||||
format_nsh_address_vat (u8 * s, va_list * args)
|
||||
{
|
||||
nsh_t *a = va_arg (*args, nsh_t *);
|
||||
@@ -2958,7 +2958,7 @@ vl_api_one_eid_table_details_t_handler (vl_api_one_eid_table_details_t * mp)
|
||||
s = format (0, "%d", clib_net_to_host_u32 (mp->locator_set_index));
|
||||
|
||||
eid = format (0, "%U", format_lisp_eid_vat,
|
||||
mp->deid, mp->seid, mp->is_src_dst);
|
||||
&mp->deid, &mp->seid, mp->is_src_dst);
|
||||
vec_add1 (eid, 0);
|
||||
|
||||
print (vam->ofp, "[%d] %-35s%-20s%-30s%-20d%-20d%-10d%-20s",
|
||||
@@ -3007,7 +3007,7 @@ vl_api_one_eid_table_details_t_handler_json (vl_api_one_eid_table_details_t
|
||||
else
|
||||
{
|
||||
eid = format (0, "%U", format_lisp_eid_vat,
|
||||
mp->deid, mp->seid, mp->is_src_dst);
|
||||
&mp->deid, &mp->seid, mp->is_src_dst);
|
||||
vec_add1 (eid, 0);
|
||||
vat_json_object_add_string_copy (node, "eid", eid);
|
||||
vec_free (eid);
|
||||
@@ -3031,9 +3031,9 @@ vl_api_one_stats_details_t_handler (vl_api_one_stats_details_t * mp)
|
||||
u8 *seid = 0, *deid = 0;
|
||||
ip46_address_t lloc, rloc;
|
||||
|
||||
deid = format (0, "%U", format_lisp_eid_vat, mp->deid, 0);
|
||||
deid = format (0, "%U", format_lisp_eid_vat, &mp->deid, 0, 0);
|
||||
|
||||
seid = format (0, "%U", format_lisp_eid_vat, mp->seid, 0);
|
||||
seid = format (0, "%U", format_lisp_eid_vat, &mp->seid, 0, 0);
|
||||
|
||||
vec_add1 (deid, 0);
|
||||
vec_add1 (seid, 0);
|
||||
@@ -3079,9 +3079,9 @@ vl_api_one_stats_details_t_handler_json (vl_api_one_stats_details_t * mp)
|
||||
node = vat_json_array_add (&vam->json_tree);
|
||||
|
||||
vat_json_init_object (node);
|
||||
deid = format (0, "%U", format_lisp_eid_vat, mp->deid, 0);
|
||||
deid = format (0, "%U", format_lisp_eid_vat, &mp->deid, 0, 0);
|
||||
|
||||
seid = format (0, "%U", format_lisp_eid_vat, mp->seid, 0);
|
||||
seid = format (0, "%U", format_lisp_eid_vat, &mp->seid, 0, 0);
|
||||
|
||||
vec_add1 (deid, 0);
|
||||
vec_add1 (seid, 0);
|
||||
|
||||
+20
-9
@@ -477,17 +477,11 @@ writev (int fd, const struct iovec * iov, int iovcnt)
|
||||
return size;
|
||||
}
|
||||
|
||||
int
|
||||
fcntl (int fd, int cmd, ...)
|
||||
static int
|
||||
fcntl_internal (int fd, int cmd, va_list ap)
|
||||
{
|
||||
vls_handle_t vlsh;
|
||||
int rv = 0;
|
||||
va_list ap;
|
||||
|
||||
if ((errno = -ldp_init ()))
|
||||
return -1;
|
||||
|
||||
va_start (ap, cmd);
|
||||
|
||||
vlsh = ldp_fd_to_vlsh (fd);
|
||||
LDBG (0, "fd %u vlsh %d, cmd %u", fd, vlsh, cmd);
|
||||
@@ -533,6 +527,20 @@ fcntl (int fd, int cmd, ...)
|
||||
#endif
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
fcntl (int fd, int cmd, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int rv;
|
||||
|
||||
if ((errno = -ldp_init ()))
|
||||
return -1;
|
||||
|
||||
va_start (ap, cmd);
|
||||
rv = fcntl_internal (fd, cmd, ap);
|
||||
va_end (ap);
|
||||
|
||||
return rv;
|
||||
@@ -544,8 +552,11 @@ fcntl64 (int fd, int cmd, ...)
|
||||
va_list ap;
|
||||
int rv;
|
||||
|
||||
if ((errno = -ldp_init ()))
|
||||
return -1;
|
||||
|
||||
va_start (ap, cmd);
|
||||
rv = fcntl (fd, cmd, ap);
|
||||
rv = fcntl_internal (fd, cmd, ap);
|
||||
va_end (ap);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -550,45 +550,16 @@ libc_eventfd (int count, int flags)
|
||||
int
|
||||
libc_vfcntl (int fd, int cmd, va_list ap)
|
||||
{
|
||||
long int args[4];
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
swrap_bind_symbol_libc (fcntl);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
args[i] = va_arg (ap, long int);
|
||||
}
|
||||
|
||||
rc = swrap.libc.symbols._libc_fcntl.f (fd,
|
||||
cmd,
|
||||
args[0], args[1], args[2], args[3]);
|
||||
|
||||
return rc;
|
||||
return swrap.libc.symbols._libc_fcntl.f (fd, cmd, va_arg (ap, long int));
|
||||
}
|
||||
|
||||
#ifdef HAVE_FCNTL64
|
||||
int
|
||||
libc_vfcntl64 (int fd, int cmd, va_list ap)
|
||||
{
|
||||
long int args[4];
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
swrap_bind_symbol_libc (fcntl64);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
args[i] = va_arg (ap, long int);
|
||||
}
|
||||
|
||||
rc = swrap.libc.symbols._libc_fcntl64.f (fd,
|
||||
cmd,
|
||||
args[0], args[1], args[2],
|
||||
args[3]);
|
||||
|
||||
return rc;
|
||||
return swrap.libc.symbols._libc_fcntl64.f (fd, cmd, va_arg (ap, long int));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -122,7 +122,9 @@ int libc_eventfd (int count, int flags);
|
||||
|
||||
int libc_vfcntl (int fd, int cmd, va_list ap);
|
||||
|
||||
#ifdef HAVE_FCNTL64
|
||||
int libc_vfcntl64 (int fd, int cmd, va_list ap);
|
||||
#endif
|
||||
|
||||
int libc_vioctl (int fd, int cmd, va_list ap);
|
||||
|
||||
|
||||
@@ -529,7 +529,7 @@ static inline u8
|
||||
vcl_session_is_cl (vcl_session_t * s)
|
||||
{
|
||||
if (s->session_type == VPPCOM_PROTO_UDP)
|
||||
return 1;
|
||||
return !(s->flags & VCL_SESSION_F_CONNECTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -548,6 +548,12 @@ vcl_session_is_closing (vcl_session_t * s)
|
||||
|| s->session_state == STATE_DISCONNECT);
|
||||
}
|
||||
|
||||
static inline u8
|
||||
vcl_session_is_closed (vcl_session_t * s)
|
||||
{
|
||||
return (!s || (s->session_state == STATE_CLOSED));
|
||||
}
|
||||
|
||||
static inline int
|
||||
vcl_session_closing_error (vcl_session_t * s)
|
||||
{
|
||||
|
||||
+23
-12
@@ -209,6 +209,8 @@ vcl_send_session_listen (vcl_worker_t * wrk, vcl_session_t * s)
|
||||
clib_memcpy_fast (&mp->ip, &s->transport.lcl_ip, sizeof (mp->ip));
|
||||
mp->port = s->transport.lcl_port;
|
||||
mp->proto = s->session_type;
|
||||
if (s->flags & VCL_SESSION_F_CONNECTED)
|
||||
mp->flags = TRANSPORT_CFG_F_CONNECTED;
|
||||
app_send_ctrl_evt_to_vpp (mq, app_evt);
|
||||
}
|
||||
|
||||
@@ -550,7 +552,8 @@ vcl_session_reset_handler (vcl_worker_t * wrk,
|
||||
return VCL_INVALID_SESSION_INDEX;
|
||||
}
|
||||
|
||||
session->session_state = STATE_DISCONNECT;
|
||||
if (session->session_state != STATE_CLOSED)
|
||||
session->session_state = STATE_DISCONNECT;
|
||||
VDBG (0, "reset session %u [0x%llx]", sid, reset_msg->handle);
|
||||
return sid;
|
||||
}
|
||||
@@ -1556,10 +1559,6 @@ vppcom_unformat_proto (uint8_t * proto, char *proto_str)
|
||||
*proto = VPPCOM_PROTO_UDP;
|
||||
else if (!strcmp (proto_str, "udp"))
|
||||
*proto = VPPCOM_PROTO_UDP;
|
||||
else if (!strcmp (proto_str, "UDPC"))
|
||||
*proto = VPPCOM_PROTO_UDPC;
|
||||
else if (!strcmp (proto_str, "udpc"))
|
||||
*proto = VPPCOM_PROTO_UDPC;
|
||||
else if (!strcmp (proto_str, "TLS"))
|
||||
*proto = VPPCOM_PROTO_TLS;
|
||||
else if (!strcmp (proto_str, "tls"))
|
||||
@@ -2780,7 +2779,8 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
|
||||
{
|
||||
case SESSION_IO_EVT_RX:
|
||||
sid = e->session_index;
|
||||
if (!(session = vcl_session_get (wrk, sid)))
|
||||
session = vcl_session_get (wrk, sid);
|
||||
if (vcl_session_is_closed (session))
|
||||
break;
|
||||
vcl_fifo_rx_evt_valid_or_break (session);
|
||||
session_events = session->vep.ev.events;
|
||||
@@ -2793,7 +2793,8 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
|
||||
break;
|
||||
case SESSION_IO_EVT_TX:
|
||||
sid = e->session_index;
|
||||
if (!(session = vcl_session_get (wrk, sid)))
|
||||
session = vcl_session_get (wrk, sid);
|
||||
if (vcl_session_is_closed (session))
|
||||
break;
|
||||
session_events = session->vep.ev.events;
|
||||
if (!(EPOLLOUT & session_events))
|
||||
@@ -2821,7 +2822,8 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
|
||||
connected_msg = (session_connected_msg_t *) e->data;
|
||||
sid = vcl_session_connected_handler (wrk, connected_msg);
|
||||
/* Generate EPOLLOUT because there's no connected event */
|
||||
if (!(session = vcl_session_get (wrk, sid)))
|
||||
session = vcl_session_get (wrk, sid);
|
||||
if (vcl_session_is_closed (session))
|
||||
break;
|
||||
session_events = session->vep.ev.events;
|
||||
if (!(EPOLLOUT & session_events))
|
||||
@@ -2835,7 +2837,7 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
|
||||
case SESSION_CTRL_EVT_DISCONNECTED:
|
||||
disconnected_msg = (session_disconnected_msg_t *) e->data;
|
||||
session = vcl_session_disconnected_handler (wrk, disconnected_msg);
|
||||
if (!session)
|
||||
if (vcl_session_is_closed (session))
|
||||
break;
|
||||
session_events = session->vep.ev.events;
|
||||
add_event = 1;
|
||||
@@ -2844,7 +2846,8 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
|
||||
break;
|
||||
case SESSION_CTRL_EVT_RESET:
|
||||
sid = vcl_session_reset_handler (wrk, (session_reset_msg_t *) e->data);
|
||||
if (!(session = vcl_session_get (wrk, sid)))
|
||||
session = vcl_session_get (wrk, sid);
|
||||
if (vcl_session_is_closed (session))
|
||||
break;
|
||||
session_events = session->vep.ev.events;
|
||||
add_event = 1;
|
||||
@@ -2923,7 +2926,7 @@ vcl_epoll_wait_handle_mq (vcl_worker_t * wrk, svm_msg_q_t * mq,
|
||||
}
|
||||
}
|
||||
ASSERT (maxevents > *num_ev);
|
||||
vcl_mq_dequeue_batch (wrk, mq, maxevents - *num_ev);
|
||||
vcl_mq_dequeue_batch (wrk, mq, ~0);
|
||||
svm_msg_q_unlock (mq);
|
||||
|
||||
handle_dequeued:
|
||||
@@ -2931,7 +2934,10 @@ handle_dequeued:
|
||||
{
|
||||
msg = vec_elt_at_index (wrk->mq_msg_vector, i);
|
||||
e = svm_msg_q_msg_data (mq, msg);
|
||||
vcl_epoll_wait_handle_mq_event (wrk, e, events, num_ev);
|
||||
if (*num_ev < maxevents)
|
||||
vcl_epoll_wait_handle_mq_event (wrk, e, events, num_ev);
|
||||
else
|
||||
vcl_handle_mq_event (wrk, e);
|
||||
svm_msg_q_free_msg (mq, msg);
|
||||
}
|
||||
vec_reset_length (wrk->mq_msg_vector);
|
||||
@@ -3593,6 +3599,11 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op,
|
||||
*(int *) buffer = SHUT_RDWR;
|
||||
*buflen = sizeof (int);
|
||||
break;
|
||||
|
||||
case VPPCOM_ATTR_SET_CONNECTED:
|
||||
session->flags |= VCL_SESSION_F_CONNECTED;
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = VPPCOM_EINVAL;
|
||||
break;
|
||||
|
||||
+2
-5
@@ -51,7 +51,6 @@ typedef enum
|
||||
VPPCOM_PROTO_UDP,
|
||||
VPPCOM_PROTO_NONE,
|
||||
VPPCOM_PROTO_TLS,
|
||||
VPPCOM_PROTO_UDPC,
|
||||
VPPCOM_PROTO_QUIC,
|
||||
} vppcom_proto_t;
|
||||
|
||||
@@ -71,9 +70,6 @@ vppcom_proto_str (vppcom_proto_t proto)
|
||||
case VPPCOM_PROTO_TLS:
|
||||
proto_str = "TLS";
|
||||
break;
|
||||
case VPPCOM_PROTO_UDPC:
|
||||
proto_str = "UDPC";
|
||||
break;
|
||||
case VPPCOM_PROTO_QUIC:
|
||||
proto_str = "QUIC";
|
||||
break;
|
||||
@@ -87,7 +83,7 @@ vppcom_proto_str (vppcom_proto_t proto)
|
||||
static inline int
|
||||
vcl_proto_is_dgram (uint8_t proto)
|
||||
{
|
||||
return proto == VPPCOM_PROTO_UDP || proto == VPPCOM_PROTO_UDPC;
|
||||
return proto == VPPCOM_PROTO_UDP;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
@@ -164,6 +160,7 @@ typedef enum
|
||||
VPPCOM_ATTR_SET_TCP_USER_MSS,
|
||||
VPPCOM_ATTR_SET_SHUT,
|
||||
VPPCOM_ATTR_GET_SHUT,
|
||||
VPPCOM_ATTR_SET_CONNECTED,
|
||||
} vppcom_attr_op_t;
|
||||
|
||||
typedef struct _vcl_poll
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ typedef struct vlib_main_t
|
||||
u64 cpu_time_main_loop_start;
|
||||
|
||||
/* Incremented once for each main loop. */
|
||||
u32 main_loop_count;
|
||||
volatile u32 main_loop_count;
|
||||
|
||||
/* Count of vectors processed this main loop. */
|
||||
u32 main_loop_vectors_processed;
|
||||
|
||||
@@ -1434,6 +1434,18 @@ vlib_worker_thread_initial_barrier_sync_and_release (vlib_main_t * vm)
|
||||
*vlib_worker_threads->wait_at_barrier = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the wroker thread barrier is held
|
||||
*/
|
||||
u8
|
||||
vlib_worker_thread_barrier_held (void)
|
||||
{
|
||||
if (vec_len (vlib_mains) < 2)
|
||||
return (1);
|
||||
|
||||
return (*vlib_worker_threads->wait_at_barrier == 1);
|
||||
}
|
||||
|
||||
void
|
||||
vlib_worker_thread_barrier_sync_int (vlib_main_t * vm, const char *func_name)
|
||||
{
|
||||
@@ -1630,6 +1642,41 @@ vlib_worker_thread_barrier_release (vlib_main_t * vm)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until each of the workers has been once around the track
|
||||
*/
|
||||
void
|
||||
vlib_worker_wait_one_loop (void)
|
||||
{
|
||||
ASSERT (vlib_get_thread_index () == 0);
|
||||
|
||||
if (vec_len (vlib_mains) < 2)
|
||||
return;
|
||||
|
||||
if (vlib_worker_thread_barrier_held ())
|
||||
return;
|
||||
|
||||
u32 *counts = 0;
|
||||
u32 ii;
|
||||
|
||||
vec_validate (counts, vec_len (vlib_mains) - 1);
|
||||
|
||||
/* record the current loop counts */
|
||||
vec_foreach_index (ii, vlib_mains)
|
||||
counts[ii] = vlib_mains[ii]->main_loop_count;
|
||||
|
||||
/* spin until each changes, apart from the main thread, or we'd be
|
||||
* a while */
|
||||
for (ii = 1; ii < vec_len (counts); ii++)
|
||||
{
|
||||
while (counts[ii] == vlib_mains[ii]->main_loop_count)
|
||||
CLIB_PAUSE ();
|
||||
}
|
||||
|
||||
vec_free (counts);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the frame queue to see if any frames are available.
|
||||
* If so, pull the packets off the frames and put them to
|
||||
|
||||
@@ -206,8 +206,13 @@ u32 vlib_frame_queue_main_init (u32 node_index, u32 frame_queue_nelts);
|
||||
void vlib_worker_thread_barrier_sync_int (vlib_main_t * vm,
|
||||
const char *func_name);
|
||||
void vlib_worker_thread_barrier_release (vlib_main_t * vm);
|
||||
u8 vlib_worker_thread_barrier_held (void);
|
||||
void vlib_worker_thread_initial_barrier_sync_and_release (vlib_main_t * vm);
|
||||
void vlib_worker_thread_node_refork (void);
|
||||
/**
|
||||
* Wait until each of the workers has been once around the track
|
||||
*/
|
||||
void vlib_worker_wait_one_loop (void);
|
||||
|
||||
static_always_inline uword
|
||||
vlib_get_thread_index (void)
|
||||
|
||||
+48
-81
@@ -18,25 +18,23 @@
|
||||
#include <vnet/ethernet/arp_packet.h>
|
||||
#include <vnet/fib/fib_walk.h>
|
||||
|
||||
#include <vppinfra/bihash_24_8.h>
|
||||
|
||||
/*
|
||||
* Vector Hash tables of neighbour (traditional) adjacencies
|
||||
* Key: interface(for the vector index), address (and its proto),
|
||||
* link-type/ether-type.
|
||||
*/
|
||||
static BVT(clib_bihash) **adj_nbr_tables[FIB_PROTOCOL_MAX];
|
||||
|
||||
// FIXME SIZE APPROPRIATELY. ASK DAVEB.
|
||||
#define ADJ_NBR_DEFAULT_HASH_NUM_BUCKETS (64 * 64)
|
||||
#define ADJ_NBR_DEFAULT_HASH_MEMORY_SIZE (32<<20)
|
||||
static uword **adj_nbr_tables[FIB_PROTOCOL_IP_MAX];
|
||||
|
||||
typedef struct adj_nbr_key_t_
|
||||
{
|
||||
ip46_address_t ank_ip;
|
||||
u64 ank_linkt;
|
||||
} adj_nbr_key_t;
|
||||
|
||||
#define ADJ_NBR_SET_KEY(_key, _lt, _nh) \
|
||||
{ \
|
||||
_key.key[0] = (_nh)->as_u64[0]; \
|
||||
_key.key[1] = (_nh)->as_u64[1]; \
|
||||
_key.key[2] = (_lt); \
|
||||
ip46_address_copy(&(_key).ank_ip, (_nh)); \
|
||||
_key.ank_linkt = (_lt); \
|
||||
}
|
||||
|
||||
#define ADJ_NBR_ITF_OK(_proto, _itf) \
|
||||
@@ -50,7 +48,7 @@ adj_nbr_insert (fib_protocol_t nh_proto,
|
||||
u32 sw_if_index,
|
||||
adj_index_t adj_index)
|
||||
{
|
||||
BVT(clib_bihash_kv) kv;
|
||||
adj_nbr_key_t kv;
|
||||
|
||||
if (sw_if_index >= vec_len(adj_nbr_tables[nh_proto]))
|
||||
{
|
||||
@@ -59,22 +57,13 @@ adj_nbr_insert (fib_protocol_t nh_proto,
|
||||
if (NULL == adj_nbr_tables[nh_proto][sw_if_index])
|
||||
{
|
||||
adj_nbr_tables[nh_proto][sw_if_index] =
|
||||
clib_mem_alloc_aligned(sizeof(BVT(clib_bihash)),
|
||||
CLIB_CACHE_LINE_BYTES);
|
||||
clib_memset(adj_nbr_tables[nh_proto][sw_if_index],
|
||||
0,
|
||||
sizeof(BVT(clib_bihash)));
|
||||
|
||||
BV(clib_bihash_init) (adj_nbr_tables[nh_proto][sw_if_index],
|
||||
"Adjacency Neighbour table",
|
||||
ADJ_NBR_DEFAULT_HASH_NUM_BUCKETS,
|
||||
ADJ_NBR_DEFAULT_HASH_MEMORY_SIZE);
|
||||
hash_create_mem(0, sizeof(adj_nbr_key_t), sizeof(adj_index_t));
|
||||
}
|
||||
|
||||
ADJ_NBR_SET_KEY(kv, link_type, nh_addr);
|
||||
kv.value = adj_index;
|
||||
|
||||
BV(clib_bihash_add_del) (adj_nbr_tables[nh_proto][sw_if_index], &kv, 1);
|
||||
hash_set_mem_alloc (&adj_nbr_tables[nh_proto][sw_if_index],
|
||||
&kv, adj_index);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -84,15 +73,19 @@ adj_nbr_remove (adj_index_t ai,
|
||||
const ip46_address_t *nh_addr,
|
||||
u32 sw_if_index)
|
||||
{
|
||||
BVT(clib_bihash_kv) kv;
|
||||
adj_nbr_key_t kv;
|
||||
|
||||
if (!ADJ_NBR_ITF_OK(nh_proto, sw_if_index))
|
||||
return;
|
||||
|
||||
ADJ_NBR_SET_KEY(kv, link_type, nh_addr);
|
||||
kv.value = ai;
|
||||
|
||||
BV(clib_bihash_add_del) (adj_nbr_tables[nh_proto][sw_if_index], &kv, 0);
|
||||
hash_unset_mem_free(&adj_nbr_tables[nh_proto][sw_if_index], &kv);
|
||||
|
||||
if (0 == hash_elts(adj_nbr_tables[nh_proto][sw_if_index]))
|
||||
{
|
||||
hash_free(adj_nbr_tables[nh_proto][sw_if_index]);
|
||||
}
|
||||
}
|
||||
|
||||
adj_index_t
|
||||
@@ -101,22 +94,21 @@ adj_nbr_find (fib_protocol_t nh_proto,
|
||||
const ip46_address_t *nh_addr,
|
||||
u32 sw_if_index)
|
||||
{
|
||||
BVT(clib_bihash_kv) kv;
|
||||
adj_nbr_key_t kv;
|
||||
uword *p;
|
||||
|
||||
ADJ_NBR_SET_KEY(kv, link_type, nh_addr);
|
||||
|
||||
if (!ADJ_NBR_ITF_OK(nh_proto, sw_if_index))
|
||||
return (ADJ_INDEX_INVALID);
|
||||
|
||||
if (BV(clib_bihash_search)(adj_nbr_tables[nh_proto][sw_if_index],
|
||||
&kv, &kv) < 0)
|
||||
p = hash_get_mem(adj_nbr_tables[nh_proto][sw_if_index], &kv);
|
||||
|
||||
if (p)
|
||||
{
|
||||
return (ADJ_INDEX_INVALID);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (kv.value);
|
||||
return (p[0]);
|
||||
}
|
||||
return (ADJ_INDEX_INVALID);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
@@ -533,27 +525,12 @@ adj_nbr_update_rewrite_internal (ip_adjacency_t *adj,
|
||||
adj_unlock(walk_ai);
|
||||
}
|
||||
|
||||
typedef struct adj_db_count_ctx_t_ {
|
||||
u64 count;
|
||||
} adj_db_count_ctx_t;
|
||||
|
||||
static int
|
||||
adj_db_count (BVT(clib_bihash_kv) * kvp,
|
||||
void *arg)
|
||||
{
|
||||
adj_db_count_ctx_t * ctx = arg;
|
||||
ctx->count++;
|
||||
return (BIHASH_WALK_CONTINUE);
|
||||
}
|
||||
|
||||
u32
|
||||
adj_nbr_db_size (void)
|
||||
{
|
||||
adj_db_count_ctx_t ctx = {
|
||||
.count = 0,
|
||||
};
|
||||
fib_protocol_t proto;
|
||||
u32 sw_if_index = 0;
|
||||
u64 count = 0;
|
||||
|
||||
for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
|
||||
{
|
||||
@@ -561,54 +538,44 @@ adj_nbr_db_size (void)
|
||||
{
|
||||
if (NULL != adj_nbr_tables[proto][sw_if_index])
|
||||
{
|
||||
BV(clib_bihash_foreach_key_value_pair) (
|
||||
adj_nbr_tables[proto][sw_if_index],
|
||||
adj_db_count,
|
||||
&ctx);
|
||||
count += hash_elts(adj_nbr_tables[proto][sw_if_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (ctx.count);
|
||||
return (count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Context for a walk of the adjacency neighbour DB
|
||||
* @brief Walk all adjacencies on a link for a given next-hop protocol
|
||||
*/
|
||||
typedef struct adj_walk_ctx_t_
|
||||
{
|
||||
adj_walk_cb_t awc_cb;
|
||||
void *awc_ctx;
|
||||
} adj_walk_ctx_t;
|
||||
|
||||
static int
|
||||
adj_nbr_walk_cb (BVT(clib_bihash_kv) * kvp,
|
||||
void *arg)
|
||||
{
|
||||
adj_walk_ctx_t *ctx = arg;
|
||||
|
||||
if (ADJ_WALK_RC_STOP == ctx->awc_cb(kvp->value, ctx->awc_ctx))
|
||||
return (BIHASH_WALK_STOP);
|
||||
return (BIHASH_WALK_CONTINUE);
|
||||
}
|
||||
|
||||
void
|
||||
adj_nbr_walk (u32 sw_if_index,
|
||||
fib_protocol_t adj_nh_proto,
|
||||
adj_walk_cb_t cb,
|
||||
void *ctx)
|
||||
{
|
||||
adj_index_t ai, *ais, *aip;
|
||||
adj_nbr_key_t *key;
|
||||
|
||||
if (!ADJ_NBR_ITF_OK(adj_nh_proto, sw_if_index))
|
||||
return;
|
||||
|
||||
adj_walk_ctx_t awc = {
|
||||
.awc_ctx = ctx,
|
||||
.awc_cb = cb,
|
||||
};
|
||||
ais = NULL;
|
||||
|
||||
BV(clib_bihash_foreach_key_value_pair) (
|
||||
adj_nbr_tables[adj_nh_proto][sw_if_index],
|
||||
adj_nbr_walk_cb,
|
||||
&awc);
|
||||
/* elements may be removed from the table during the walk, so
|
||||
* collect the set first then process them */
|
||||
hash_foreach_mem (key, ai, adj_nbr_tables[adj_nh_proto][sw_if_index],
|
||||
({
|
||||
vec_add1(ais, ai);
|
||||
}));
|
||||
|
||||
vec_foreach(aip, ais)
|
||||
{
|
||||
/* An adj may be deleted during the walk so check first */
|
||||
if (!pool_is_free_index(adj_pool, *aip))
|
||||
cb(*aip, ctx);
|
||||
}
|
||||
vec_free(ais);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user