1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2018 Intel Corporation
8 #include <rte_common.h>
9 #include <rte_byteorder.h>
10 #include <rte_cycles.h>
11 #include <rte_malloc.h>
15 #include "rte_table_action.h"
17 #define rte_htons rte_cpu_to_be_16
18 #define rte_htonl rte_cpu_to_be_32
20 #define rte_ntohs rte_be_to_cpu_16
21 #define rte_ntohl rte_be_to_cpu_32
24 * RTE_TABLE_ACTION_FWD
26 #define fwd_data rte_pipeline_table_entry
29 fwd_apply(struct fwd_data *data,
30 struct rte_table_action_fwd_params *p)
32 data->action = p->action;
34 if (p->action == RTE_PIPELINE_ACTION_PORT)
35 data->port_id = p->id;
37 if (p->action == RTE_PIPELINE_ACTION_TABLE)
38 data->table_id = p->id;
44 * RTE_TABLE_ACTION_MTR
47 mtr_cfg_check(struct rte_table_action_mtr_config *mtr)
49 if ((mtr->alg == RTE_TABLE_ACTION_METER_SRTCM) ||
50 ((mtr->n_tc != 1) && (mtr->n_tc != 4)) ||
51 (mtr->n_bytes_enabled != 0))
56 #define MBUF_SCHED_QUEUE_TC_COLOR(queue, tc, color) \
57 ((uint16_t)((((uint64_t)(queue)) & 0x3) | \
58 ((((uint64_t)(tc)) & 0x3) << 2) | \
59 ((((uint64_t)(color)) & 0x3) << 4)))
61 #define MBUF_SCHED_COLOR(sched, color) \
62 (((sched) & (~0x30LLU)) | ((color) << 4))
64 struct mtr_trtcm_data {
65 struct rte_meter_trtcm trtcm;
66 uint64_t stats[e_RTE_METER_COLORS];
67 } __attribute__((__packed__));
69 #define MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data) \
70 (((data)->stats[e_RTE_METER_GREEN] & 0xF8LLU) >> 3)
73 mtr_trtcm_data_meter_profile_id_set(struct mtr_trtcm_data *data,
76 data->stats[e_RTE_METER_GREEN] &= ~0xF8LLU;
77 data->stats[e_RTE_METER_GREEN] |= (profile_id % 32) << 3;
80 #define MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color)\
81 (((data)->stats[(color)] & 4LLU) >> 2)
83 #define MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color)\
84 ((enum rte_meter_color)((data)->stats[(color)] & 3LLU))
87 mtr_trtcm_data_policer_action_set(struct mtr_trtcm_data *data,
88 enum rte_meter_color color,
89 enum rte_table_action_policer action)
91 if (action == RTE_TABLE_ACTION_POLICER_DROP) {
92 data->stats[color] |= 4LLU;
94 data->stats[color] &= ~7LLU;
95 data->stats[color] |= color & 3LLU;
100 mtr_trtcm_data_stats_get(struct mtr_trtcm_data *data,
101 enum rte_meter_color color)
103 return data->stats[color] >> 8;
107 mtr_trtcm_data_stats_reset(struct mtr_trtcm_data *data,
108 enum rte_meter_color color)
110 data->stats[color] &= 0xFFLU;
113 #define MTR_TRTCM_DATA_STATS_INC(data, color) \
114 ((data)->stats[(color)] += (1LLU << 8))
117 mtr_data_size(struct rte_table_action_mtr_config *mtr)
119 return mtr->n_tc * sizeof(struct mtr_trtcm_data);
122 struct dscp_table_entry_data {
123 enum rte_meter_color color;
125 uint16_t queue_tc_color;
128 struct dscp_table_data {
129 struct dscp_table_entry_data entry[64];
132 struct meter_profile_data {
133 struct rte_meter_trtcm_profile profile;
138 static struct meter_profile_data *
139 meter_profile_data_find(struct meter_profile_data *mp,
145 for (i = 0; i < mp_size; i++) {
146 struct meter_profile_data *mp_data = &mp[i];
148 if (mp_data->valid && (mp_data->profile_id == profile_id))
155 static struct meter_profile_data *
156 meter_profile_data_find_unused(struct meter_profile_data *mp,
161 for (i = 0; i < mp_size; i++) {
162 struct meter_profile_data *mp_data = &mp[i];
172 mtr_apply_check(struct rte_table_action_mtr_params *p,
173 struct rte_table_action_mtr_config *cfg,
174 struct meter_profile_data *mp,
179 if (p->tc_mask > RTE_LEN2MASK(cfg->n_tc, uint32_t))
182 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
183 struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
184 struct meter_profile_data *mp_data;
186 if ((p->tc_mask & (1LLU << i)) == 0)
189 mp_data = meter_profile_data_find(mp,
191 p_tc->meter_profile_id);
200 mtr_apply(struct mtr_trtcm_data *data,
201 struct rte_table_action_mtr_params *p,
202 struct rte_table_action_mtr_config *cfg,
203 struct meter_profile_data *mp,
209 /* Check input arguments */
210 status = mtr_apply_check(p, cfg, mp, mp_size);
215 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
216 struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
217 struct mtr_trtcm_data *data_tc = &data[i];
218 struct meter_profile_data *mp_data;
220 if ((p->tc_mask & (1LLU << i)) == 0)
224 mp_data = meter_profile_data_find(mp,
226 p_tc->meter_profile_id);
230 memset(data_tc, 0, sizeof(*data_tc));
233 status = rte_meter_trtcm_config(&data_tc->trtcm,
239 mtr_trtcm_data_meter_profile_id_set(data_tc,
242 /* Policer actions */
243 mtr_trtcm_data_policer_action_set(data_tc,
245 p_tc->policer[e_RTE_METER_GREEN]);
247 mtr_trtcm_data_policer_action_set(data_tc,
249 p_tc->policer[e_RTE_METER_YELLOW]);
251 mtr_trtcm_data_policer_action_set(data_tc,
253 p_tc->policer[e_RTE_METER_RED]);
259 static __rte_always_inline uint64_t
260 pkt_work_mtr(struct rte_mbuf *mbuf,
261 struct mtr_trtcm_data *data,
262 struct dscp_table_data *dscp_table,
263 struct meter_profile_data *mp,
266 uint16_t total_length)
268 uint64_t drop_mask, sched;
269 uint64_t *sched_ptr = (uint64_t *) &mbuf->hash.sched;
270 struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
271 enum rte_meter_color color_in, color_meter, color_policer;
275 color_in = dscp_entry->color;
277 mp_id = MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data);
281 color_meter = rte_meter_trtcm_color_aware_check(
289 MTR_TRTCM_DATA_STATS_INC(data, color_meter);
292 drop_mask = MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color_meter);
294 MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color_meter);
295 *sched_ptr = MBUF_SCHED_COLOR(sched, color_policer);
305 action_valid(enum rte_table_action_type action)
308 case RTE_TABLE_ACTION_FWD:
309 case RTE_TABLE_ACTION_MTR:
317 #define RTE_TABLE_ACTION_MAX 64
320 uint64_t action_mask;
321 struct rte_table_action_common_config common;
322 struct rte_table_action_mtr_config mtr;
326 action_cfg_size(enum rte_table_action_type action)
329 case RTE_TABLE_ACTION_MTR:
330 return sizeof(struct rte_table_action_mtr_config);
337 action_cfg_get(struct ap_config *ap_config,
338 enum rte_table_action_type type)
341 case RTE_TABLE_ACTION_MTR:
342 return &ap_config->mtr;
350 action_cfg_set(struct ap_config *ap_config,
351 enum rte_table_action_type type,
354 void *dst = action_cfg_get(ap_config, type);
357 memcpy(dst, action_cfg, action_cfg_size(type));
359 ap_config->action_mask |= 1LLU << type;
363 size_t offset[RTE_TABLE_ACTION_MAX];
368 action_data_size(enum rte_table_action_type action,
369 struct ap_config *ap_config)
372 case RTE_TABLE_ACTION_FWD:
373 return sizeof(struct fwd_data);
375 case RTE_TABLE_ACTION_MTR:
376 return mtr_data_size(&ap_config->mtr);
385 action_data_offset_set(struct ap_data *ap_data,
386 struct ap_config *ap_config)
388 uint64_t action_mask = ap_config->action_mask;
392 memset(ap_data->offset, 0, sizeof(ap_data->offset));
395 for (action = 0; action < RTE_TABLE_ACTION_MAX; action++)
396 if (action_mask & (1LLU << action)) {
397 ap_data->offset[action] = offset;
398 offset += action_data_size((enum rte_table_action_type)action,
402 ap_data->total_size = offset;
405 struct rte_table_action_profile {
406 struct ap_config cfg;
411 struct rte_table_action_profile *
412 rte_table_action_profile_create(struct rte_table_action_common_config *common)
414 struct rte_table_action_profile *ap;
416 /* Check input arguments */
420 /* Memory allocation */
421 ap = calloc(1, sizeof(struct rte_table_action_profile));
426 memcpy(&ap->cfg.common, common, sizeof(*common));
433 rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
434 enum rte_table_action_type type,
439 /* Check input arguments */
440 if ((profile == NULL) ||
442 (action_valid(type) == 0) ||
443 (profile->cfg.action_mask & (1LLU << type)) ||
444 ((action_cfg_size(type) == 0) && action_config) ||
445 (action_cfg_size(type) && (action_config == NULL)))
449 case RTE_TABLE_ACTION_MTR:
450 status = mtr_cfg_check(action_config);
462 action_cfg_set(&profile->cfg, type, action_config);
468 rte_table_action_profile_freeze(struct rte_table_action_profile *profile)
473 profile->cfg.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
474 action_data_offset_set(&profile->data, &profile->cfg);
481 rte_table_action_profile_free(struct rte_table_action_profile *profile)
493 #define METER_PROFILES_MAX 32
495 struct rte_table_action {
496 struct ap_config cfg;
498 struct dscp_table_data dscp_table;
499 struct meter_profile_data mp[METER_PROFILES_MAX];
502 struct rte_table_action *
503 rte_table_action_create(struct rte_table_action_profile *profile,
506 struct rte_table_action *action;
508 /* Check input arguments */
509 if ((profile == NULL) ||
510 (profile->frozen == 0))
513 /* Memory allocation */
514 action = rte_zmalloc_socket(NULL,
515 sizeof(struct rte_table_action),
522 memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg));
523 memcpy(&action->data, &profile->data, sizeof(profile->data));
528 static __rte_always_inline void *
529 action_data_get(void *data,
530 struct rte_table_action *action,
531 enum rte_table_action_type type)
533 size_t offset = action->data.offset[type];
534 uint8_t *data_bytes = data;
536 return &data_bytes[offset];
540 rte_table_action_apply(struct rte_table_action *action,
542 enum rte_table_action_type type,
547 /* Check input arguments */
548 if ((action == NULL) ||
550 (action_valid(type) == 0) ||
551 ((action->cfg.action_mask & (1LLU << type)) == 0) ||
552 (action_params == NULL))
556 action_data = action_data_get(data, action, type);
559 case RTE_TABLE_ACTION_FWD:
560 return fwd_apply(action_data,
563 case RTE_TABLE_ACTION_MTR:
564 return mtr_apply(action_data,
568 RTE_DIM(action->mp));
576 rte_table_action_dscp_table_update(struct rte_table_action *action,
578 struct rte_table_action_dscp_table *table)
582 /* Check input arguments */
583 if ((action == NULL) ||
584 (action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) ||
589 for (i = 0; i < RTE_DIM(table->entry); i++) {
590 struct dscp_table_entry_data *data =
591 &action->dscp_table.entry[i];
592 struct rte_table_action_dscp_table_entry *entry =
594 uint16_t queue_tc_color =
595 MBUF_SCHED_QUEUE_TC_COLOR(entry->tc_queue_id,
599 if ((dscp_mask & (1LLU << i)) == 0)
602 data->color = entry->color;
603 data->tc = entry->tc_id;
604 data->queue_tc_color = queue_tc_color;
611 rte_table_action_meter_profile_add(struct rte_table_action *action,
612 uint32_t meter_profile_id,
613 struct rte_table_action_meter_profile *profile)
615 struct meter_profile_data *mp_data;
618 /* Check input arguments */
619 if ((action == NULL) ||
620 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
624 if (profile->alg != RTE_TABLE_ACTION_METER_TRTCM)
627 mp_data = meter_profile_data_find(action->mp,
633 mp_data = meter_profile_data_find_unused(action->mp,
634 RTE_DIM(action->mp));
638 /* Install new profile */
639 status = rte_meter_trtcm_profile_config(&mp_data->profile,
644 mp_data->profile_id = meter_profile_id;
651 rte_table_action_meter_profile_delete(struct rte_table_action *action,
652 uint32_t meter_profile_id)
654 struct meter_profile_data *mp_data;
656 /* Check input arguments */
657 if ((action == NULL) ||
658 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0))
661 mp_data = meter_profile_data_find(action->mp,
667 /* Uninstall profile */
674 rte_table_action_meter_read(struct rte_table_action *action,
677 struct rte_table_action_mtr_counters *stats,
680 struct mtr_trtcm_data *mtr_data;
683 /* Check input arguments */
684 if ((action == NULL) ||
685 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
687 (tc_mask > RTE_LEN2MASK(action->cfg.mtr.n_tc, uint32_t)))
690 mtr_data = action_data_get(data, action, RTE_TABLE_ACTION_MTR);
694 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
695 struct rte_table_action_mtr_counters_tc *dst =
697 struct mtr_trtcm_data *src = &mtr_data[i];
699 if ((tc_mask & (1 << i)) == 0)
702 dst->n_packets[e_RTE_METER_GREEN] =
703 mtr_trtcm_data_stats_get(src, e_RTE_METER_GREEN);
705 dst->n_packets[e_RTE_METER_YELLOW] =
706 mtr_trtcm_data_stats_get(src, e_RTE_METER_YELLOW);
708 dst->n_packets[e_RTE_METER_RED] =
709 mtr_trtcm_data_stats_get(src, e_RTE_METER_RED);
711 dst->n_packets_valid = 1;
712 dst->n_bytes_valid = 0;
715 stats->tc_mask = tc_mask;
720 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
721 struct mtr_trtcm_data *src = &mtr_data[i];
723 if ((tc_mask & (1 << i)) == 0)
726 mtr_trtcm_data_stats_reset(src, e_RTE_METER_GREEN);
727 mtr_trtcm_data_stats_reset(src, e_RTE_METER_YELLOW);
728 mtr_trtcm_data_stats_reset(src, e_RTE_METER_RED);
735 static __rte_always_inline uint64_t
736 pkt_work(struct rte_mbuf *mbuf,
737 struct rte_pipeline_table_entry *table_entry,
739 struct rte_table_action *action,
740 struct ap_config *cfg)
742 uint64_t drop_mask = 0;
744 uint32_t ip_offset = action->cfg.common.ip_offset;
745 void *ip = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ip_offset);
748 uint16_t total_length;
750 if (cfg->common.ip_version) {
751 struct ipv4_hdr *hdr = ip;
753 dscp = hdr->type_of_service >> 2;
754 total_length = rte_ntohs(hdr->total_length);
756 struct ipv6_hdr *hdr = ip;
758 dscp = (rte_ntohl(hdr->vtc_flow) & 0x0F600000) >> 18;
760 rte_ntohs(hdr->payload_len) + sizeof(struct ipv6_hdr);
763 if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
765 action_data_get(table_entry, action, RTE_TABLE_ACTION_MTR);
767 drop_mask |= pkt_work_mtr(mbuf,
779 static __rte_always_inline uint64_t
780 pkt4_work(struct rte_mbuf **mbufs,
781 struct rte_pipeline_table_entry **table_entries,
783 struct rte_table_action *action,
784 struct ap_config *cfg)
786 uint64_t drop_mask0 = 0;
787 uint64_t drop_mask1 = 0;
788 uint64_t drop_mask2 = 0;
789 uint64_t drop_mask3 = 0;
791 struct rte_mbuf *mbuf0 = mbufs[0];
792 struct rte_mbuf *mbuf1 = mbufs[1];
793 struct rte_mbuf *mbuf2 = mbufs[2];
794 struct rte_mbuf *mbuf3 = mbufs[3];
796 struct rte_pipeline_table_entry *table_entry0 = table_entries[0];
797 struct rte_pipeline_table_entry *table_entry1 = table_entries[1];
798 struct rte_pipeline_table_entry *table_entry2 = table_entries[2];
799 struct rte_pipeline_table_entry *table_entry3 = table_entries[3];
801 uint32_t ip_offset = action->cfg.common.ip_offset;
802 void *ip0 = RTE_MBUF_METADATA_UINT32_PTR(mbuf0, ip_offset);
803 void *ip1 = RTE_MBUF_METADATA_UINT32_PTR(mbuf1, ip_offset);
804 void *ip2 = RTE_MBUF_METADATA_UINT32_PTR(mbuf2, ip_offset);
805 void *ip3 = RTE_MBUF_METADATA_UINT32_PTR(mbuf3, ip_offset);
807 uint32_t dscp0, dscp1, dscp2, dscp3;
808 uint16_t total_length0, total_length1, total_length2, total_length3;
810 if (cfg->common.ip_version) {
811 struct ipv4_hdr *hdr0 = ip0;
812 struct ipv4_hdr *hdr1 = ip1;
813 struct ipv4_hdr *hdr2 = ip2;
814 struct ipv4_hdr *hdr3 = ip3;
816 dscp0 = hdr0->type_of_service >> 2;
817 dscp1 = hdr1->type_of_service >> 2;
818 dscp2 = hdr2->type_of_service >> 2;
819 dscp3 = hdr3->type_of_service >> 2;
821 total_length0 = rte_ntohs(hdr0->total_length);
822 total_length1 = rte_ntohs(hdr1->total_length);
823 total_length2 = rte_ntohs(hdr2->total_length);
824 total_length3 = rte_ntohs(hdr3->total_length);
826 struct ipv6_hdr *hdr0 = ip0;
827 struct ipv6_hdr *hdr1 = ip1;
828 struct ipv6_hdr *hdr2 = ip2;
829 struct ipv6_hdr *hdr3 = ip3;
831 dscp0 = (rte_ntohl(hdr0->vtc_flow) & 0x0F600000) >> 18;
832 dscp1 = (rte_ntohl(hdr1->vtc_flow) & 0x0F600000) >> 18;
833 dscp2 = (rte_ntohl(hdr2->vtc_flow) & 0x0F600000) >> 18;
834 dscp3 = (rte_ntohl(hdr3->vtc_flow) & 0x0F600000) >> 18;
837 rte_ntohs(hdr0->payload_len) + sizeof(struct ipv6_hdr);
839 rte_ntohs(hdr1->payload_len) + sizeof(struct ipv6_hdr);
841 rte_ntohs(hdr2->payload_len) + sizeof(struct ipv6_hdr);
843 rte_ntohs(hdr3->payload_len) + sizeof(struct ipv6_hdr);
846 if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
848 action_data_get(table_entry0, action, RTE_TABLE_ACTION_MTR);
850 action_data_get(table_entry1, action, RTE_TABLE_ACTION_MTR);
852 action_data_get(table_entry2, action, RTE_TABLE_ACTION_MTR);
854 action_data_get(table_entry3, action, RTE_TABLE_ACTION_MTR);
856 drop_mask0 |= pkt_work_mtr(mbuf0,
864 drop_mask1 |= pkt_work_mtr(mbuf1,
872 drop_mask2 |= pkt_work_mtr(mbuf2,
880 drop_mask3 |= pkt_work_mtr(mbuf3,
895 static __rte_always_inline int
896 ah(struct rte_pipeline *p,
897 struct rte_mbuf **pkts,
899 struct rte_pipeline_table_entry **entries,
900 struct rte_table_action *action,
901 struct ap_config *cfg)
903 uint64_t pkts_drop_mask = 0;
906 if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR))
909 if ((pkts_mask & (pkts_mask + 1)) == 0) {
910 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
913 for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {
916 drop_mask = pkt4_work(&pkts[i],
922 pkts_drop_mask |= drop_mask << i;
925 for ( ; i < n_pkts; i++) {
928 drop_mask = pkt_work(pkts[i],
934 pkts_drop_mask |= drop_mask << i;
937 for ( ; pkts_mask; ) {
938 uint32_t pos = __builtin_ctzll(pkts_mask);
939 uint64_t pkt_mask = 1LLU << pos;
942 drop_mask = pkt_work(pkts[pos],
948 pkts_mask &= ~pkt_mask;
949 pkts_drop_mask |= drop_mask << pos;
952 rte_pipeline_ah_packet_drop(p, pkts_drop_mask);
958 ah_default(struct rte_pipeline *p,
959 struct rte_mbuf **pkts,
961 struct rte_pipeline_table_entry **entries,
964 struct rte_table_action *action = arg;
974 static rte_pipeline_table_action_handler_hit
975 ah_selector(struct rte_table_action *action)
977 if (action->cfg.action_mask == (1LLU << RTE_TABLE_ACTION_FWD))
984 rte_table_action_table_params_get(struct rte_table_action *action,
985 struct rte_pipeline_table_params *params)
987 rte_pipeline_table_action_handler_hit f_action_hit;
990 /* Check input arguments */
991 if ((action == NULL) ||
995 f_action_hit = ah_selector(action);
996 total_size = rte_align32pow2(action->data.total_size);
999 params->f_action_hit = f_action_hit;
1000 params->f_action_miss = NULL;
1001 params->arg_ah = (f_action_hit) ? action : NULL;
1002 params->action_data_size = total_size -
1003 sizeof(struct rte_pipeline_table_entry);
1009 rte_table_action_free(struct rte_table_action *action)