From 625f4d4040d53dc3ae221d59df7fc7d05ed6a970 Mon Sep 17 00:00:00 2001 From: Jasvinder Singh Date: Thu, 29 Mar 2018 19:31:26 +0100 Subject: [PATCH] pipeline: add TTL update action Add implementation of ttl update action. Signed-off-by: Cristian Dumitrescu --- lib/librte_pipeline/rte_pipeline_version.map | 1 + lib/librte_pipeline/rte_table_action.c | 162 +++++++++++++++++++ lib/librte_pipeline/rte_table_action.h | 66 ++++++++ 3 files changed, 229 insertions(+) diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map index c7106dc2cc..938858550d 100644 --- a/lib/librte_pipeline/rte_pipeline_version.map +++ b/lib/librte_pipeline/rte_pipeline_version.map @@ -61,5 +61,6 @@ EXPERIMENTAL { rte_table_action_profile_free; rte_table_action_profile_freeze; rte_table_action_table_params_get; + rte_table_action_ttl_read; } DPDK_16.04; diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c index d22493a839..c77bfb7eea 100644 --- a/lib/librte_pipeline/rte_table_action.c +++ b/lib/librte_pipeline/rte_table_action.c @@ -1030,6 +1030,89 @@ pkt_ipv6_work_nat(struct ipv6_hdr *ip, } } +/** + * RTE_TABLE_ACTION_TTL + */ +static int +ttl_cfg_check(struct rte_table_action_ttl_config *ttl) +{ + if (ttl->drop == 0) + return -ENOTSUP; + + return 0; +} + +struct ttl_data { + uint32_t n_packets; +} __attribute__((__packed__)); + +#define TTL_INIT(data, decrement) \ + ((data)->n_packets = (decrement) ? 1 : 0) + +#define TTL_DEC_GET(data) \ + ((uint8_t)((data)->n_packets & 1)) + +#define TTL_STATS_RESET(data) \ + ((data)->n_packets = ((data)->n_packets & 1)) + +#define TTL_STATS_READ(data) \ + ((data)->n_packets >> 1) + +#define TTL_STATS_ADD(data, value) \ + ((data)->n_packets = \ + (((((data)->n_packets >> 1) + (value)) << 1) | \ + ((data)->n_packets & 1))) + +static int +ttl_apply(void *data, + struct rte_table_action_ttl_params *p) +{ + struct ttl_data *d = data; + + TTL_INIT(d, p->decrement); + + return 0; +} + +static __rte_always_inline uint64_t +pkt_ipv4_work_ttl(struct ipv4_hdr *ip, + struct ttl_data *data) +{ + uint32_t drop; + uint16_t cksum = ip->hdr_checksum; + uint8_t ttl = ip->time_to_live; + uint8_t ttl_diff = TTL_DEC_GET(data); + + cksum += ttl_diff; + ttl -= ttl_diff; + + ip->hdr_checksum = cksum; + ip->time_to_live = ttl; + + drop = (ttl == 0) ? 1 : 0; + TTL_STATS_ADD(data, drop); + + return drop; +} + +static __rte_always_inline uint64_t +pkt_ipv6_work_ttl(struct ipv6_hdr *ip, + struct ttl_data *data) +{ + uint32_t drop; + uint8_t ttl = ip->hop_limits; + uint8_t ttl_diff = TTL_DEC_GET(data); + + ttl -= ttl_diff; + + ip->hop_limits = ttl; + + drop = (ttl == 0) ? 1 : 0; + TTL_STATS_ADD(data, drop); + + return drop; +} + /** * Action profile */ @@ -1042,6 +1125,7 @@ action_valid(enum rte_table_action_type action) case RTE_TABLE_ACTION_TM: case RTE_TABLE_ACTION_ENCAP: case RTE_TABLE_ACTION_NAT: + case RTE_TABLE_ACTION_TTL: return 1; default: return 0; @@ -1058,6 +1142,7 @@ struct ap_config { struct rte_table_action_tm_config tm; struct rte_table_action_encap_config encap; struct rte_table_action_nat_config nat; + struct rte_table_action_ttl_config ttl; }; static size_t @@ -1072,6 +1157,8 @@ action_cfg_size(enum rte_table_action_type action) return sizeof(struct rte_table_action_encap_config); case RTE_TABLE_ACTION_NAT: return sizeof(struct rte_table_action_nat_config); + case RTE_TABLE_ACTION_TTL: + return sizeof(struct rte_table_action_ttl_config); default: return 0; } @@ -1094,6 +1181,9 @@ action_cfg_get(struct ap_config *ap_config, case RTE_TABLE_ACTION_NAT: return &ap_config->nat; + case RTE_TABLE_ACTION_TTL: + return &ap_config->ttl; + default: return NULL; } @@ -1138,6 +1228,9 @@ action_data_size(enum rte_table_action_type action, return nat_data_size(&ap_config->nat, &ap_config->common); + case RTE_TABLE_ACTION_TTL: + return sizeof(struct ttl_data); + default: return 0; } @@ -1225,6 +1318,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil status = nat_cfg_check(action_config); break; + case RTE_TABLE_ACTION_TTL: + status = ttl_cfg_check(action_config); + break; + default: status = 0; break; @@ -1358,6 +1455,10 @@ rte_table_action_apply(struct rte_table_action *action, action_params, &action->cfg.common); + case RTE_TABLE_ACTION_TTL: + return ttl_apply(action_data, + action_params); + default: return -EINVAL; } @@ -1524,6 +1625,34 @@ rte_table_action_meter_read(struct rte_table_action *action, return 0; } +int +rte_table_action_ttl_read(struct rte_table_action *action, + void *data, + struct rte_table_action_ttl_counters *stats, + int clear) +{ + struct ttl_data *ttl_data; + + /* Check input arguments */ + if ((action == NULL) || + ((action->cfg.action_mask & + (1LLU << RTE_TABLE_ACTION_TTL)) == 0) || + (data == NULL)) + return -EINVAL; + + ttl_data = action_data_get(data, action, RTE_TABLE_ACTION_TTL); + + /* Read */ + if (stats) + stats->n_packets = TTL_STATS_READ(ttl_data); + + /* Clear */ + if (clear) + TTL_STATS_RESET(ttl_data); + + return 0; +} + static __rte_always_inline uint64_t pkt_work(struct rte_mbuf *mbuf, struct rte_pipeline_table_entry *table_entry, @@ -1597,6 +1726,16 @@ pkt_work(struct rte_mbuf *mbuf, pkt_ipv6_work_nat(ip, data, &cfg->nat); } + if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) { + void *data = + action_data_get(table_entry, action, RTE_TABLE_ACTION_TTL); + + if (cfg->common.ip_version) + drop_mask |= pkt_ipv4_work_ttl(ip, data); + else + drop_mask |= pkt_ipv6_work_ttl(ip, data); + } + return drop_mask; } @@ -1803,6 +1942,29 @@ pkt4_work(struct rte_mbuf **mbufs, } } + if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) { + void *data0 = + action_data_get(table_entry0, action, RTE_TABLE_ACTION_TTL); + void *data1 = + action_data_get(table_entry1, action, RTE_TABLE_ACTION_TTL); + void *data2 = + action_data_get(table_entry2, action, RTE_TABLE_ACTION_TTL); + void *data3 = + action_data_get(table_entry3, action, RTE_TABLE_ACTION_TTL); + + if (cfg->common.ip_version) { + drop_mask0 |= pkt_ipv4_work_ttl(ip0, data0); + drop_mask1 |= pkt_ipv4_work_ttl(ip1, data1); + drop_mask2 |= pkt_ipv4_work_ttl(ip2, data2); + drop_mask3 |= pkt_ipv4_work_ttl(ip3, data3); + } else { + drop_mask0 |= pkt_ipv6_work_ttl(ip0, data0); + drop_mask1 |= pkt_ipv6_work_ttl(ip1, data1); + drop_mask2 |= pkt_ipv6_work_ttl(ip2, data2); + drop_mask3 |= pkt_ipv6_work_ttl(ip3, data3); + } + } + return drop_mask0 | (drop_mask1 << 1) | (drop_mask2 << 2) | diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h index 5204511857..57ac4f9161 100644 --- a/lib/librte_pipeline/rte_table_action.h +++ b/lib/librte_pipeline/rte_table_action.h @@ -80,6 +80,9 @@ enum rte_table_action_type { /** Network Address Translation (NAT). */ RTE_TABLE_ACTION_NAT, + + /** Time to Live (TTL) update. */ + RTE_TABLE_ACTION_TTL, }; /** Common action configuration (per table action profile). */ @@ -447,6 +450,44 @@ struct rte_table_action_nat_params { uint16_t port; }; +/** + * RTE_TABLE_ACTION_TTL + */ +/** TTL action configuration (per table action profile). */ +struct rte_table_action_ttl_config { + /** When non-zero, the input packets whose updated IPv4 Time to Live + * (TTL) field or IPv6 Hop Limit (HL) field is zero are dropped. + * When zero, the input packets whose updated IPv4 TTL field or IPv6 HL + * field is zero are forwarded as usual (typically for debugging + * purpose). + */ + int drop; + + /** When non-zero, the *n_packets* stats counter for TTL action is + * enabled, otherwise disabled. + * + * @see struct rte_table_action_ttl_counters + */ + int n_packets_enabled; +}; + +/** TTL action parameters (per table rule). */ +struct rte_table_action_ttl_params { + /** When non-zero, decrement the IPv4 TTL field and update the checksum + * field, or decrement the IPv6 HL field. When zero, the IPv4 TTL field + * or the IPv6 HL field is not changed. + */ + int decrement; +}; + +/** TTL action statistics packets (per table rule). */ +struct rte_table_action_ttl_counters { + /** Number of IPv4 packets whose updated TTL field is zero or IPv6 + * packets whose updated HL field is zero. + */ + uint64_t n_packets; +}; + /** * Table action profile. */ @@ -671,6 +712,31 @@ rte_table_action_meter_read(struct rte_table_action *action, struct rte_table_action_mtr_counters *stats, int clear); +/** + * Table action TTL read. + * + * @param[in] action + * Handle to table action object (needs to be valid). + * @param[in] data + * Data byte array (typically table rule data) with TTL action previously + * applied on it. + * @param[inout] stats + * When non-NULL, it points to the area where the TTL stats counters read from + * *data* are saved. + * @param[in] clear + * When non-zero, the TTL stats counters are cleared (i.e. set to zero), + * otherwise the counters are not modified. When the read operation is enabled + * (*stats* is non-NULL), the clear operation is performed after the read + * operation is completed. + * @return + * Zero on success, non-zero error code otherwise. + */ +int __rte_experimental +rte_table_action_ttl_read(struct rte_table_action *action, + void *data, + struct rte_table_action_ttl_counters *stats, + int clear); + #ifdef __cplusplus } #endif -- 2.20.1