aboutsummaryrefslogtreecommitdiffstats
path: root/vnet
diff options
context:
space:
mode:
authorKlement Sekera <ksekera@cisco.com>2016-09-20 15:45:58 +0200
committerDamjan Marion <dmarion.lists@gmail.com>2016-09-20 17:30:01 +0000
commit48a9a54e7c8e295c0cba3491a05c8aa0a5a1f81a (patch)
tree7d3154f488c8c4668da0db585ea0ddf31adfca23 /vnet
parentf298ecfe1d408164dd2be5205824da9a6b218279 (diff)
VPP-419 add thread-safety to LLDP feature
Change-Id: I3b1153a64674c2caef71c968739ecca6512e9929 Signed-off-by: Klement Sekera <ksekera@cisco.com>
Diffstat (limited to 'vnet')
-rw-r--r--vnet/vnet/lldp/lldp_input.c108
-rw-r--r--vnet/vnet/lldp/lldp_node.c12
2 files changed, 90 insertions, 30 deletions
diff --git a/vnet/vnet/lldp/lldp_input.c b/vnet/vnet/lldp/lldp_input.c
index f86fe62cecc..762743d0d8d 100644
--- a/vnet/vnet/lldp/lldp_input.c
+++ b/vnet/vnet/lldp/lldp_input.c
@@ -18,6 +18,69 @@
*/
#include <vnet/lldp/lldp_node.h>
#include <vnet/lldp/lldp_protocol.h>
+#include <vlibmemory/api.h>
+
+typedef struct
+{
+ u32 hw_if_index;
+ u8 chassis_id_len;
+ u8 chassis_id_subtype;
+ u8 portid_len;
+ u8 portid_subtype;
+ u16 ttl;
+ u8 data[0]; /* this contains both chassis id (chassis_id_len bytes) and port
+ id (portid_len bytes) */
+} lldp_intf_update_t;
+
+static void
+lldp_rpc_update_peer_cb (const lldp_intf_update_t * a)
+{
+ ASSERT (os_get_cpu_number () == 0);
+
+ lldp_intf_t *n = lldp_get_intf (&lldp_main, a->hw_if_index);
+ if (!n)
+ {
+ /* LLDP turned off for this interface, ignore the update */
+ return;
+ }
+ const u8 *chassis_id = a->data;
+ const u8 *portid = a->data + a->chassis_id_len;
+
+ if (n->chassis_id)
+ {
+ _vec_len (n->chassis_id) = 0;
+ }
+ vec_add (n->chassis_id, chassis_id, a->chassis_id_len);
+ n->chassis_id_subtype = a->chassis_id_subtype;
+ if (n->port_id)
+ {
+ _vec_len (n->port_id) = 0;
+ }
+ vec_add (n->port_id, portid, a->portid_len);
+ n->port_id_subtype = a->portid_subtype;
+ n->ttl = a->ttl;
+ n->last_heard = vlib_time_now (lldp_main.vlib_main);
+}
+
+static void
+lldp_rpc_update_peer (u32 hw_if_index, const u8 * chid, u8 chid_len,
+ u8 chid_subtype, const u8 * portid,
+ u8 portid_len, u8 portid_subtype, u16 ttl)
+{
+ const size_t data_size =
+ sizeof (lldp_intf_update_t) + chid_len + portid_len;
+ u8 data[data_size];
+ lldp_intf_update_t *u = (lldp_intf_update_t *) data;
+ u->hw_if_index = hw_if_index;
+ u->chassis_id_len = chid_len;
+ u->chassis_id_subtype = chid_subtype;
+ u->ttl = ttl;
+ u->portid_len = portid_len;
+ u->portid_subtype = portid_subtype;
+ clib_memcpy (u->data, chid, chid_len);
+ clib_memcpy (u->data + chid_len, portid, portid_len);
+ vl_api_rpc_call_main_thread (lldp_rpc_update_peer_cb, data, data_size);
+}
lldp_tlv_code_t
lldp_tlv_get_code (const lldp_tlv_t * tlv)
@@ -54,14 +117,13 @@ lldp_tlv_set_length (lldp_tlv_t * tlv, u16 length)
lldp_main_t lldp_main;
static int
-lldp_packet_scan (lldp_main_t * lm, lldp_intf_t * n, const lldp_tlv_t * pkt)
+lldp_packet_scan (u32 hw_if_index, const lldp_tlv_t * pkt)
{
const lldp_tlv_t *tlv = pkt;
-/* first check if the header fits in before extracting data from it */
#define TLV_VIOLATES_PKT_BOUNDARY(pkt, tlv) \
- (((((u8 *)tlv) + sizeof(lldp_tlv_t)) > ((u8 *)pkt + vec_len(pkt))) || \
- ((((u8 *)tlv) + lldp_tlv_get_length(tlv)) > ((u8 *)pkt + vec_len(pkt))))
+ (((((u8 *)tlv) + sizeof (lldp_tlv_t)) > ((u8 *)pkt + vec_len (pkt))) || \
+ ((((u8 *)tlv) + lldp_tlv_get_length (tlv)) > ((u8 *)pkt + vec_len (pkt))))
/* first tlv is always chassis id, followed by port id and ttl tlvs */
if (TLV_VIOLATES_PKT_BOUNDARY (pkt, tlv) ||
@@ -122,10 +184,10 @@ lldp_packet_scan (lldp_main_t * lm, lldp_intf_t * n, const lldp_tlv_t * pkt)
{
switch (lldp_tlv_get_code (tlv))
{
-#define F(num, type, str) \
- case LLDP_TLV_NAME(type): \
- /* ignore optional TLV */ \
- break;
+#define F(num, type, str) \
+ case LLDP_TLV_NAME (type): \
+ /* ignore optional TLV */ \
+ break;
foreach_lldp_optional_tlv_type (F);
#undef F
default:
@@ -141,20 +203,8 @@ lldp_packet_scan (lldp_main_t * lm, lldp_intf_t * n, const lldp_tlv_t * pkt)
{
return LLDP_ERROR_BAD_TLV;
}
- /* LLDP PDU validated, now store data */
- if (n->chassis_id)
- {
- _vec_len (n->chassis_id) = 0;
- }
- vec_add (n->chassis_id, chid, chid_len);
- n->chassis_id_subtype = chid_subtype;
- if (n->port_id)
- {
- _vec_len (n->port_id) = 0;
- }
- vec_add (n->port_id, portid, portid_len);
- n->port_id_subtype = portid_subtype;
- n->ttl = ttl;
+ lldp_rpc_update_peer (hw_if_index, chid, chid_len, chid_subtype, portid,
+ portid_len, portid_subtype, ttl);
return LLDP_ERROR_NONE;
}
@@ -202,7 +252,11 @@ lldp_input (vlib_main_t * vm, vlib_buffer_t * b0, u32 bi0)
lldp_error_t e;
/* find our interface */
- lldp_intf_t *n = lldp_get_intf (lm, vnet_buffer (b0)->sw_if_index[VLIB_RX]);
+ vnet_sw_interface_t *sw_interface = vnet_get_sw_interface (lm->vnet_main,
+ vnet_buffer
+ (b0)->sw_if_index
+ [VLIB_RX]);
+ lldp_intf_t *n = lldp_get_intf (lm, sw_interface->hw_if_index);
if (!n)
{
@@ -211,12 +265,8 @@ lldp_input (vlib_main_t * vm, vlib_buffer_t * b0, u32 bi0)
}
/* Actually scan the packet */
- e = lldp_packet_scan (lm, n, vlib_buffer_get_current (b0));
-
- if (LLDP_ERROR_NONE == e)
- {
- n->last_heard = vlib_time_now (vm);
- }
+ e = lldp_packet_scan (sw_interface->hw_if_index,
+ vlib_buffer_get_current (b0));
return e;
}
diff --git a/vnet/vnet/lldp/lldp_node.c b/vnet/vnet/lldp/lldp_node.c
index 2eb27e0634e..acaa5e10e36 100644
--- a/vnet/vnet/lldp/lldp_node.c
+++ b/vnet/vnet/lldp/lldp_node.c
@@ -79,7 +79,7 @@ lldp_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
error0 = lldp_input (vm, b0, bi0);
b0->error = node->errors[error0];
- /* If this pkt is traced, snapshoot the data */
+ /* If this pkt is traced, snapshot the data */
if (b0->flags & VLIB_BUFFER_IS_TRACED)
{
int len;
@@ -241,6 +241,16 @@ VLIB_REGISTER_NODE(lldp_process_node, static) = {
void
lldp_schedule_intf (lldp_main_t * lm, lldp_intf_t * n)
{
+ const int idx = n - lm->intfs;
+ u32 v;
+ vec_foreach_index (v, lm->intfs_timeouts)
+ {
+ if (lm->intfs_timeouts[v] == idx)
+ {
+ /* already scheduled */
+ return;
+ }
+ }
n->last_sent = 0; /* ensure that a packet is sent out immediately */
/* put the interface at the current position in the timeouts - it
* will timeout immediately */