/* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2010-2016 Intel Corporation */ #include #include #include #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 route add port ether * p route add port ether * p route add port ether qinq * p route add port ether qinq * p route add port ether mpls * p route add port ether mpls * * route add default: * p route add default * * route del: * p route del * * route del default: * p route del default * * route ls: * p 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 arp add * * arp add default: * p arp add default * * arp del: * p arp del * * arp del default: * p arp del default * * arp ls: * p 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, };