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;
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 *
-pipeline_routing_init(struct pipeline_params *params,
- __rte_unused void *arg)
+app_pipeline_routing_init(struct pipeline_params *params,
+ void *arg)
{
+ struct app_params *app = (struct app_params *) arg;
struct pipeline_routing *p;
- uint32_t size;
+ uint32_t pipeline_id, size;
+ int status;
/* Check input arguments */
if ((params == NULL) ||
(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);
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)
{
key->depth,
route->data.port_id);
- if (route->data.flags & PIPELINE_ROUTING_ROUTE_ARP)
+ 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,
/* 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;
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
*
};
static struct pipeline_fe_ops pipeline_routing_fe_ops = {
- .f_init = pipeline_routing_init,
- .f_post_init = NULL,
+ .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,