f00708c2aa
Add ip4_rewrite and ip4_lookup ctrl API. ip4_lookup ctrl API is used to add route entries for LPM lookup with result data containing next hop id and next proto. ip4_rewrite ctrl API is used to add rewrite data for every next hop. Signed-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com> Signed-off-by: Pavan Nikhilesh <pbhagavatula@marvell.com> Signed-off-by: Kiran Kumar K <kirankumark@marvell.com>
327 lines
8.2 KiB
C
327 lines
8.2 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(C) 2020 Marvell International Ltd.
|
|
*/
|
|
|
|
#include <rte_debug.h>
|
|
#include <rte_ethdev.h>
|
|
#include <rte_ether.h>
|
|
#include <rte_graph.h>
|
|
#include <rte_graph_worker.h>
|
|
#include <rte_ip.h>
|
|
#include <rte_malloc.h>
|
|
#include <rte_mbuf.h>
|
|
#include <rte_tcp.h>
|
|
#include <rte_udp.h>
|
|
#include <rte_vect.h>
|
|
|
|
#include "rte_node_ip4_api.h"
|
|
|
|
#include "ip4_rewrite_priv.h"
|
|
#include "node_private.h"
|
|
|
|
static struct ip4_rewrite_node_main *ip4_rewrite_nm;
|
|
|
|
static uint16_t
|
|
ip4_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
|
|
void **objs, uint16_t nb_objs)
|
|
{
|
|
struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;
|
|
struct ip4_rewrite_nh_header *nh = ip4_rewrite_nm->nh;
|
|
uint16_t next0, next1, next2, next3, next_index;
|
|
struct rte_ipv4_hdr *ip0, *ip1, *ip2, *ip3;
|
|
uint16_t n_left_from, held = 0, last_spec = 0;
|
|
void *d0, *d1, *d2, *d3;
|
|
void **to_next, **from;
|
|
rte_xmm_t priv01;
|
|
rte_xmm_t priv23;
|
|
int i;
|
|
|
|
/* Speculative next as last next */
|
|
next_index = *(uint16_t *)node->ctx;
|
|
rte_prefetch0(nh);
|
|
|
|
pkts = (struct rte_mbuf **)objs;
|
|
from = objs;
|
|
n_left_from = nb_objs;
|
|
|
|
for (i = 0; i < 4 && i < n_left_from; i++)
|
|
rte_prefetch0(pkts[i]);
|
|
|
|
/* Get stream for the speculated next node */
|
|
to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
|
|
/* Update Ethernet header of pkts */
|
|
while (n_left_from >= 4) {
|
|
if (likely(n_left_from > 7)) {
|
|
/* Prefetch only next-mbuf struct and priv area.
|
|
* Data need not be prefetched as we only write.
|
|
*/
|
|
rte_prefetch0(pkts[4]);
|
|
rte_prefetch0(pkts[5]);
|
|
rte_prefetch0(pkts[6]);
|
|
rte_prefetch0(pkts[7]);
|
|
}
|
|
|
|
mbuf0 = pkts[0];
|
|
mbuf1 = pkts[1];
|
|
mbuf2 = pkts[2];
|
|
mbuf3 = pkts[3];
|
|
|
|
pkts += 4;
|
|
n_left_from -= 4;
|
|
priv01.u64[0] = node_mbuf_priv1(mbuf0)->u;
|
|
priv01.u64[1] = node_mbuf_priv1(mbuf1)->u;
|
|
priv23.u64[0] = node_mbuf_priv1(mbuf2)->u;
|
|
priv23.u64[1] = node_mbuf_priv1(mbuf3)->u;
|
|
|
|
/* Increment checksum by one. */
|
|
priv01.u32[1] += rte_cpu_to_be_16(0x0100);
|
|
priv01.u32[3] += rte_cpu_to_be_16(0x0100);
|
|
priv23.u32[1] += rte_cpu_to_be_16(0x0100);
|
|
priv23.u32[3] += rte_cpu_to_be_16(0x0100);
|
|
|
|
/* Update ttl,cksum rewrite ethernet hdr on mbuf0 */
|
|
d0 = rte_pktmbuf_mtod(mbuf0, void *);
|
|
rte_memcpy(d0, nh[priv01.u16[0]].rewrite_data,
|
|
nh[priv01.u16[0]].rewrite_len);
|
|
|
|
next0 = nh[priv01.u16[0]].tx_node;
|
|
ip0 = (struct rte_ipv4_hdr *)((uint8_t *)d0 +
|
|
sizeof(struct rte_ether_hdr));
|
|
ip0->time_to_live = priv01.u16[1] - 1;
|
|
ip0->hdr_checksum = priv01.u16[2] + priv01.u16[3];
|
|
|
|
/* Update ttl,cksum rewrite ethernet hdr on mbuf1 */
|
|
d1 = rte_pktmbuf_mtod(mbuf1, void *);
|
|
rte_memcpy(d1, nh[priv01.u16[4]].rewrite_data,
|
|
nh[priv01.u16[4]].rewrite_len);
|
|
|
|
next1 = nh[priv01.u16[4]].tx_node;
|
|
ip1 = (struct rte_ipv4_hdr *)((uint8_t *)d1 +
|
|
sizeof(struct rte_ether_hdr));
|
|
ip1->time_to_live = priv01.u16[5] - 1;
|
|
ip1->hdr_checksum = priv01.u16[6] + priv01.u16[7];
|
|
|
|
/* Update ttl,cksum rewrite ethernet hdr on mbuf2 */
|
|
d2 = rte_pktmbuf_mtod(mbuf2, void *);
|
|
rte_memcpy(d2, nh[priv23.u16[0]].rewrite_data,
|
|
nh[priv23.u16[0]].rewrite_len);
|
|
next2 = nh[priv23.u16[0]].tx_node;
|
|
ip2 = (struct rte_ipv4_hdr *)((uint8_t *)d2 +
|
|
sizeof(struct rte_ether_hdr));
|
|
ip2->time_to_live = priv23.u16[1] - 1;
|
|
ip2->hdr_checksum = priv23.u16[2] + priv23.u16[3];
|
|
|
|
/* Update ttl,cksum rewrite ethernet hdr on mbuf3 */
|
|
d3 = rte_pktmbuf_mtod(mbuf3, void *);
|
|
rte_memcpy(d3, nh[priv23.u16[4]].rewrite_data,
|
|
nh[priv23.u16[4]].rewrite_len);
|
|
|
|
next3 = nh[priv23.u16[4]].tx_node;
|
|
ip3 = (struct rte_ipv4_hdr *)((uint8_t *)d3 +
|
|
sizeof(struct rte_ether_hdr));
|
|
ip3->time_to_live = priv23.u16[5] - 1;
|
|
ip3->hdr_checksum = priv23.u16[6] + priv23.u16[7];
|
|
|
|
/* Enqueue four to next node */
|
|
rte_edge_t fix_spec =
|
|
((next_index == next0) && (next0 == next1) &&
|
|
(next1 == next2) && (next2 == next3));
|
|
|
|
if (unlikely(fix_spec == 0)) {
|
|
/* Copy things successfully speculated till now */
|
|
rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
|
|
from += last_spec;
|
|
to_next += last_spec;
|
|
held += last_spec;
|
|
last_spec = 0;
|
|
|
|
/* next0 */
|
|
if (next_index == next0) {
|
|
to_next[0] = from[0];
|
|
to_next++;
|
|
held++;
|
|
} else {
|
|
rte_node_enqueue_x1(graph, node, next0,
|
|
from[0]);
|
|
}
|
|
|
|
/* next1 */
|
|
if (next_index == next1) {
|
|
to_next[0] = from[1];
|
|
to_next++;
|
|
held++;
|
|
} else {
|
|
rte_node_enqueue_x1(graph, node, next1,
|
|
from[1]);
|
|
}
|
|
|
|
/* next2 */
|
|
if (next_index == next2) {
|
|
to_next[0] = from[2];
|
|
to_next++;
|
|
held++;
|
|
} else {
|
|
rte_node_enqueue_x1(graph, node, next2,
|
|
from[2]);
|
|
}
|
|
|
|
/* next3 */
|
|
if (next_index == next3) {
|
|
to_next[0] = from[3];
|
|
to_next++;
|
|
held++;
|
|
} else {
|
|
rte_node_enqueue_x1(graph, node, next3,
|
|
from[3]);
|
|
}
|
|
|
|
from += 4;
|
|
|
|
/* Change speculation if last two are same */
|
|
if ((next_index != next3) && (next2 == next3)) {
|
|
/* Put the current speculated node */
|
|
rte_node_next_stream_put(graph, node,
|
|
next_index, held);
|
|
held = 0;
|
|
|
|
/* Get next speculated stream */
|
|
next_index = next3;
|
|
to_next = rte_node_next_stream_get(
|
|
graph, node, next_index, nb_objs);
|
|
}
|
|
} else {
|
|
last_spec += 4;
|
|
}
|
|
}
|
|
|
|
while (n_left_from > 0) {
|
|
uint16_t chksum;
|
|
|
|
mbuf0 = pkts[0];
|
|
|
|
pkts += 1;
|
|
n_left_from -= 1;
|
|
|
|
d0 = rte_pktmbuf_mtod(mbuf0, void *);
|
|
rte_memcpy(d0, nh[node_mbuf_priv1(mbuf0)->nh].rewrite_data,
|
|
nh[node_mbuf_priv1(mbuf0)->nh].rewrite_len);
|
|
|
|
next0 = nh[node_mbuf_priv1(mbuf0)->nh].tx_node;
|
|
ip0 = (struct rte_ipv4_hdr *)((uint8_t *)d0 +
|
|
sizeof(struct rte_ether_hdr));
|
|
chksum = node_mbuf_priv1(mbuf0)->cksum +
|
|
rte_cpu_to_be_16(0x0100);
|
|
chksum += chksum >= 0xffff;
|
|
ip0->hdr_checksum = chksum;
|
|
ip0->time_to_live = node_mbuf_priv1(mbuf0)->ttl - 1;
|
|
|
|
if (unlikely(next_index ^ next0)) {
|
|
/* Copy things successfully speculated till now */
|
|
rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
|
|
from += last_spec;
|
|
to_next += last_spec;
|
|
held += last_spec;
|
|
last_spec = 0;
|
|
|
|
rte_node_enqueue_x1(graph, node, next0, from[0]);
|
|
from += 1;
|
|
} else {
|
|
last_spec += 1;
|
|
}
|
|
}
|
|
|
|
/* !!! Home run !!! */
|
|
if (likely(last_spec == nb_objs)) {
|
|
rte_node_next_stream_move(graph, node, next_index);
|
|
return nb_objs;
|
|
}
|
|
|
|
held += last_spec;
|
|
rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
|
|
rte_node_next_stream_put(graph, node, next_index, held);
|
|
/* Save the last next used */
|
|
*(uint16_t *)node->ctx = next_index;
|
|
|
|
return nb_objs;
|
|
}
|
|
|
|
static int
|
|
ip4_rewrite_node_init(const struct rte_graph *graph, struct rte_node *node)
|
|
{
|
|
|
|
RTE_SET_USED(graph);
|
|
RTE_SET_USED(node);
|
|
node_dbg("ip4_rewrite", "Initialized ip4_rewrite node initialized");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
ip4_rewrite_set_next(uint16_t port_id, uint16_t next_index)
|
|
{
|
|
if (ip4_rewrite_nm == NULL) {
|
|
ip4_rewrite_nm = rte_zmalloc(
|
|
"ip4_rewrite", sizeof(struct ip4_rewrite_node_main),
|
|
RTE_CACHE_LINE_SIZE);
|
|
if (ip4_rewrite_nm == NULL)
|
|
return -ENOMEM;
|
|
}
|
|
ip4_rewrite_nm->next_index[port_id] = next_index;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
rte_node_ip4_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,
|
|
uint8_t rewrite_len, uint16_t dst_port)
|
|
{
|
|
struct ip4_rewrite_nh_header *nh;
|
|
|
|
if (next_hop >= RTE_GRAPH_IP4_REWRITE_MAX_NH)
|
|
return -EINVAL;
|
|
|
|
if (rewrite_len > RTE_GRAPH_IP4_REWRITE_MAX_LEN)
|
|
return -EINVAL;
|
|
|
|
if (ip4_rewrite_nm == NULL) {
|
|
ip4_rewrite_nm = rte_zmalloc(
|
|
"ip4_rewrite", sizeof(struct ip4_rewrite_node_main),
|
|
RTE_CACHE_LINE_SIZE);
|
|
if (ip4_rewrite_nm == NULL)
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Check if dst port doesn't exist as edge */
|
|
if (!ip4_rewrite_nm->next_index[dst_port])
|
|
return -EINVAL;
|
|
|
|
/* Update next hop */
|
|
nh = &ip4_rewrite_nm->nh[next_hop];
|
|
|
|
memcpy(nh->rewrite_data, rewrite_data, rewrite_len);
|
|
nh->tx_node = ip4_rewrite_nm->next_index[dst_port];
|
|
nh->rewrite_len = rewrite_len;
|
|
nh->enabled = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct rte_node_register ip4_rewrite_node = {
|
|
.process = ip4_rewrite_node_process,
|
|
.name = "ip4_rewrite",
|
|
/* Default edge i.e '0' is pkt drop */
|
|
.nb_edges = 1,
|
|
.next_nodes = {
|
|
[0] = "pkt_drop",
|
|
},
|
|
.init = ip4_rewrite_node_init,
|
|
};
|
|
|
|
struct rte_node_register *
|
|
ip4_rewrite_node_get(void)
|
|
{
|
|
return &ip4_rewrite_node;
|
|
}
|
|
|
|
RTE_NODE_REGISTER(ip4_rewrite_node);
|