@@ -1584,6 +1584,15 @@ dp_netdev_pmd_remove_flow(struct dp_netdev_pmd_thread *pmd,
cls = dp_netdev_pmd_lookup_dpcls(pmd, in_port);
ovs_assert(cls != NULL);
+ if (pmd->dp->ppl_md.id == HW_OFFLOAD_PIPELINE &&
+ flow->cr.flow_tag != HW_NO_FREE_FLOW_TAG ) {
+ VLOG_INFO("hw_pipeline_dpcls_remove");
+ hw_pipeline_dpcls_remove(pmd->dp,&flow->cr);
+ }
+ else
+ {
+ VLOG_INFO("skip hw_pipeline_dpcls_remove");
+ }
dpcls_remove(cls, &flow->cr);
cmap_remove(&pmd->flow_table, node, dp_netdev_flow_hash(&flow->ufid));
flow->dead = true;
@@ -36,6 +36,10 @@
VLOG_DEFINE_THIS_MODULE(hw_pipeline);
+bool hw_pipeline_ft_pool_free(flow_tag_pool *p,uint32_t flow_tag);
+
+bool hw_pipeline_ft_pool_is_valid(flow_tag_pool *p);
+
// Internal functions Flow Tags Pool
uint32_t hw_pipeline_ft_pool_init(flow_tag_pool *p,uint32_t pool_size);
@@ -46,8 +50,34 @@ static int hw_pipeline_msg_queue_init(msg_queue *message_queue,
unsigned core_id);
static int hw_pipeline_msg_queue_clear(msg_queue *message_queue);
+static int hw_pipeline_send_remove_flow(struct dp_netdev *dp,
+ uint32_t flow_tag,ovs_u128 *ufidp);
+
void *hw_pipeline_thread(void *pdp);
+/*****************************************************************************/
+// HW Flow Tags Pool
+// A pool of unique tags used by the OVS
+// The flow tag is used as an interface with the HW.
+// If there is a match between a packet & a rule then
+// the flow tag is received by the OVS in the fdir.hash in the rte_mbuf
+// With this flow tag the OVS find the associated flow.
+// The Pool is per pmd_thread.
+// Each flow points on a flow tag and vice versa.
+/*****************************************************************************/
+bool hw_pipeline_ft_pool_is_valid(flow_tag_pool *p)
+{
+ rte_spinlock_lock(&p->lock);
+ if (p->ft_data != NULL && p->pool_size>0) {
+ VLOG_DBG("The pool is allocated & its size is : %d\n", p->pool_size);
+ rte_spinlock_unlock(&p->lock);
+ return true;
+ }
+ VLOG_DBG("The pool is invalid its size is : %d\n", p->pool_size);
+ rte_spinlock_unlock(&p->lock);
+ return false;
+}
+
uint32_t hw_pipeline_ft_pool_init(flow_tag_pool *p,
uint32_t pool_size)
{
@@ -83,6 +113,7 @@ uint32_t hw_pipeline_ft_pool_init(flow_tag_pool *p,
uint32_t hw_pipeline_ft_pool_uninit(flow_tag_pool *p)
{
uint32_t ii=0;
+
if (OVS_UNLIKELY(p==NULL||p->ft_data==NULL)) {
VLOG_ERR("No pool or no data allocated \n");
return -1;
@@ -98,6 +129,45 @@ uint32_t hw_pipeline_ft_pool_uninit(flow_tag_pool *p)
rte_spinlock_unlock(&p->lock);
return 0;
}
+
+/*
+ * hw_pipeline_ft_pool_free returns an index to the pool.
+ * The index is returned to the tail.
+ * The function deals with 3 cases:
+ * 1. index out of range in the pool . returns false
+ * 2. There is an place in the pool :
+ * a. This is the last place .
+ * b. This is the common index .
+ * */
+bool hw_pipeline_ft_pool_free(flow_tag_pool *p,
+ uint32_t handle)
+{
+ uint32_t index ,tail;
+
+ index = OVS_FLOW_TAG_INDEX_GET(handle);
+ if (OVS_UNLIKELY(index >= HW_MAX_FLOW_TAG)) {
+ // ( case 1, see function header above)
+ VLOG_ERR("index out of range \n");
+ return false;
+ }
+ rte_spinlock_lock(&p->lock);
+ tail = p->tail;
+ if (tail == HW_NO_FREE_FLOW_TAG) {
+ // last place in the pool ( case 2a, see function header above)
+ p->head = index;
+ }
+ else {
+ // common case ( case 2b, see function header above)
+ p->ft_data[tail].next = index; // old tail next points on index
+ }
+ // current tail is updated to be index & its next HW_NO_FREE_FLOW_TAG
+ p->tail = index;
+ p->ft_data[index].next = HW_NO_FREE_FLOW_TAG;
+ p->ft_data[index].valid = false;
+ rte_spinlock_unlock(&p->lock);
+ return true;
+}
+
/*************************************************************************/
// Msg Queue
// A queue that contains pairs : (flow , key )
@@ -188,6 +258,45 @@ static int hw_pipeline_msg_queue_clear(msg_queue *message_queue)
return 0;
}
+
+
+static bool hw_pipeline_msg_queue_enqueue(msg_queue *message_queue,
+ msg_queue_elem *data)
+{
+ ssize_t ret =0;
+
+ ret = write(message_queue->writeFd, data, sizeof(msg_queue_elem));
+ if (OVS_UNLIKELY( ret == -1)) {
+ switch (errno) {
+ case EBADF:
+ VLOG_ERR("FD is non-valid , or is not open for writing.\n");
+ break;
+ case EFBIG:
+ VLOG_ERR("File is too large.\n");
+ break;
+ case EINTR:
+ VLOG_ERR("interrupted by a signal\n");
+ break;
+ case EIO:
+ VLOG_ERR("hardware error\n");
+ break;
+ case ENOSPC:
+ VLOG_ERR("The device's file is full\n");
+ break;
+ case EPIPE:
+ VLOG_ERR("FIFO that isn't open for reading\n");
+ break;
+ case EINVAL:
+ VLOG_ERR("Not aligned to the block size");
+ break;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ return true;
+}
void *hw_pipeline_thread(void *pdp)
{
struct dp_netdev *dp= (struct dp_netdev *)pdp;
@@ -241,3 +350,43 @@ int hw_pipeline_uninit(struct dp_netdev *dp)
dp->ppl_md.id = DEFAULT_SW_PIPELINE;
return 0;
}
+
+static int hw_pipeline_send_remove_flow(struct dp_netdev *dp,uint32_t flow_tag,
+ ovs_u128 *ufidp)
+{
+ msg_queue_elem rule;
+
+ rule.data.rm_flow.in_port=
+ dp->ft_pool.ft_data[flow_tag].sw_flow->flow.in_port.odp_port;
+ rule.data.rm_flow.flow_tag = flow_tag;
+ memcpy(&rule.data.rm_flow.ufid,ufidp,sizeof(ovs_u128));
+ rule.mode = HW_PIPELINE_REMOVE_RULE;
+ if (OVS_UNLIKELY(
+ !hw_pipeline_msg_queue_enqueue(&dp->message_queue,&rule))) {
+ VLOG_INFO("queue overflow");
+ return -1;
+ }
+ return 0;
+}
+/* Removes 'rule' from 'cls', also distracting the 'rule'.
+ * Free the unique tag back to pool.
+ * The function sends a message to the message queue
+ * to insert a rule to HW, but
+ * in the context of hw_pipeline_thread
+ * */
+void
+hw_pipeline_dpcls_remove(struct dp_netdev *dp,
+ struct dpcls_rule *rule)
+{
+ if (hw_pipeline_send_remove_flow(dp,rule->flow_tag,rule->ufidp)==-1) {
+ VLOG_ERR("The Message Queue is FULL \n");
+ return;
+ }
+ if (OVS_LIKELY(hw_pipeline_ft_pool_is_valid(&dp->ft_pool))) {
+ if (OVS_UNLIKELY(
+ !hw_pipeline_ft_pool_free(&dp->ft_pool,rule->flow_tag))) {
+ VLOG_ERR("tag is out of range");
+ return;
+ }
+ }
+}
@@ -26,9 +26,23 @@ enum pipeline_id {
HW_OFFLOAD_PIPELINE
};
+typedef enum{
+ HW_PIPELINE_NO_RULE,
+ HW_PIPELINE_INSERT_RULE,
+ HW_PIPELINE_REMOVE_RULE
+}HW_pipeline_msgq_mode;
+
struct pipeline_md {
uint16_t id;
uint32_t flow_tag;
};
+#define OVS_GET_HANDLE_VALUE(x,s,w) ((x>>s)&((1<<(w+1))-1))
+
+#define OVS_FLOW_TAG_INDEX_W 16
+#define OVS_FLOW_TAG_INDEX_S 0
+#define OVS_FLOW_TAG_INDEX_M ((1<<(OVS_FLOW_TAG_INDEX_W+1))-1)
+#define OVS_FLOW_TAG_INDEX_GET(x) \
+ OVS_GET_HANDLE_VALUE(x,OVS_FLOW_TAG_INDEX_S,OVS_FLOW_TAG_INDEX_W)
+
#endif /* LIB_HW_PIPELINE_H_ */
PMD send a flow that would be removed by HW classifier Signed-off-by: Shachar Beiser <shacharbe@mellanox.com> Conflicts: lib/hw-pipeline.c --- lib/dpif-netdev.c | 9 ++++ lib/hw-pipeline.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/hw-pipeline.h | 14 +++++ 3 files changed, 172 insertions(+)