Anand B Jyoti 50c644fc1f examples/ip_pipeline: check VLAN and MPLS parameters
This commit add to CLI command check for the following errors
1. SVLAN and CVLAN IDs greater than 12 bits
2. MPLS ID greater than 20 bits
3. max number of supported MPLS labels to avoid array overflow

It prevents running CLI commands with invalid parameters.

Signed-off-by: Anand B Jyoti <anand.b.jyoti@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
2017-01-17 18:37:41 +01:00

1643 lines
37 KiB
C

/*-
* BSD LICENSE
*
* Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cmdline_parse.h>
#include <cmdline_parse_num.h>
#include <cmdline_parse_string.h>
#include "app.h"
#include "pipeline_common_fe.h"
#include "pipeline_routing.h"
#include "parser.h"
struct app_pipeline_routing_route {
struct pipeline_routing_route_key key;
struct pipeline_routing_route_data data;
void *entry_ptr;
TAILQ_ENTRY(app_pipeline_routing_route) node;
};
struct app_pipeline_routing_arp_entry {
struct pipeline_routing_arp_key key;
struct ether_addr macaddr;
void *entry_ptr;
TAILQ_ENTRY(app_pipeline_routing_arp_entry) node;
};
struct pipeline_routing {
/* Parameters */
struct app_params *app;
uint32_t pipeline_id;
uint32_t n_ports_in;
uint32_t n_ports_out;
struct pipeline_routing_params rp;
/* Links */
uint32_t link_id[PIPELINE_MAX_PORT_OUT];
/* Routes */
TAILQ_HEAD(, app_pipeline_routing_route) routes;
uint32_t n_routes;
uint32_t default_route_present;
uint32_t default_route_port_id;
void *default_route_entry_ptr;
/* ARP entries */
TAILQ_HEAD(, app_pipeline_routing_arp_entry) arp_entries;
uint32_t n_arp_entries;
uint32_t default_arp_entry_present;
uint32_t default_arp_entry_port_id;
void *default_arp_entry_ptr;
};
static int
app_pipeline_routing_find_link(struct pipeline_routing *p,
uint32_t link_id,
uint32_t *port_id)
{
uint32_t i;
for (i = 0; i < p->n_ports_out; i++)
if (p->link_id[i] == link_id) {
*port_id = i;
return 0;
}
return -1;
}
static void
app_pipeline_routing_link_op(__rte_unused struct app_params *app,
uint32_t link_id,
uint32_t up,
void *arg)
{
struct pipeline_routing_route_key key0, key1;
struct pipeline_routing *p = arg;
struct app_link_params *lp;
uint32_t port_id, netmask;
int status;
if (app == NULL)
return;
APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, lp);
if (lp == NULL)
return;
status = app_pipeline_routing_find_link(p,
link_id,
&port_id);
if (status)
return;
netmask = (~0U) << (32 - lp->depth);
/* Local network (directly attached network) */
key0.type = PIPELINE_ROUTING_ROUTE_IPV4;
key0.key.ipv4.ip = lp->ip & netmask;
key0.key.ipv4.depth = lp->depth;
/* Local termination */
key1.type = PIPELINE_ROUTING_ROUTE_IPV4;
key1.key.ipv4.ip = lp->ip;
key1.key.ipv4.depth = 32;
if (up) {
struct pipeline_routing_route_data data0, data1;
/* Local network (directly attached network) */
memset(&data0, 0, sizeof(data0));
data0.flags = PIPELINE_ROUTING_ROUTE_LOCAL |
PIPELINE_ROUTING_ROUTE_ARP;
if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ)
data0.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) {
data0.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
data0.l2.mpls.n_labels = 1;
}
data0.port_id = port_id;
if (p->rp.n_arp_entries)
app_pipeline_routing_add_route(app,
p->pipeline_id,
&key0,
&data0);
/* Local termination */
memset(&data1, 0, sizeof(data1));
data1.flags = PIPELINE_ROUTING_ROUTE_LOCAL |
PIPELINE_ROUTING_ROUTE_ARP;
if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ)
data1.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) {
data1.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
data1.l2.mpls.n_labels = 1;
}
data1.port_id = p->rp.port_local_dest;
app_pipeline_routing_add_route(app,
p->pipeline_id,
&key1,
&data1);
} else {
/* Local network (directly attached network) */
if (p->rp.n_arp_entries)
app_pipeline_routing_delete_route(app,
p->pipeline_id,
&key0);
/* Local termination */
app_pipeline_routing_delete_route(app,
p->pipeline_id,
&key1);
}
}
static int
app_pipeline_routing_set_link_op(
struct app_params *app,
struct pipeline_routing *p)
{
uint32_t port_id;
for (port_id = 0; port_id < p->n_ports_out; port_id++) {
struct app_link_params *link;
uint32_t link_id;
int status;
link = app_pipeline_track_pktq_out_to_link(app,
p->pipeline_id,
port_id);
if (link == NULL)
continue;
link_id = link - app->link_params;
p->link_id[port_id] = link_id;
status = app_link_set_op(app,
link_id,
p->pipeline_id,
app_pipeline_routing_link_op,
(void *) p);
if (status)
return status;
}
return 0;
}
static void *
app_pipeline_routing_init(struct pipeline_params *params,
void *arg)
{
struct app_params *app = (struct app_params *) arg;
struct pipeline_routing *p;
uint32_t pipeline_id, size;
int status;
/* Check input arguments */
if ((params == NULL) ||
(params->n_ports_in == 0) ||
(params->n_ports_out == 0))
return NULL;
APP_PARAM_GET_ID(params, "PIPELINE", pipeline_id);
/* Memory allocation */
size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_routing));
p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
if (p == NULL)
return NULL;
/* Initialization */
p->app = app;
p->pipeline_id = pipeline_id;
p->n_ports_in = params->n_ports_in;
p->n_ports_out = params->n_ports_out;
status = pipeline_routing_parse_args(&p->rp, params);
if (status) {
rte_free(p);
return NULL;
}
TAILQ_INIT(&p->routes);
p->n_routes = 0;
TAILQ_INIT(&p->arp_entries);
p->n_arp_entries = 0;
app_pipeline_routing_set_link_op(app, p);
return p;
}
static int
app_pipeline_routing_post_init(void *pipeline)
{
struct pipeline_routing *p = pipeline;
/* Check input arguments */
if (p == NULL)
return -1;
return app_pipeline_routing_set_macaddr(p->app, p->pipeline_id);
}
static int
app_pipeline_routing_free(void *pipeline)
{
struct pipeline_routing *p = pipeline;
/* Check input arguments */
if (p == NULL)
return -1;
/* Free resources */
while (!TAILQ_EMPTY(&p->routes)) {
struct app_pipeline_routing_route *route;
route = TAILQ_FIRST(&p->routes);
TAILQ_REMOVE(&p->routes, route, node);
rte_free(route);
}
while (!TAILQ_EMPTY(&p->arp_entries)) {
struct app_pipeline_routing_arp_entry *arp_entry;
arp_entry = TAILQ_FIRST(&p->arp_entries);
TAILQ_REMOVE(&p->arp_entries, arp_entry, node);
rte_free(arp_entry);
}
rte_free(p);
return 0;
}
static struct app_pipeline_routing_route *
app_pipeline_routing_find_route(struct pipeline_routing *p,
const struct pipeline_routing_route_key *key)
{
struct app_pipeline_routing_route *it, *found;
found = NULL;
TAILQ_FOREACH(it, &p->routes, node) {
if ((key->type == it->key.type) &&
(key->key.ipv4.ip == it->key.key.ipv4.ip) &&
(key->key.ipv4.depth == it->key.key.ipv4.depth)) {
found = it;
break;
}
}
return found;
}
static struct app_pipeline_routing_arp_entry *
app_pipeline_routing_find_arp_entry(struct pipeline_routing *p,
const struct pipeline_routing_arp_key *key)
{
struct app_pipeline_routing_arp_entry *it, *found;
found = NULL;
TAILQ_FOREACH(it, &p->arp_entries, node) {
if ((key->type == it->key.type) &&
(key->key.ipv4.port_id == it->key.key.ipv4.port_id) &&
(key->key.ipv4.ip == it->key.key.ipv4.ip)) {
found = it;
break;
}
}
return found;
}
static void
print_route(const struct app_pipeline_routing_route *route)
{
if (route->key.type == PIPELINE_ROUTING_ROUTE_IPV4) {
const struct pipeline_routing_route_key_ipv4 *key =
&route->key.key.ipv4;
printf("IP Prefix = %" PRIu32 ".%" PRIu32
".%" PRIu32 ".%" PRIu32 "/%" PRIu32
" => (Port = %" PRIu32,
(key->ip >> 24) & 0xFF,
(key->ip >> 16) & 0xFF,
(key->ip >> 8) & 0xFF,
key->ip & 0xFF,
key->depth,
route->data.port_id);
if (route->data.flags & PIPELINE_ROUTING_ROUTE_LOCAL)
printf(", Local");
else if (route->data.flags & PIPELINE_ROUTING_ROUTE_ARP)
printf(
", Next Hop IP = %" PRIu32 ".%" PRIu32
".%" PRIu32 ".%" PRIu32,
(route->data.ethernet.ip >> 24) & 0xFF,
(route->data.ethernet.ip >> 16) & 0xFF,
(route->data.ethernet.ip >> 8) & 0xFF,
route->data.ethernet.ip & 0xFF);
else
printf(
", Next Hop HWaddress = %02" PRIx32
":%02" PRIx32 ":%02" PRIx32
":%02" PRIx32 ":%02" PRIx32
":%02" PRIx32,
route->data.ethernet.macaddr.addr_bytes[0],
route->data.ethernet.macaddr.addr_bytes[1],
route->data.ethernet.macaddr.addr_bytes[2],
route->data.ethernet.macaddr.addr_bytes[3],
route->data.ethernet.macaddr.addr_bytes[4],
route->data.ethernet.macaddr.addr_bytes[5]);
if (route->data.flags & PIPELINE_ROUTING_ROUTE_QINQ)
printf(", QinQ SVLAN = %" PRIu32 " CVLAN = %" PRIu32,
route->data.l2.qinq.svlan,
route->data.l2.qinq.cvlan);
if (route->data.flags & PIPELINE_ROUTING_ROUTE_MPLS) {
uint32_t i;
printf(", MPLS labels");
for (i = 0; i < route->data.l2.mpls.n_labels; i++)
printf(" %" PRIu32,
route->data.l2.mpls.labels[i]);
}
printf(")\n");
}
}
static void
print_arp_entry(const struct app_pipeline_routing_arp_entry *entry)
{
printf("(Port = %" PRIu32 ", IP = %" PRIu32 ".%" PRIu32
".%" PRIu32 ".%" PRIu32
") => HWaddress = %02" PRIx32 ":%02" PRIx32 ":%02" PRIx32
":%02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 "\n",
entry->key.key.ipv4.port_id,
(entry->key.key.ipv4.ip >> 24) & 0xFF,
(entry->key.key.ipv4.ip >> 16) & 0xFF,
(entry->key.key.ipv4.ip >> 8) & 0xFF,
entry->key.key.ipv4.ip & 0xFF,
entry->macaddr.addr_bytes[0],
entry->macaddr.addr_bytes[1],
entry->macaddr.addr_bytes[2],
entry->macaddr.addr_bytes[3],
entry->macaddr.addr_bytes[4],
entry->macaddr.addr_bytes[5]);
}
static int
app_pipeline_routing_route_ls(struct app_params *app, uint32_t pipeline_id)
{
struct pipeline_routing *p;
struct app_pipeline_routing_route *it;
p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
if (p == NULL)
return -EINVAL;
TAILQ_FOREACH(it, &p->routes, node)
print_route(it);
if (p->default_route_present)
printf("Default route: port %" PRIu32 " (entry ptr = %p)\n",
p->default_route_port_id,
p->default_route_entry_ptr);
else
printf("Default: DROP\n");
return 0;
}
int
app_pipeline_routing_add_route(struct app_params *app,
uint32_t pipeline_id,
struct pipeline_routing_route_key *key,
struct pipeline_routing_route_data *data)
{
struct pipeline_routing *p;
struct pipeline_routing_route_add_msg_req *req;
struct pipeline_routing_route_add_msg_rsp *rsp;
struct app_pipeline_routing_route *entry;
int new_entry;
/* Check input arguments */
if ((app == NULL) ||
(key == NULL) ||
(data == NULL))
return -1;
p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
if (p == NULL)
return -1;
switch (key->type) {
case PIPELINE_ROUTING_ROUTE_IPV4:
{
uint32_t depth = key->key.ipv4.depth;
uint32_t netmask;
/* key */
if ((depth == 0) || (depth > 32))
return -1;
netmask = (~0U) << (32 - depth);
key->key.ipv4.ip &= netmask;
/* data */
if (data->port_id >= p->n_ports_out)
return -1;
/* Valid range of VLAN tags 12 bits */
if (data->flags & PIPELINE_ROUTING_ROUTE_QINQ)
if ((data->l2.qinq.svlan & 0xF000) ||
(data->l2.qinq.cvlan & 0xF000))
return -1;
/* Max number of MPLS labels supported */
if (data->flags & PIPELINE_ROUTING_ROUTE_MPLS) {
uint32_t i;
if (data->l2.mpls.n_labels >
PIPELINE_ROUTING_MPLS_LABELS_MAX)
return -1;
/* Max MPLS label value 20 bits */
for (i = 0; i < data->l2.mpls.n_labels; i++)
if (data->l2.mpls.labels[i] & 0xFFF00000)
return -1;
}
}
break;
default:
return -1;
}
/* Find existing rule or allocate new rule */
entry = app_pipeline_routing_find_route(p, key);
new_entry = (entry == NULL);
if (entry == NULL) {
entry = rte_malloc(NULL, sizeof(*entry), RTE_CACHE_LINE_SIZE);
if (entry == NULL)
return -1;
}
/* Allocate and write request */
req = app_msg_alloc(app);
if (req == NULL) {
if (new_entry)
rte_free(entry);
return -1;
}
req->type = PIPELINE_MSG_REQ_CUSTOM;
req->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_ADD;
memcpy(&req->key, key, sizeof(*key));
memcpy(&req->data, data, sizeof(*data));
rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
if (rsp == NULL) {
if (new_entry)
rte_free(entry);
return -1;
}
/* Read response and write entry */
if (rsp->status ||
(rsp->entry_ptr == NULL) ||
((new_entry == 0) && (rsp->key_found == 0)) ||
((new_entry == 1) && (rsp->key_found == 1))) {
app_msg_free(app, rsp);
if (new_entry)
rte_free(entry);
return -1;
}
memcpy(&entry->key, key, sizeof(*key));
memcpy(&entry->data, data, sizeof(*data));
entry->entry_ptr = rsp->entry_ptr;
/* Commit entry */
if (new_entry) {
TAILQ_INSERT_TAIL(&p->routes, entry, node);
p->n_routes++;
}
/* Message buffer free */
app_msg_free(app, rsp);
return 0;
}
int
app_pipeline_routing_delete_route(struct app_params *app,
uint32_t pipeline_id,
struct pipeline_routing_route_key *key)
{
struct pipeline_routing *p;
struct pipeline_routing_route_delete_msg_req *req;
struct pipeline_routing_route_delete_msg_rsp *rsp;
struct app_pipeline_routing_route *entry;
/* Check input arguments */
if ((app == NULL) ||
(key == NULL))
return -1;
p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
if (p == NULL)
return -1;
switch (key->type) {
case PIPELINE_ROUTING_ROUTE_IPV4:
{
uint32_t depth = key->key.ipv4.depth;
uint32_t netmask;
/* key */
if ((depth == 0) || (depth > 32))
return -1;
netmask = (~0U) << (32 - depth);
key->key.ipv4.ip &= netmask;
}
break;
default:
return -1;
}
/* Find rule */
entry = app_pipeline_routing_find_route(p, key);
if (entry == NULL)
return 0;
/* Allocate and write request */
req = app_msg_alloc(app);
if (req == NULL)
return -1;
req->type = PIPELINE_MSG_REQ_CUSTOM;
req->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_DEL;
memcpy(&req->key, key, sizeof(*key));
rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
if (rsp == NULL)
return -1;
/* Read response */
if (rsp->status || !rsp->key_found) {
app_msg_free(app, rsp);
return -1;
}
/* Remove route */
TAILQ_REMOVE(&p->routes, entry, node);
p->n_routes--;
rte_free(entry);
/* Free response */
app_msg_free(app, rsp);
return 0;
}
int
app_pipeline_routing_add_default_route(struct app_params *app,
uint32_t pipeline_id,
uint32_t port_id)
{
struct pipeline_routing *p;
struct pipeline_routing_route_add_default_msg_req *req;
struct pipeline_routing_route_add_default_msg_rsp *rsp;
/* Check input arguments */
if (app == NULL)
return -1;
p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
if (p == NULL)
return -1;
if (port_id >= p->n_ports_out)
return -1;
/* Allocate and write request */
req = app_msg_alloc(app);
if (req == NULL)
return -1;
req->type = PIPELINE_MSG_REQ_CUSTOM;
req->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_ADD_DEFAULT;
req->port_id = port_id;
/* Send request and wait for response */
rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
if (rsp == NULL)
return -1;
/* Read response and write route */
if (rsp->status || (rsp->entry_ptr == NULL)) {
app_msg_free(app, rsp);
return -1;
}
p->default_route_port_id = port_id;
p->default_route_entry_ptr = rsp->entry_ptr;
/* Commit route */
p->default_route_present = 1;
/* Free response */
app_msg_free(app, rsp);
return 0;
}
int
app_pipeline_routing_delete_default_route(struct app_params *app,
uint32_t pipeline_id)
{
struct pipeline_routing *p;
struct pipeline_routing_arp_delete_default_msg_req *req;
struct pipeline_routing_arp_delete_default_msg_rsp *rsp;
/* Check input arguments */
if (app == NULL)
return -1;
p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
if (p == NULL)
return -1;
/* Allocate and write request */
req = app_msg_alloc(app);
if (req == NULL)
return -1;
req->type = PIPELINE_MSG_REQ_CUSTOM;
req->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_DEL_DEFAULT;
/* Send request and wait for response */
rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
if (rsp == NULL)
return -1;
/* Read response and write route */
if (rsp->status) {
app_msg_free(app, rsp);
return -1;
}
/* Commit route */
p->default_route_present = 0;
/* Free response */
app_msg_free(app, rsp);
return 0;
}
static int
app_pipeline_routing_arp_ls(struct app_params *app, uint32_t pipeline_id)
{
struct pipeline_routing *p;
struct app_pipeline_routing_arp_entry *it;
p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
if (p == NULL)
return -EINVAL;
TAILQ_FOREACH(it, &p->arp_entries, node)
print_arp_entry(it);
if (p->default_arp_entry_present)
printf("Default entry: port %" PRIu32 " (entry ptr = %p)\n",
p->default_arp_entry_port_id,
p->default_arp_entry_ptr);
else
printf("Default: DROP\n");
return 0;
}
int
app_pipeline_routing_add_arp_entry(struct app_params *app, uint32_t pipeline_id,
struct pipeline_routing_arp_key *key,
struct ether_addr *macaddr)
{
struct pipeline_routing *p;
struct pipeline_routing_arp_add_msg_req *req;
struct pipeline_routing_arp_add_msg_rsp *rsp;
struct app_pipeline_routing_arp_entry *entry;
int new_entry;
/* Check input arguments */
if ((app == NULL) ||
(key == NULL) ||
(macaddr == NULL))
return -1;
p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
if (p == NULL)
return -1;
switch (key->type) {
case PIPELINE_ROUTING_ARP_IPV4:
{
uint32_t port_id = key->key.ipv4.port_id;
/* key */
if (port_id >= p->n_ports_out)
return -1;
}
break;
default:
return -1;
}
/* Find existing entry or allocate new */
entry = app_pipeline_routing_find_arp_entry(p, key);
new_entry = (entry == NULL);
if (entry == NULL) {
entry = rte_malloc(NULL, sizeof(*entry), RTE_CACHE_LINE_SIZE);
if (entry == NULL)
return -1;
}
/* Message buffer allocation */
req = app_msg_alloc(app);
if (req == NULL) {
if (new_entry)
rte_free(entry);
return -1;
}
req->type = PIPELINE_MSG_REQ_CUSTOM;
req->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_ADD;
memcpy(&req->key, key, sizeof(*key));
ether_addr_copy(macaddr, &req->macaddr);
/* Send request and wait for response */
rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
if (rsp == NULL) {
if (new_entry)
rte_free(entry);
return -1;
}
/* Read response and write entry */
if (rsp->status ||
(rsp->entry_ptr == NULL) ||
((new_entry == 0) && (rsp->key_found == 0)) ||
((new_entry == 1) && (rsp->key_found == 1))) {
app_msg_free(app, rsp);
if (new_entry)
rte_free(entry);
return -1;
}
memcpy(&entry->key, key, sizeof(*key));
ether_addr_copy(macaddr, &entry->macaddr);
entry->entry_ptr = rsp->entry_ptr;
/* Commit entry */
if (new_entry) {
TAILQ_INSERT_TAIL(&p->arp_entries, entry, node);
p->n_arp_entries++;
}
/* Message buffer free */
app_msg_free(app, rsp);
return 0;
}
int
app_pipeline_routing_delete_arp_entry(struct app_params *app,
uint32_t pipeline_id,
struct pipeline_routing_arp_key *key)
{
struct pipeline_routing *p;
struct pipeline_routing_arp_delete_msg_req *req;
struct pipeline_routing_arp_delete_msg_rsp *rsp;
struct app_pipeline_routing_arp_entry *entry;
/* Check input arguments */
if ((app == NULL) ||
(key == NULL))
return -1;
p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
if (p == NULL)
return -EINVAL;
switch (key->type) {
case PIPELINE_ROUTING_ARP_IPV4:
{
uint32_t port_id = key->key.ipv4.port_id;
/* key */
if (port_id >= p->n_ports_out)
return -1;
}
break;
default:
return -1;
}
/* Find rule */
entry = app_pipeline_routing_find_arp_entry(p, key);
if (entry == NULL)
return 0;
/* Allocate and write request */
req = app_msg_alloc(app);
if (req == NULL)
return -1;
req->type = PIPELINE_MSG_REQ_CUSTOM;
req->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_DEL;
memcpy(&req->key, key, sizeof(*key));
rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
if (rsp == NULL)
return -1;
/* Read response */
if (rsp->status || !rsp->key_found) {
app_msg_free(app, rsp);
return -1;
}
/* Remove entry */
TAILQ_REMOVE(&p->arp_entries, entry, node);
p->n_arp_entries--;
rte_free(entry);
/* Free response */
app_msg_free(app, rsp);
return 0;
}
int
app_pipeline_routing_add_default_arp_entry(struct app_params *app,
uint32_t pipeline_id,
uint32_t port_id)
{
struct pipeline_routing *p;
struct pipeline_routing_arp_add_default_msg_req *req;
struct pipeline_routing_arp_add_default_msg_rsp *rsp;
/* Check input arguments */
if (app == NULL)
return -1;
p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
if (p == NULL)
return -1;
if (port_id >= p->n_ports_out)
return -1;
/* Allocate and write request */
req = app_msg_alloc(app);
if (req == NULL)
return -1;
req->type = PIPELINE_MSG_REQ_CUSTOM;
req->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_ADD_DEFAULT;
req->port_id = port_id;
/* Send request and wait for response */
rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
if (rsp == NULL)
return -1;
/* Read response and write entry */
if (rsp->status || rsp->entry_ptr == NULL) {
app_msg_free(app, rsp);
return -1;
}
p->default_arp_entry_port_id = port_id;
p->default_arp_entry_ptr = rsp->entry_ptr;
/* Commit entry */
p->default_arp_entry_present = 1;
/* Free response */
app_msg_free(app, rsp);
return 0;
}
int
app_pipeline_routing_delete_default_arp_entry(struct app_params *app,
uint32_t pipeline_id)
{
struct pipeline_routing *p;
struct pipeline_routing_arp_delete_default_msg_req *req;
struct pipeline_routing_arp_delete_default_msg_rsp *rsp;
/* Check input arguments */
if (app == NULL)
return -1;
p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
if (p == NULL)
return -EINVAL;
/* Allocate and write request */
req = app_msg_alloc(app);
if (req == NULL)
return -ENOMEM;
req->type = PIPELINE_MSG_REQ_CUSTOM;
req->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_DEL_DEFAULT;
/* Send request and wait for response */
rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
if (rsp == NULL)
return -ETIMEDOUT;
/* Read response and write entry */
if (rsp->status) {
app_msg_free(app, rsp);
return rsp->status;
}
/* Commit entry */
p->default_arp_entry_present = 0;
/* Free response */
app_msg_free(app, rsp);
return 0;
}
int
app_pipeline_routing_set_macaddr(struct app_params *app,
uint32_t pipeline_id)
{
struct app_pipeline_params *p;
struct pipeline_routing_set_macaddr_msg_req *req;
struct pipeline_routing_set_macaddr_msg_rsp *rsp;
uint32_t port_id;
/* Check input arguments */
if (app == NULL)
return -EINVAL;
APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
if (p == NULL)
return -EINVAL;
/* Allocate and write request */
req = app_msg_alloc(app);
if (req == NULL)
return -ENOMEM;
req->type = PIPELINE_MSG_REQ_CUSTOM;
req->subtype = PIPELINE_ROUTING_MSG_REQ_SET_MACADDR;
memset(req->macaddr, 0, sizeof(req->macaddr));
for (port_id = 0; port_id < p->n_pktq_out; port_id++) {
struct app_link_params *link;
link = app_pipeline_track_pktq_out_to_link(app,
pipeline_id,
port_id);
if (link)
req->macaddr[port_id] = link->mac_addr;
}
/* Send request and wait for response */
rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
if (rsp == NULL)
return -ETIMEDOUT;
/* Read response and write entry */
if (rsp->status) {
app_msg_free(app, rsp);
return rsp->status;
}
/* Free response */
app_msg_free(app, rsp);
return 0;
}
/*
* route
*
* route add (ARP = ON/OFF, MPLS = ON/OFF, QINQ = ON/OFF):
* p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr>
* p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr>
* p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> qinq <svlan> <cvlan>
* p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> qinq <svlan> <cvlan>
* p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> mpls <mpls labels>
* p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> mpls <mpls labels>
*
* route add default:
* p <pipelineid> route add default <portid>
*
* route del:
* p <pipelineid> route del <ipaddr> <depth>
*
* route del default:
* p <pipelineid> route del default
*
* route ls:
* p <pipelineid> route ls
*/
struct cmd_route_result {
cmdline_fixed_string_t p_string;
uint32_t p;
cmdline_fixed_string_t route_string;
cmdline_multi_string_t multi_string;
};
static void
cmd_route_parsed(
void *parsed_result,
__rte_unused struct cmdline *cl,
void *data)
{
struct cmd_route_result *params = parsed_result;
struct app_params *app = data;
char *tokens[16];
uint32_t n_tokens = RTE_DIM(tokens);
int status;
status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
if (status != 0) {
printf(CMD_MSG_TOO_MANY_ARGS, "route");
return;
}
/* route add */
if ((n_tokens >= 2) &&
(strcmp(tokens[0], "add") == 0) &&
strcmp(tokens[1], "default")) {
struct pipeline_routing_route_key key;
struct pipeline_routing_route_data route_data;
struct in_addr ipv4, nh_ipv4;
struct ether_addr mac_addr;
uint32_t depth, port_id, svlan, cvlan, i;
uint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
uint32_t n_labels = RTE_DIM(mpls_labels);
memset(&key, 0, sizeof(key));
memset(&route_data, 0, sizeof(route_data));
if (n_tokens < 7) {
printf(CMD_MSG_NOT_ENOUGH_ARGS, "route add");
return;
}
if (parse_ipv4_addr(tokens[1], &ipv4)) {
printf(CMD_MSG_INVALID_ARG, "ipaddr");
return;
}
if (parser_read_uint32(&depth, tokens[2])) {
printf(CMD_MSG_INVALID_ARG, "depth");
return;
}
if (strcmp(tokens[3], "port")) {
printf(CMD_MSG_ARG_NOT_FOUND, "port");
return;
}
if (parser_read_uint32(&port_id, tokens[4])) {
printf(CMD_MSG_INVALID_ARG, "portid");
return;
}
if (strcmp(tokens[5], "ether")) {
printf(CMD_MSG_ARG_NOT_FOUND, "ether");
return;
}
if (parse_mac_addr(tokens[6], &mac_addr)) {
if (parse_ipv4_addr(tokens[6], &nh_ipv4)) {
printf(CMD_MSG_INVALID_ARG, "nhmacaddr or nhipaddr");
return;
}
route_data.flags |= PIPELINE_ROUTING_ROUTE_ARP;
}
if (n_tokens > 7) {
if (strcmp(tokens[7], "mpls") == 0) {
if (n_tokens != 9) {
printf(CMD_MSG_MISMATCH_ARGS, "route add mpls");
return;
}
if (parse_mpls_labels(tokens[8], mpls_labels, &n_labels)) {
printf(CMD_MSG_INVALID_ARG, "mpls labels");
return;
}
route_data.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
} else if (strcmp(tokens[7], "qinq") == 0) {
if (n_tokens != 10) {
printf(CMD_MSG_MISMATCH_ARGS, "route add qinq");
return;
}
if (parser_read_uint32(&svlan, tokens[8])) {
printf(CMD_MSG_INVALID_ARG, "svlan");
return;
}
if (parser_read_uint32(&cvlan, tokens[9])) {
printf(CMD_MSG_INVALID_ARG, "cvlan");
return;
}
route_data.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
} else {
printf(CMD_MSG_ARG_NOT_FOUND, "mpls or qinq");
return;
}
}
switch (route_data.flags) {
case 0:
route_data.port_id = port_id;
route_data.ethernet.macaddr = mac_addr;
break;
case PIPELINE_ROUTING_ROUTE_ARP:
route_data.port_id = port_id;
route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
break;
case PIPELINE_ROUTING_ROUTE_MPLS:
route_data.port_id = port_id;
route_data.ethernet.macaddr = mac_addr;
for (i = 0; i < n_labels; i++)
route_data.l2.mpls.labels[i] = mpls_labels[i];
route_data.l2.mpls.n_labels = n_labels;
break;
case PIPELINE_ROUTING_ROUTE_MPLS | PIPELINE_ROUTING_ROUTE_ARP:
route_data.port_id = port_id;
route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
for (i = 0; i < n_labels; i++)
route_data.l2.mpls.labels[i] = mpls_labels[i];
route_data.l2.mpls.n_labels = n_labels;
break;
case PIPELINE_ROUTING_ROUTE_QINQ:
route_data.port_id = port_id;
route_data.ethernet.macaddr = mac_addr;
route_data.l2.qinq.svlan = svlan;
route_data.l2.qinq.cvlan = cvlan;
break;
case PIPELINE_ROUTING_ROUTE_QINQ | PIPELINE_ROUTING_ROUTE_ARP:
default:
route_data.port_id = port_id;
route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
route_data.l2.qinq.svlan = svlan;
route_data.l2.qinq.cvlan = cvlan;
break;
}
key.type = PIPELINE_ROUTING_ROUTE_IPV4;
key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
key.key.ipv4.depth = depth;
status = app_pipeline_routing_add_route(app,
params->p,
&key,
&route_data);
if (status != 0)
printf(CMD_MSG_FAIL, "route add");
return;
} /* route add */
/* route add default */
if ((n_tokens >= 2) &&
(strcmp(tokens[0], "add") == 0) &&
(strcmp(tokens[1], "default") == 0)) {
uint32_t port_id;
if (n_tokens != 3) {
printf(CMD_MSG_MISMATCH_ARGS, "route add default");
return;
}
if (parser_read_uint32(&port_id, tokens[2])) {
printf(CMD_MSG_INVALID_ARG, "portid");
return;
}
status = app_pipeline_routing_add_default_route(app,
params->p,
port_id);
if (status != 0)
printf(CMD_MSG_FAIL, "route add default");
return;
} /* route add default */
/* route del*/
if ((n_tokens >= 2) &&
(strcmp(tokens[0], "del") == 0) &&
strcmp(tokens[1], "default")) {
struct pipeline_routing_route_key key;
struct in_addr ipv4;
uint32_t depth;
memset(&key, 0, sizeof(key));
if (n_tokens != 3) {
printf(CMD_MSG_MISMATCH_ARGS, "route del");
return;
}
if (parse_ipv4_addr(tokens[1], &ipv4)) {
printf(CMD_MSG_INVALID_ARG, "ipaddr");
return;
}
if (parser_read_uint32(&depth, tokens[2])) {
printf(CMD_MSG_INVALID_ARG, "depth");
return;
}
key.type = PIPELINE_ROUTING_ROUTE_IPV4;
key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
key.key.ipv4.depth = depth;
status = app_pipeline_routing_delete_route(app, params->p, &key);
if (status != 0)
printf(CMD_MSG_FAIL, "route del");
return;
} /* route del */
/* route del default */
if ((n_tokens >= 2) &&
(strcmp(tokens[0], "del") == 0) &&
(strcmp(tokens[1], "default") == 0)) {
if (n_tokens != 2) {
printf(CMD_MSG_MISMATCH_ARGS, "route del default");
return;
}
status = app_pipeline_routing_delete_default_route(app,
params->p);
if (status != 0)
printf(CMD_MSG_FAIL, "route del default");
return;
} /* route del default */
/* route ls */
if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
if (n_tokens != 1) {
printf(CMD_MSG_MISMATCH_ARGS, "route ls");
return;
}
status = app_pipeline_routing_route_ls(app, params->p);
if (status != 0)
printf(CMD_MSG_FAIL, "route ls");
return;
} /* route ls */
printf(CMD_MSG_MISMATCH_ARGS, "route");
}
static cmdline_parse_token_string_t cmd_route_p_string =
TOKEN_STRING_INITIALIZER(struct cmd_route_result, p_string, "p");
static cmdline_parse_token_num_t cmd_route_p =
TOKEN_NUM_INITIALIZER(struct cmd_route_result, p, UINT32);
static cmdline_parse_token_string_t cmd_route_route_string =
TOKEN_STRING_INITIALIZER(struct cmd_route_result, route_string, "route");
static cmdline_parse_token_string_t cmd_route_multi_string =
TOKEN_STRING_INITIALIZER(struct cmd_route_result, multi_string,
TOKEN_STRING_MULTI);
static cmdline_parse_inst_t cmd_route = {
.f = cmd_route_parsed,
.data = NULL,
.help_str = "route add / add default / del / del default / ls",
.tokens = {
(void *)&cmd_route_p_string,
(void *)&cmd_route_p,
(void *)&cmd_route_route_string,
(void *)&cmd_route_multi_string,
NULL,
},
};
/*
* arp
*
* arp add:
* p <pipelineid> arp add <portid> <ipaddr> <macaddr>
*
* arp add default:
* p <pipelineid> arp add default <portid>
*
* arp del:
* p <pipelineid> arp del <portid> <ipaddr>
*
* arp del default:
* p <pipelineid> arp del default
*
* arp ls:
* p <pipelineid> arp ls
*/
struct cmd_arp_result {
cmdline_fixed_string_t p_string;
uint32_t p;
cmdline_fixed_string_t arp_string;
cmdline_multi_string_t multi_string;
};
static void
cmd_arp_parsed(
void *parsed_result,
__rte_unused struct cmdline *cl,
void *data)
{
struct cmd_arp_result *params = parsed_result;
struct app_params *app = data;
char *tokens[16];
uint32_t n_tokens = RTE_DIM(tokens);
int status;
status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
if (status != 0) {
printf(CMD_MSG_TOO_MANY_ARGS, "arp");
return;
}
/* arp add */
if ((n_tokens >= 2) &&
(strcmp(tokens[0], "add") == 0) &&
strcmp(tokens[1], "default")) {
struct pipeline_routing_arp_key key;
struct in_addr ipv4;
struct ether_addr mac_addr;
uint32_t port_id;
memset(&key, 0, sizeof(key));
if (n_tokens != 4) {
printf(CMD_MSG_MISMATCH_ARGS, "arp add");
return;
}
if (parser_read_uint32(&port_id, tokens[1])) {
printf(CMD_MSG_INVALID_ARG, "portid");
return;
}
if (parse_ipv4_addr(tokens[2], &ipv4)) {
printf(CMD_MSG_INVALID_ARG, "ipaddr");
return;
}
if (parse_mac_addr(tokens[3], &mac_addr)) {
printf(CMD_MSG_INVALID_ARG, "macaddr");
return;
}
key.type = PIPELINE_ROUTING_ARP_IPV4;
key.key.ipv4.port_id = port_id;
key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
status = app_pipeline_routing_add_arp_entry(app,
params->p,
&key,
&mac_addr);
if (status != 0)
printf(CMD_MSG_FAIL, "arp add");
return;
} /* arp add */
/* arp add default */
if ((n_tokens >= 2) &&
(strcmp(tokens[0], "add") == 0) &&
(strcmp(tokens[1], "default") == 0)) {
uint32_t port_id;
if (n_tokens != 3) {
printf(CMD_MSG_MISMATCH_ARGS, "arp add default");
return;
}
if (parser_read_uint32(&port_id, tokens[2])) {
printf(CMD_MSG_INVALID_ARG, "portid");
return;
}
status = app_pipeline_routing_add_default_arp_entry(app,
params->p,
port_id);
if (status != 0)
printf(CMD_MSG_FAIL, "arp add default");
return;
} /* arp add default */
/* arp del*/
if ((n_tokens >= 2) &&
(strcmp(tokens[0], "del") == 0) &&
strcmp(tokens[1], "default")) {
struct pipeline_routing_arp_key key;
struct in_addr ipv4;
uint32_t port_id;
memset(&key, 0, sizeof(key));
if (n_tokens != 3) {
printf(CMD_MSG_MISMATCH_ARGS, "arp del");
return;
}
if (parser_read_uint32(&port_id, tokens[1])) {
printf(CMD_MSG_INVALID_ARG, "portid");
return;
}
if (parse_ipv4_addr(tokens[2], &ipv4)) {
printf(CMD_MSG_INVALID_ARG, "ipaddr");
return;
}
key.type = PIPELINE_ROUTING_ARP_IPV4;
key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
key.key.ipv4.port_id = port_id;
status = app_pipeline_routing_delete_arp_entry(app,
params->p,
&key);
if (status != 0)
printf(CMD_MSG_FAIL, "arp del");
return;
} /* arp del */
/* arp del default */
if ((n_tokens >= 2) &&
(strcmp(tokens[0], "del") == 0) &&
(strcmp(tokens[1], "default") == 0)) {
if (n_tokens != 2) {
printf(CMD_MSG_MISMATCH_ARGS, "arp del default");
return;
}
status = app_pipeline_routing_delete_default_arp_entry(app,
params->p);
if (status != 0)
printf(CMD_MSG_FAIL, "arp del default");
return;
} /* arp del default */
/* arp ls */
if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
if (n_tokens != 1) {
printf(CMD_MSG_MISMATCH_ARGS, "arp ls");
return;
}
status = app_pipeline_routing_arp_ls(app, params->p);
if (status != 0)
printf(CMD_MSG_FAIL, "arp ls");
return;
} /* arp ls */
printf(CMD_MSG_FAIL, "arp");
}
static cmdline_parse_token_string_t cmd_arp_p_string =
TOKEN_STRING_INITIALIZER(struct cmd_arp_result, p_string, "p");
static cmdline_parse_token_num_t cmd_arp_p =
TOKEN_NUM_INITIALIZER(struct cmd_arp_result, p, UINT32);
static cmdline_parse_token_string_t cmd_arp_arp_string =
TOKEN_STRING_INITIALIZER(struct cmd_arp_result, arp_string, "arp");
static cmdline_parse_token_string_t cmd_arp_multi_string =
TOKEN_STRING_INITIALIZER(struct cmd_arp_result, multi_string,
TOKEN_STRING_MULTI);
static cmdline_parse_inst_t cmd_arp = {
.f = cmd_arp_parsed,
.data = NULL,
.help_str = "arp add / add default / del / del default / ls",
.tokens = {
(void *)&cmd_arp_p_string,
(void *)&cmd_arp_p,
(void *)&cmd_arp_arp_string,
(void *)&cmd_arp_multi_string,
NULL,
},
};
static cmdline_parse_ctx_t pipeline_cmds[] = {
(cmdline_parse_inst_t *)&cmd_route,
(cmdline_parse_inst_t *)&cmd_arp,
NULL,
};
static struct pipeline_fe_ops pipeline_routing_fe_ops = {
.f_init = app_pipeline_routing_init,
.f_post_init = app_pipeline_routing_post_init,
.f_free = app_pipeline_routing_free,
.f_track = app_pipeline_track_default,
.cmds = pipeline_cmds,
};
struct pipeline_type pipeline_routing = {
.name = "ROUTING",
.be_ops = &pipeline_routing_be_ops,
.fe_ops = &pipeline_routing_fe_ops,
};