aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMohsin Kazmi <sykazmi@cisco.com>2017-11-20 10:23:47 +0100
committerNeale Ranns <nranns@cisco.com>2017-11-22 11:20:45 +0000
commit5a4f96a178b693ace8e736c30c949ced5928d824 (patch)
tree55109d1354c6fc3814282a9b9ba6e52fc19a43df /src
parent4878cbe276ec1131d0cf30ac5df18aa9ba699bc4 (diff)
VOM: stats: Associate stat obj to interface
Change-Id: Id8b159dd72b92798538a32fe570fb0038d742ef2 Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
Diffstat (limited to 'src')
-rw-r--r--src/vpp-api/vom/interface.cpp18
-rw-r--r--src/vpp-api/vom/interface.hpp15
-rw-r--r--src/vpp-api/vom/interface_cmds.cpp43
-rw-r--r--src/vpp-api/vom/interface_cmds.hpp9
-rw-r--r--src/vpp-api/vom/rpc_cmd.hpp11
5 files changed, 71 insertions, 25 deletions
diff --git a/src/vpp-api/vom/interface.cpp b/src/vpp-api/vom/interface.cpp
index 8f1023d2273..39ca074920f 100644
--- a/src/vpp-api/vom/interface.cpp
+++ b/src/vpp-api/vom/interface.cpp
@@ -163,11 +163,15 @@ interface::sweep()
new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV6, m_hdl));
}
+ if (m_stats)
+ HW::dequeue(m_stats);
+
// If the interface is up, bring it down
if (m_state && interface::admin_state_t::UP == m_state.data()) {
m_state.data() = interface::admin_state_t::DOWN;
HW::enqueue(new interface_cmds::state_change_cmd(m_state, m_hdl));
}
+
if (m_hdl) {
std::queue<cmd*> cmds;
HW::enqueue(mk_delete_cmd(cmds));
@@ -356,6 +360,20 @@ interface::set(const oper_state_t& state)
m_oper = state;
}
+void
+interface::enable_stats_i(interface::stat_listener& el)
+{
+ m_stats.reset(new interface_cmds::stats_cmd(el, handle_i()));
+ HW::enqueue(m_stats);
+ HW::write();
+}
+
+void
+interface::enable_stats(interface::stat_listener& el)
+{
+ singular()->enable_stats_i(el);
+}
+
std::shared_ptr<interface>
interface::singular_i() const
{
diff --git a/src/vpp-api/vom/interface.hpp b/src/vpp-api/vom/interface.hpp
index 181e76dad69..76ecf8af0a0 100644
--- a/src/vpp-api/vom/interface.hpp
+++ b/src/vpp-api/vom/interface.hpp
@@ -421,6 +421,11 @@ public:
*/
static void dump(std::ostream& os);
+ /**
+ * Enable stats for this interface
+ */
+ void enable_stats(stat_listener& el);
+
protected:
/**
* Construct an interface object with a handle and a HW address
@@ -513,6 +518,11 @@ private:
static event_handler m_evh;
/**
+ * enable the interface stats in the singular instance
+ */
+ void enable_stats_i(stat_listener& el);
+
+ /**
* Commit the acculmulated changes into VPP. i.e. to a 'HW" write.
*/
void update(const interface& obj);
@@ -550,6 +560,11 @@ private:
std::shared_ptr<route_domain> m_rd;
/**
+ * shared pointer to the stats object for this interface.
+ */
+ std::shared_ptr<interface_cmds::stats_cmd> m_stats;
+
+ /**
* The state of the interface
*/
HW::item<admin_state_t> m_state;
diff --git a/src/vpp-api/vom/interface_cmds.cpp b/src/vpp-api/vom/interface_cmds.cpp
index 4f6286f7bef..750ad1f8881 100644
--- a/src/vpp-api/vom/interface_cmds.cpp
+++ b/src/vpp-api/vom/interface_cmds.cpp
@@ -401,11 +401,10 @@ events_cmd::to_string() const
/**
* Interface statistics
*/
-stats_cmd::stats_cmd(interface::stat_listener& el,
- const std::vector<handle_t>& interfaces)
+stats_cmd::stats_cmd(interface::stat_listener& el, const handle_t& handle)
: event_cmd(el.status())
, m_listener(el)
- , m_swifindex(interfaces)
+ , m_swifindex(handle)
{
}
@@ -419,29 +418,21 @@ rc_t
stats_cmd::issue(connection& con)
{
/*
- * First set the clal back to handle the interface stats
- */
+ * First set the call back to handle the interface stats
+ */
m_reg.reset(new reg_t(con.ctx(), std::ref(*(static_cast<event_cmd*>(this)))));
- // m_reg->execute();
/*
- * then send the request to enable them
- */
- msg_t req(con.ctx(), m_swifindex.size(),
- std::ref(*(static_cast<rpc_cmd*>(this))));
+ * then send the request to enable them
+ */
+ msg_t req(con.ctx(), 1, std::ref(*(static_cast<rpc_cmd*>(this))));
auto& payload = req.get_request().get_payload();
payload.enable_disable = 1;
payload.pid = getpid();
- payload.num = m_swifindex.size();
-
- auto it = m_swifindex.cbegin();
- uint32_t ii = 0;
- while (it != m_swifindex.cend()) {
- payload.sw_ifs[ii] = it->value();
- ++it;
- ++ii;
- }
+ payload.num = 1;
+
+ payload.sw_ifs[0] = m_swifindex.value();
VAPI_CALL(req.execute());
@@ -453,6 +444,20 @@ stats_cmd::issue(connection& con)
void
stats_cmd::retire(connection& con)
{
+ /*
+ * disable interface stats.
+ */
+ msg_t req(con.ctx(), 1, std::ref(*(static_cast<rpc_cmd*>(this))));
+
+ auto& payload = req.get_request().get_payload();
+ payload.enable_disable = 0;
+ payload.pid = getpid();
+ payload.num = 1;
+ payload.sw_ifs[0] = m_swifindex.value();
+
+ VAPI_CALL(req.execute());
+
+ wait();
}
void
diff --git a/src/vpp-api/vom/interface_cmds.hpp b/src/vpp-api/vom/interface_cmds.hpp
index 4178be38e04..c86df92a4aa 100644
--- a/src/vpp-api/vom/interface_cmds.hpp
+++ b/src/vpp-api/vom/interface_cmds.hpp
@@ -364,7 +364,7 @@ private:
/**
* The listeners to notify when data/events arrive
*/
- interface::interface::event_listener& m_listener;
+ interface::event_listener& m_listener;
};
/**
@@ -377,8 +377,7 @@ public:
/**
* Constructor taking the listner to notify
*/
- stats_cmd(interface::stat_listener& el,
- const std::vector<handle_t>& interfaces);
+ stats_cmd(interface::stat_listener& el, const handle_t& handle);
/**
* Issue the command to VPP/HW
@@ -409,9 +408,9 @@ private:
/**
* The listeners to notify when data/stats arrive
*/
- interface::interface::stat_listener& m_listener;
+ interface::stat_listener& m_listener;
- std::vector<handle_t> m_swifindex;
+ handle_t m_swifindex;
};
/**
diff --git a/src/vpp-api/vom/rpc_cmd.hpp b/src/vpp-api/vom/rpc_cmd.hpp
index 60dbd47c8b3..ae3c6753d24 100644
--- a/src/vpp-api/vom/rpc_cmd.hpp
+++ b/src/vpp-api/vom/rpc_cmd.hpp
@@ -71,7 +71,16 @@ public:
/**
* Fulfill the commands promise. Called from the RX thread
*/
- void fulfill(const DATA& d) { m_promise.set_value(d); }
+ void fulfill(const DATA& d)
+ {
+ m_promise.set_value(d);
+
+ /*
+ * we reset the promise after setting the value to reuse it
+ * when we run the retire command from the same cmd object
+ */
+ m_promise = std::promise<DATA>();
+ }
/**
* Wait on the commands promise. i.e. block on the completion
word.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/*
 * Copyright (c) 2018 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __GBP_CONTRACT_H__
#define __GBP_CONTRACT_H__

#include <plugins/gbp/gbp.h>
#include <plugins/gbp/gbp_types.h>

#define foreach_gbp_contract_error                         \
  _(ALLOW_NO_SCLASS,    "allow-no-sclass")                 \
  _(ALLOW_INTRA,        "allow-intra-sclass")              \
  _(ALLOW_A_BIT,        "allow-a-bit-set")                 \
  _(ALLOW_SCLASS_1,     "allow-sclass-1")                  \
  _(ALLOW_CONTRACT,     "allow-contract")                  \
  _(DROP_CONTRACT,      "drop-contract")                   \
  _(DROP_ETHER_TYPE,    "drop-ether-type")                 \
  _(DROP_NO_CONTRACT,   "drop-no-contract")                \
  _(DROP_NO_DCLASS,     "drop-no-dclass")                  \
  _(DROP_NO_RULE,       "drop-no-rule")

typedef enum
{
#define _(sym,str) GBP_CONTRACT_ERROR_##sym,
  foreach_gbp_contract_error
#undef _
    GBP_CONTRACT_N_ERROR,
#define GBP_CONTRACT_N_ERROR GBP_CONTRACT_N_ERROR
} gbp_contract_error_t;

extern char *gbp_contract_error_strings[GBP_CONTRACT_N_ERROR];

/**
 * The key for an Contract
 */
typedef struct gbp_contract_key_t_
{
  union
  {
    struct
    {
      gbp_scope_t gck_scope;
      /**
       * source and destination EPGs for which the ACL applies
       */
      sclass_t gck_src;
      sclass_t gck_dst;
    };
    u64 as_u64;
  };
} gbp_contract_key_t;

typedef struct gbp_next_hop_t_
{
  fib_node_t gnh_node;
  ip46_address_t gnh_ip;
  mac_address_t gnh_mac;
  index_t gnh_gu;
  index_t gnh_bd;
  index_t gnh_rd;
  u32 gnh_ge;
  u32 gnh_sibling;
  index_t gnh_ai[FIB_PROTOCOL_IP_MAX];
} gbp_next_hop_t;

#define foreach_gbp_hash_mode	\
  _(SRC_IP, "src-ip")		\
  _(DST_IP, "dst-ip")		\
  _(SYMMETRIC, "symmetric")

typedef enum gbp_hash_mode_t_
{
#define _(v,s) GBP_HASH_MODE_##v,
  foreach_gbp_hash_mode
#undef _
} gbp_hash_mode_t;

#define foreach_gbp_rule_action   \
  _(PERMIT,   "permit")           \
  _(DENY,     "deny")             \
  _(REDIRECT, "redirect")

typedef enum gbp_rule_action_t_
{
#define _(v,s) GBP_RULE_##v,
  foreach_gbp_rule_action
#undef _
} gbp_rule_action_t;

#define foreach_gbp_policy_node   \
  _(L2, "L2")                     \
  _(IP4, "ip4")                   \
  _(IP6, "ip6")

typedef enum gbp_policy_node_t_
{
#define _(v,s) GBP_POLICY_NODE_##v,
  foreach_gbp_policy_node
#undef _
} gbp_policy_node_t;
#define GBP_POLICY_N_NODES (GBP_POLICY_NODE_IP6+1)

#define FOR_EACH_GBP_POLICY_NODE(pnode)         \
  for (pnode = GBP_POLICY_NODE_L2; pnode < GBP_POLICY_N_NODES; pnode++)

typedef struct gbp_rule_t_
{
  gbp_rule_action_t gu_action;
  gbp_hash_mode_t gu_hash_mode;
  index_t *gu_nhs;

  /**
   * DPO of the load-balance object used to redirect
   */
  dpo_id_t gu_dpo[GBP_POLICY_N_NODES][FIB_PROTOCOL_IP_MAX];
} gbp_rule_t;

/**
 * A Group Based Policy Contract.
 *  Determines the ACL that applies to traffic pass between two endpoint groups
 */
typedef struct gbp_contract_t_
{
  /**
   * source and destination EPGs
   */
  gbp_contract_key_t gc_key;

  u32 gc_acl_index;
  u32 gc_lc_index;

  /**
   * The ACL to apply for packets from the source to the destination EPG
   */
  index_t *gc_rules;

  /**
   * An ethertype whitelist
   */
  u16 *gc_allowed_ethertypes;
} gbp_contract_t;

/**
 * EPG src,dst pair to ACL mapping table, aka contract DB
 */
typedef struct gbp_contract_db_t_
{
  /**
   * We can form a u64 key from the pair, so use a simple hash table
   */
  uword *gc_hash;
} gbp_contract_db_t;

extern int gbp_contract_update (gbp_scope_t scope,
				sclass_t sclass,
				sclass_t dclass,
				u32 acl_index,
				index_t * rules,
				u16 * allowed_ethertypes, u32 * stats_index);
extern int gbp_contract_delete (gbp_scope_t scope, sclass_t sclass,
				sclass_t dclass);

extern index_t gbp_rule_alloc (gbp_rule_action_t action,
			       gbp_hash_mode_t hash_mode, index_t * nhs);
extern void gbp_rule_free (index_t gui);
extern index_t gbp_next_hop_alloc (const ip46_address_t * ip,
				   index_t grd,
				   const mac_address_t * mac, index_t gbd);

typedef int (*gbp_contract_cb_t) (gbp_contract_t * gbpe, void *ctx);
extern void gbp_contract_walk (gbp_contract_cb_t bgpe, void *ctx);

extern u8 *format_gbp_rule_action (u8 * s, va_list * args);
extern u8 *format_gbp_contract (u8 * s, va_list * args);

/**
 * DP functions and databases
 */
extern gbp_contract_db_t gbp_contract_db;

always_inline index_t
gbp_contract_find (gbp_contract_key_t * key)
{
  uword *p;

  p = hash_get (gbp_contract_db.gc_hash, key->as_u64);

  if (NULL != p)
    return (p[0]);

  return (INDEX_INVALID);
}

extern gbp_contract_t *gbp_contract_pool;

always_inline gbp_contract_t *
gbp_contract_get (index_t gci)
{
  return (pool_elt_at_index (gbp_contract_pool, gci));
}

extern gbp_rule_t *gbp_rule_pool;

always_inline gbp_rule_t *
gbp_rule_get (index_t gui)
{
  return (pool_elt_at_index (gbp_rule_pool, gui));
}

extern vlib_combined_counter_main_t gbp_contract_permit_counters;
extern vlib_combined_counter_main_t gbp_contract_drop_counters;

typedef enum
{
  GBP_CONTRACT_APPLY_L2,
  GBP_CONTRACT_APPLY_IP4,
  GBP_CONTRACT_APPLY_IP6,
} gbp_contract_apply_type_t;

static_always_inline gbp_rule_action_t
gbp_contract_apply (vlib_main_t * vm, gbp_main_t * gm,
		    gbp_contract_key_t * key, vlib_buffer_t * b,
		    gbp_rule_t ** rule, u32 * intra, u32 * sclass1,
		    u32 * acl_match, u32 * rule_match,
		    gbp_contract_error_t * err,
		    gbp_contract_apply_type_t type)
{
  fa_5tuple_opaque_t fa_5tuple;
  const gbp_contract_t *contract;
  index_t contract_index;
  u32 acl_pos, trace_bitmap;
  u16 etype;
  u8 ip6, action;

  *rule = 0;
  trace_bitmap = 0;

  if (key->gck_src == key->gck_dst)
    {
      /* intra-epg allowed */
      (*intra)++;
      *err = GBP_CONTRACT_ERROR_ALLOW_INTRA;
      return GBP_RULE_PERMIT;
    }

  if (1 == key->gck_src || 1 == key->gck_dst)
    {
      /* sclass 1 allowed */
      (*sclass1)++;
      *err = GBP_CONTRACT_ERROR_ALLOW_SCLASS_1;
      return GBP_RULE_PERMIT;
    }

  /* look for contract */
  contract_index = gbp_contract_find (key);
  if (INDEX_INVALID == contract_index)
    {
      *err = GBP_CONTRACT_ERROR_DROP_NO_CONTRACT;
      return GBP_RULE_DENY;
    }

  contract = gbp_contract_get (contract_index);

  *err = GBP_CONTRACT_ERROR_DROP_CONTRACT;

  switch (type)
    {
    case GBP_CONTRACT_APPLY_IP4:
      ip6 = 0;
      break;
    case GBP_CONTRACT_APPLY_IP6:
      ip6 = 1;
      break;
    case GBP_CONTRACT_APPLY_L2:
      {
	/* check ethertype */
	etype =
	  ((u16 *) (vlib_buffer_get_current (b) +
		    vnet_buffer (b)->l2.l2_len))[-1];

	if (~0 == vec_search (contract->gc_allowed_ethertypes, etype))
	  {
	    *err = GBP_CONTRACT_ERROR_DROP_ETHER_TYPE;
	    goto contract_deny;
	  }

	switch (clib_net_to_host_u16 (etype))
	  {
	  case ETHERNET_TYPE_IP4:
	    ip6 = 0;
	    break;
	  case ETHERNET_TYPE_IP6:
	    ip6 = 1;
	    break;
	  default:
	    goto contract_deny;
	  }
      }
      break;
    }

  /* check ACL */
  action = 0;
  acl_plugin_fill_5tuple_inline (gm->acl_plugin.p_acl_main,
				 contract->gc_lc_index, b, ip6,
				 GBP_CONTRACT_APPLY_L2 != type /* input */ ,
				 GBP_CONTRACT_APPLY_L2 == type /* l2_path */ ,
				 &fa_5tuple);
  acl_plugin_match_5tuple_inline (gm->acl_plugin.p_acl_main,
				  contract->gc_lc_index, &fa_5tuple, ip6,
				  &action, &acl_pos, acl_match, rule_match,
				  &trace_bitmap);
  if (action <= 0)
    goto contract_deny;

  if (PREDICT_FALSE (*rule_match >= vec_len (contract->gc_rules)))
    {
      *err = GBP_CONTRACT_ERROR_DROP_NO_RULE;
      goto contract_deny;
    }

  *rule = gbp_rule_get (contract->gc_rules[*rule_match]);
  switch ((*rule)->gu_action)
    {
    case GBP_RULE_PERMIT:
    case GBP_RULE_REDIRECT:
      *err = GBP_CONTRACT_ERROR_ALLOW_CONTRACT;
      vlib_increment_combined_counter (&gbp_contract_permit_counters,
				       vm->thread_index, contract_index, 1,
				       vlib_buffer_length_in_chain (vm, b));
      return (*rule)->gu_action;
    case GBP_RULE_DENY:
      break;
    }

contract_deny:
  vlib_increment_combined_counter (&gbp_contract_drop_counters,
				   vm->thread_index, contract_index, 1,
				   vlib_buffer_length_in_chain (vm, b));
  return GBP_RULE_DENY;
}

#endif /* __GBP_CONTRACT_H__ */
/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */