This series of patches enable users to request to add/del pipe PMD request to the primary by REST API and CLI. The document will be provided by following patches. Itsuro Oda (5): shared: add PIPE port type primary: suport pipe PMD spp_nfv: ignore pipe PMD spp-ctl: enable add pipe port to the primary cli: support pipe PMD src/cli/commands/pri.py | 10 +++ src/nfv/main.c | 2 +- src/nfv/nfv_status.c | 6 ++ src/primary/main.c | 85 +++++++++++++++++-- src/shared/common.c | 9 ++ src/shared/common.h | 2 + src/shared/secondary/add_port.c | 34 ++++++++ src/shared/secondary/add_port.h | 16 ++++ .../secondary/spp_worker_th/cmd_utils.c | 2 + src/spp-ctl/spp_proc.py | 7 +- src/spp-ctl/spp_webapi.py | 24 +++++- 11 files changed, 182 insertions(+), 15 deletions(-) -- 2.17.1
This patch adds PIPE port type and related functions. Signed-off-by: Itsuro Oda <oda@valinux.co.jp> --- src/shared/common.c | 9 +++++ src/shared/common.h | 2 ++ src/shared/secondary/add_port.c | 34 +++++++++++++++++++ src/shared/secondary/add_port.h | 16 +++++++++ .../secondary/spp_worker_th/cmd_utils.c | 2 ++ 5 files changed, 63 insertions(+) diff --git a/src/shared/common.c b/src/shared/common.c index d878c5a..d1c3e36 100644 --- a/src/shared/common.c +++ b/src/shared/common.c @@ -139,6 +139,15 @@ int parse_dev_name(char *dev_name, int *port_type, int *port_id) *port_id = (int)strtol(pid_str, NULL, 10); *port_type = NULLPMD; + } else if (strncmp(dev_name, VDEV_SPP_PIPE, + strlen(VDEV_SPP_PIPE)) == 0) { + dev_str_len = strlen(VDEV_SPP_PIPE); + pid_len = dev_name_len - dev_str_len; + strncpy(pid_str, dev_name + strlen(VDEV_SPP_PIPE), + pid_len); + *port_id = (int)strtol(pid_str, NULL, 10); + *port_type = PIPE; + /* TODO(yasufum) add checking invalid port type and return -1 */ } else { *port_id = 0; diff --git a/src/shared/common.h b/src/shared/common.h index b4af73c..1688437 100644 --- a/src/shared/common.h +++ b/src/shared/common.h @@ -41,6 +41,7 @@ #define VDEV_ETH_TAP "eth_tap" #define VDEV_NET_TAP "net_tap" #define VDEV_NET_MEMIF "net_memif" +#define VDEV_SPP_PIPE "spp_pipe" #define VDEV_ETH_NULL "eth_null" @@ -85,6 +86,7 @@ enum port_type { NULLPMD, TAP, MEMIF, + PIPE, UNDEF, }; diff --git a/src/shared/secondary/add_port.c b/src/shared/secondary/add_port.c index 652ef69..a7b7261 100644 --- a/src/shared/secondary/add_port.c +++ b/src/shared/secondary/add_port.c @@ -62,6 +62,14 @@ get_null_pmd_name(int id) return buffer; } +static inline const char * +get_pipe_pmd_name(int id) +{ + static char buffer[sizeof(PIPE_PMD_DEV_NAME) + 2]; + snprintf(buffer, sizeof(buffer) - 1, PIPE_PMD_DEV_NAME, id); + return buffer; +} + /* * Create an empty rx pcap file to given path if it does not exit * Return 0 for succeeded, or -1 for failed. @@ -447,3 +455,29 @@ add_null_pmd(int index) return null_pmd_port_id; } + +/* + * Create a pipe. Note that this function used by primary only. + * Because a pipe is used by an application as a normal ether + * device, this function does creation only but does not do + * configuration etc. + */ +int +add_pipe_pmd(int index, const char *rx_ring, const char *tx_ring) +{ + const char *name; + char devargs[64]; + uint16_t pipe_pmd_port_id; + + int ret; + + name = get_pipe_pmd_name(index); + sprintf(devargs, "%s,rx=%s,tx=%s", name, rx_ring, tx_ring); + ret = dev_attach_by_devargs(devargs, &pipe_pmd_port_id); + if (ret < 0) + return ret; + + RTE_LOG(DEBUG, SHARED, "pipe port id %d\n", pipe_pmd_port_id); + + return pipe_pmd_port_id; +} diff --git a/src/shared/secondary/add_port.h b/src/shared/secondary/add_port.h index d686f20..39feb50 100644 --- a/src/shared/secondary/add_port.h +++ b/src/shared/secondary/add_port.h @@ -15,6 +15,7 @@ #define PCAP_PMD_DEV_NAME "eth_pcap%u" #define MEMIF_PMD_DEV_NAME "net_memif%u" #define NULL_PMD_DEV_NAME "eth_null%u" +#define PIPE_PMD_DEV_NAME "spp_pipe%u" #define PCAP_IFACE_RX "/tmp/spp-rx%d.pcap" #define PCAP_IFACE_TX "/tmp/spp-tx%d.pcap" @@ -108,4 +109,19 @@ add_memif_pmd(int index); int add_null_pmd(int index); +/** + * Create a pipe PMD with given ID. + * + * @param port_id + * ID of the next possible valid port. + * @param rx_ring + * Ring name for rx + * @param tx_ring + * Ring name for tx + * @return + * Unique port ID + */ +int +add_pipe_pmd(int index, const char *rx_ring, const char *tx_ring); + #endif diff --git a/src/shared/secondary/spp_worker_th/cmd_utils.c b/src/shared/secondary/spp_worker_th/cmd_utils.c index 69d7222..84d7fbe 100644 --- a/src/shared/secondary/spp_worker_th/cmd_utils.c +++ b/src/shared/secondary/spp_worker_th/cmd_utils.c @@ -448,6 +448,8 @@ init_host_port_info(void) p_iface_info->ring[port_id].iface_type = port_type; p_iface_info->ring[port_id].ethdev_port_id = port_id; break; + case PIPE: + break; default: RTE_LOG(ERR, WK_CMD_UTILS, "Unsupported port on host, " -- 2.17.1
This patch enables the primary to handle add/del request of pipe PMD. The primary comes to return infomation of pipes in the response of status request too. Signed-off-by: Itsuro Oda <oda@valinux.co.jp> --- src/primary/main.c | 85 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 8 deletions(-) diff --git a/src/primary/main.c b/src/primary/main.c index d3828e8..8d6a83d 100644 --- a/src/primary/main.c +++ b/src/primary/main.c @@ -27,7 +27,9 @@ */ #define PRI_BUF_SIZE_LCORE 128 #define PRI_BUF_SIZE_PHY 512 -#define PRI_BUF_SIZE_RING (MSG_SIZE - PRI_BUF_SIZE_LCORE - PRI_BUF_SIZE_PHY) +#define PRI_BUF_SIZE_PIPE 512 +#define PRI_BUF_SIZE_RING \ + (MSG_SIZE - PRI_BUF_SIZE_LCORE - PRI_BUF_SIZE_PHY - PRI_BUF_SIZE_PIPE) #define SPP_PATH_LEN 1024 /* seems enough for path of spp procs */ #define NOF_TOKENS 48 /* seems enough to contain tokens */ @@ -49,6 +51,7 @@ struct port_id_map { int port_id; enum port_type type; + int rx_ring_id, tx_ring_id; /* for pipe */ }; struct port_id_map port_id_list[RTE_MAX_ETHPORTS]; @@ -437,6 +440,10 @@ append_port_info_json(char *str, sprintf(str + strlen(str), "\"memif:%u\",", port_map[i].id); break; + case PIPE: + sprintf(str + strlen(str), "\"pipe:%u\",", + port_map[i].id); + break; case UNDEF: /* TODO(yasufum) Need to remove print for undefined ? */ sprintf(str + strlen(str), "\"udf\","); @@ -521,6 +528,12 @@ append_patch_info_json(char *str, "\"memif:%u\",", port_map[i].id); break; + case PIPE: + RTE_LOG(INFO, SHARED, "Type: PIPE\n"); + sprintf(patch_str + strlen(patch_str), + "\"pipe:%u\",", + port_map[i].id); + break; case UNDEF: RTE_LOG(INFO, PRIMARY, "Type: UDF\n"); /* TODO(yasufum) Need to remove print for undefined ? */ @@ -583,6 +596,12 @@ append_patch_info_json(char *str, "\"memif:%u\"", port_map[j].id); break; + case PIPE: + RTE_LOG(INFO, SHARED, "Type: PIPE\n"); + sprintf(patch_str + strlen(patch_str), + "\"pipe:%u\"", + port_map[j].id); + break; case UNDEF: RTE_LOG(INFO, PRIMARY, "Type: UDF\n"); /* @@ -729,6 +748,34 @@ ring_port_stats_json(char *str) return 0; } +static int +pipes_json(char *str) +{ + uint16_t dev_id; + char pipe_buf[30]; /* it is enough if port_id < 1000 */ + int find = 0; + + strcpy(str, "\"pipes\":["); + for (dev_id = 0; dev_id < RTE_MAX_ETHPORTS; dev_id++) { + if (port_id_list[dev_id].type != PIPE) + continue; + sprintf(pipe_buf, "{\"id\":%d,\"rx\":%d,\"tx\":%d}", + port_id_list[dev_id].port_id, + port_id_list[dev_id].rx_ring_id, + port_id_list[dev_id].tx_ring_id); + if (strlen(str) + strlen(pipe_buf) > PRI_BUF_SIZE_PIPE - 3) { + RTE_LOG(ERR, PRIMARY, "Cannot send all of pipes\n"); + break; + } + if (find) + strcat(str, ","); + find = 1; + strcat(str, pipe_buf); + } + strcat(str, "]"); + return 0; +} + /** * Retrieve all of statu of ports as JSON format managed by primary. * @@ -770,28 +817,33 @@ get_status_json(char *str) char buf_lcores[PRI_BUF_SIZE_LCORE]; char buf_phy_ports[PRI_BUF_SIZE_PHY]; char buf_ring_ports[PRI_BUF_SIZE_RING]; + char buf_pipes[PRI_BUF_SIZE_PIPE]; memset(buf_phy_ports, '\0', PRI_BUF_SIZE_PHY); memset(buf_ring_ports, '\0', PRI_BUF_SIZE_RING); memset(buf_lcores, '\0', PRI_BUF_SIZE_LCORE); + memset(buf_pipes, '\0', PRI_BUF_SIZE_PIPE); append_lcore_info_json(buf_lcores, lcore_id_used); phy_port_stats_json(buf_phy_ports); ring_port_stats_json(buf_ring_ports); + pipes_json(buf_pipes); - RTE_LOG(INFO, PRIMARY, "%s, %s\n", buf_phy_ports, buf_ring_ports); + RTE_LOG(INFO, PRIMARY, "%s, %s, %s\n", buf_phy_ports, buf_ring_ports, + buf_pipes); if (get_forwarding_flg() == 1) { char tmp_buf[512]; memset(tmp_buf, '\0', sizeof(tmp_buf)); forwarder_status_json(tmp_buf); - sprintf(str, "{%s,%s,%s,%s}", + sprintf(str, "{%s,%s,%s,%s,%s}", buf_lcores, tmp_buf, buf_phy_ports, - buf_ring_ports); + buf_ring_ports, buf_pipes); } else { - sprintf(str, "{%s,%s,%s}", - buf_lcores, buf_phy_ports, buf_ring_ports); + sprintf(str, "{%s,%s,%s,%s}", + buf_lcores, buf_phy_ports, buf_ring_ports, + buf_pipes); } return 0; @@ -803,7 +855,7 @@ get_status_json(char *str) */ /* TODO(yasufum) consider to merge do_add in nfv/commands.h */ static int -add_port(char *p_type, int p_id) +add_port(char *p_type, int p_id, char **token_list) { uint16_t dev_id; uint16_t port_id; @@ -840,6 +892,17 @@ add_port(char *p_type, int p_id) res = add_null_pmd(p_id); port_id_list[cnt].port_id = p_id; port_id_list[cnt].type = NULLPMD; + } else if (!strcmp(p_type, "pipe")) { + char *dummy; + res = add_pipe_pmd(p_id, token_list[0], token_list[1]); + if (res < 0) + return -1; + port_id_list[cnt].port_id = p_id; + port_id_list[cnt].type = PIPE; + parse_resource_uid(token_list[0], &dummy, + &port_id_list[cnt].rx_ring_id); + parse_resource_uid(token_list[1], &dummy, + &port_id_list[cnt].tx_ring_id); } if (res < 0) @@ -922,6 +985,12 @@ del_port(char *p_type, int p_id) if (dev_id == PORT_RESET) return -1; dev_detach_by_port_id(dev_id); + + } else if (!strcmp(p_type, "pipe")) { + dev_id = find_ethdev_id(p_id, PIPE); + if (dev_id == PORT_RESET) + return -1; + dev_detach_by_port_id(dev_id); } port_id_list[dev_id].port_id = PORT_RESET; @@ -1022,7 +1091,7 @@ parse_command(char *str) return ret; } - if (add_port(p_type, p_id) < 0) { + if (add_port(p_type, p_id, &token_list[2]) < 0) { RTE_LOG(ERR, PRIMARY, "Failed to add_port()\n"); sprintf(result, "%s", "\"failed\""); } else -- 2.17.1
Because spp_nfv does not handle pipe PMDs, spp_nfv ignores them. Signed-off-by: Itsuro Oda <oda@valinux.co.jp> --- src/nfv/main.c | 2 +- src/nfv/nfv_status.c | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/nfv/main.c b/src/nfv/main.c index f2c6bfc..f0ad17d 100644 --- a/src/nfv/main.c +++ b/src/nfv/main.c @@ -211,7 +211,7 @@ main(int argc, char *argv[]) if (port_type == PHY) { port_id = nof_phy_port; nof_phy_port++; - } else if (port_type == VHOST) + } else if (port_type == VHOST || port_type == PIPE) continue; /* NOTE: vhost may be used another process. even if no * process uses, it is necessary to "add vhost" explicitly. diff --git a/src/nfv/nfv_status.c b/src/nfv/nfv_status.c index 3947a84..33fecd4 100644 --- a/src/nfv/nfv_status.c +++ b/src/nfv/nfv_status.c @@ -119,6 +119,8 @@ append_port_info_json(char *str, sprintf(str + strlen(str), "\"memif:%u\",", port_map[i].id); break; + case PIPE: + break; case UNDEF: /* TODO(yasufum) Need to remove print for undefined ? */ sprintf(str + strlen(str), "\"udf\","); @@ -211,6 +213,8 @@ append_patch_info_json(char *str, "\"memif:%u\",", port_map[i].id); break; + case PIPE: + break; case UNDEF: RTE_LOG(INFO, SHARED, "Type: UDF\n"); /* TODO(yasufum) Need to remove print for undefined ? */ @@ -273,6 +277,8 @@ append_patch_info_json(char *str, "\"memif:%u\"", port_map[j].id); break; + case PIPE: + break; case UNDEF: RTE_LOG(INFO, SHARED, "Type: UDF\n"); /* -- 2.17.1
This patch adds pipe type to add port REST API to the primary. Note that del port API is common among all port types including pipe. Signed-off-by: Itsuro Oda <oda@valinux.co.jp> --- src/spp-ctl/spp_proc.py | 7 +++++-- src/spp-ctl/spp_webapi.py | 24 ++++++++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/spp-ctl/spp_proc.py b/src/spp-ctl/spp_proc.py index 35919fb..c784f56 100644 --- a/src/spp-ctl/spp_proc.py +++ b/src/spp-ctl/spp_proc.py @@ -294,8 +294,11 @@ class PrimaryProc(SppProc): return "clear" @exec_command - def port_add(self, port): - return "add {port}".format(**locals()) + def port_add(self, port, rx=None, tx=None): + if rx is not None and tx is not None: + return "add {port} {rx} {tx}".format(**locals()) + else: + return "add {port}".format(**locals()) @exec_command def port_del(self, port): diff --git a/src/spp-ctl/spp_webapi.py b/src/spp-ctl/spp_webapi.py index 31befe2..c7d8271 100644 --- a/src/spp-ctl/spp_webapi.py +++ b/src/spp-ctl/spp_webapi.py @@ -13,7 +13,8 @@ import sys import spp_proc -PORT_TYPES = ["phy", "vhost", "ring", "pcap", "nullpmd", "tap", "memif"] +PORT_TYPES = ["phy", "vhost", "ring", "pcap", "nullpmd", "tap", "memif", + "pipe"] VF_PORT_TYPES = ["phy", "vhost", "ring"] # TODO(yasufum) add other ports # TODO(yasufum) consider PCAP_PORT_TYPES is required. @@ -50,10 +51,10 @@ class BaseHandler(bottle.Bottle): res.content_type = "text/plain" return res.body - def _validate_port(self, port): + def _validate_port(self, port, port_types=PORT_TYPES): try: if_type, if_num = port.split(":") - if if_type not in PORT_TYPES: + if if_type not in port_types: raise int(if_num) except Exception: @@ -514,12 +515,27 @@ class V1PrimaryHandler(BaseHandler): raise KeyInvalid('action', body['action']) self._validate_port(body['port']) + def _validate_pipe_args(self, rx_ring, tx_ring): + try: + self._validate_port(rx_ring, ["ring"]) + except Exception: + raise KeyInvalid('rx', rx_ring) + try: + self._validate_port(tx_ring, ["ring"]) + except Exception: + raise KeyInvalid('tx', tx_ring) + def primary_port(self, body): self._validate_nfv_port(body) proc = self._get_proc() if body['action'] == "add": - proc.port_add(body['port']) + if body['port'].startswith("pipe:"): + self._validate_pipe_args(body.get('rx', ""), + body.get('tx', "")) + proc.port_add(body['port'], body['rx'], body['tx']) + else: + proc.port_add(body['port']) else: proc.port_del(body['port']) -- 2.17.1
This patch adds add pipe command to the primary. Infomation about pipe is added to the output of status command of the primary too. Signed-off-by: Itsuro Oda <oda@valinux.co.jp> --- src/cli/commands/pri.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/cli/commands/pri.py b/src/cli/commands/pri.py index a13137d..c6ad265 100644 --- a/src/cli/commands/pri.py +++ b/src/cli/commands/pri.py @@ -223,6 +223,12 @@ class SppPrimary(object): else: print(' - {} -> {}'.format(port, dst)) + if ('pipes' in json_obj): + print(' - pipes:') + for pipe in json_obj['pipes']: + print(' - pipe:{} ring:{} ring:{}'.format(pipe['id'], + pipe['rx'], pipe['tx'])) + if ('phy_ports' in json_obj) or ('ring_ports' in json_obj): print('- stats') @@ -764,6 +770,10 @@ class SppPrimary(object): print("'%s' is already added." % params[0]) else: req_params = {'action': 'add', 'port': params[0]} + if len(params) == 3: + # add pipe:X ring:A ring:B + req_params['rx'] = params[1] + req_params['tx'] = params[2] res = self.spp_ctl_cli.put('primary/ports', req_params) if res is not None: -- 2.17.1
> This patch enables the primary to handle add/del request of > pipe PMD. The primary comes to return infomation of pipes in > the response of status request too. > > Signed-off-by: Itsuro Oda <oda@valinux.co.jp> > --- > src/primary/main.c | 85 +++++++++++++++++++++++++++++++++++++++++----- > 1 file changed, 77 insertions(+), 8 deletions(-) > > diff --git a/src/primary/main.c b/src/primary/main.c > index d3828e8..8d6a83d 100644 > --- a/src/primary/main.c > +++ b/src/primary/main.c > @@ -27,7 +27,9 @@ > */ > #define PRI_BUF_SIZE_LCORE 128 > #define PRI_BUF_SIZE_PHY 512 This define was updated in a patch from Hideyuki, so it is failed to merge for a conflict. It might be other conflicts after that, but I haven't check it yet though. Could you update your patch with the latest code base which was updated yesterday. Thanks > -#define PRI_BUF_SIZE_RING (MSG_SIZE - PRI_BUF_SIZE_LCORE - PRI_BUF_SIZE_PHY) > +#define PRI_BUF_SIZE_PIPE 512 > +#define PRI_BUF_SIZE_RING \ > + (MSG_SIZE - PRI_BUF_SIZE_LCORE - PRI_BUF_SIZE_PHY - PRI_BUF_SIZE_PIPE) > > #define SPP_PATH_LEN 1024 /* seems enough for path of spp procs */ > #define NOF_TOKENS 48 /* seems enough to contain tokens */ > @@ -49,6 +51,7 @@ > struct port_id_map { > int port_id; > enum port_type type; > + int rx_ring_id, tx_ring_id; /* for pipe */ > }; > > struct port_id_map port_id_list[RTE_MAX_ETHPORTS]; > @@ -437,6 +440,10 @@ append_port_info_json(char *str, > sprintf(str + strlen(str), "\"memif:%u\",", > port_map[i].id); > break; > + case PIPE: > + sprintf(str + strlen(str), "\"pipe:%u\",", > + port_map[i].id); > + break; > case UNDEF: > /* TODO(yasufum) Need to remove print for undefined ? */ > sprintf(str + strlen(str), "\"udf\","); > @@ -521,6 +528,12 @@ append_patch_info_json(char *str, > "\"memif:%u\",", > port_map[i].id); > break; > + case PIPE: > + RTE_LOG(INFO, SHARED, "Type: PIPE\n"); > + sprintf(patch_str + strlen(patch_str), > + "\"pipe:%u\",", > + port_map[i].id); > + break; > case UNDEF: > RTE_LOG(INFO, PRIMARY, "Type: UDF\n"); > /* TODO(yasufum) Need to remove print for undefined ? */ > @@ -583,6 +596,12 @@ append_patch_info_json(char *str, > "\"memif:%u\"", > port_map[j].id); > break; > + case PIPE: > + RTE_LOG(INFO, SHARED, "Type: PIPE\n"); > + sprintf(patch_str + strlen(patch_str), > + "\"pipe:%u\"", > + port_map[j].id); > + break; > case UNDEF: > RTE_LOG(INFO, PRIMARY, "Type: UDF\n"); > /* > @@ -729,6 +748,34 @@ ring_port_stats_json(char *str) > return 0; > } > > +static int > +pipes_json(char *str) > +{ > + uint16_t dev_id; > + char pipe_buf[30]; /* it is enough if port_id < 1000 */ > + int find = 0; > + > + strcpy(str, "\"pipes\":["); > + for (dev_id = 0; dev_id < RTE_MAX_ETHPORTS; dev_id++) { > + if (port_id_list[dev_id].type != PIPE) > + continue; > + sprintf(pipe_buf, "{\"id\":%d,\"rx\":%d,\"tx\":%d}", > + port_id_list[dev_id].port_id, > + port_id_list[dev_id].rx_ring_id, > + port_id_list[dev_id].tx_ring_id); > + if (strlen(str) + strlen(pipe_buf) > PRI_BUF_SIZE_PIPE - 3) { > + RTE_LOG(ERR, PRIMARY, "Cannot send all of pipes\n"); > + break; > + } > + if (find) > + strcat(str, ","); > + find = 1; > + strcat(str, pipe_buf); > + } > + strcat(str, "]"); > + return 0; > +} > + > /** > * Retrieve all of statu of ports as JSON format managed by primary. > * > @@ -770,28 +817,33 @@ get_status_json(char *str) > char buf_lcores[PRI_BUF_SIZE_LCORE]; > char buf_phy_ports[PRI_BUF_SIZE_PHY]; > char buf_ring_ports[PRI_BUF_SIZE_RING]; > + char buf_pipes[PRI_BUF_SIZE_PIPE]; > memset(buf_phy_ports, '\0', PRI_BUF_SIZE_PHY); > memset(buf_ring_ports, '\0', PRI_BUF_SIZE_RING); > memset(buf_lcores, '\0', PRI_BUF_SIZE_LCORE); > + memset(buf_pipes, '\0', PRI_BUF_SIZE_PIPE); > > append_lcore_info_json(buf_lcores, lcore_id_used); > phy_port_stats_json(buf_phy_ports); > ring_port_stats_json(buf_ring_ports); > + pipes_json(buf_pipes); > > - RTE_LOG(INFO, PRIMARY, "%s, %s\n", buf_phy_ports, buf_ring_ports); > + RTE_LOG(INFO, PRIMARY, "%s, %s, %s\n", buf_phy_ports, buf_ring_ports, > + buf_pipes); > > if (get_forwarding_flg() == 1) { > char tmp_buf[512]; > memset(tmp_buf, '\0', sizeof(tmp_buf)); > forwarder_status_json(tmp_buf); > > - sprintf(str, "{%s,%s,%s,%s}", > + sprintf(str, "{%s,%s,%s,%s,%s}", > buf_lcores, tmp_buf, buf_phy_ports, > - buf_ring_ports); > + buf_ring_ports, buf_pipes); > > } else { > - sprintf(str, "{%s,%s,%s}", > - buf_lcores, buf_phy_ports, buf_ring_ports); > + sprintf(str, "{%s,%s,%s,%s}", > + buf_lcores, buf_phy_ports, buf_ring_ports, > + buf_pipes); > } > > return 0; > @@ -803,7 +855,7 @@ get_status_json(char *str) > */ > /* TODO(yasufum) consider to merge do_add in nfv/commands.h */ > static int > -add_port(char *p_type, int p_id) > +add_port(char *p_type, int p_id, char **token_list) > { > uint16_t dev_id; > uint16_t port_id; > @@ -840,6 +892,17 @@ add_port(char *p_type, int p_id) > res = add_null_pmd(p_id); > port_id_list[cnt].port_id = p_id; > port_id_list[cnt].type = NULLPMD; > + } else if (!strcmp(p_type, "pipe")) { > + char *dummy; > + res = add_pipe_pmd(p_id, token_list[0], token_list[1]); > + if (res < 0) > + return -1; > + port_id_list[cnt].port_id = p_id; > + port_id_list[cnt].type = PIPE; > + parse_resource_uid(token_list[0], &dummy, > + &port_id_list[cnt].rx_ring_id); > + parse_resource_uid(token_list[1], &dummy, > + &port_id_list[cnt].tx_ring_id); > } > > if (res < 0) > @@ -922,6 +985,12 @@ del_port(char *p_type, int p_id) > if (dev_id == PORT_RESET) > return -1; > dev_detach_by_port_id(dev_id); > + > + } else if (!strcmp(p_type, "pipe")) { > + dev_id = find_ethdev_id(p_id, PIPE); > + if (dev_id == PORT_RESET) > + return -1; > + dev_detach_by_port_id(dev_id); > } > > port_id_list[dev_id].port_id = PORT_RESET; > @@ -1022,7 +1091,7 @@ parse_command(char *str) > return ret; > } > > - if (add_port(p_type, p_id) < 0) { > + if (add_port(p_type, p_id, &token_list[2]) < 0) { > RTE_LOG(ERR, PRIMARY, "Failed to add_port()\n"); > sprintf(result, "%s", "\"failed\""); > } else >
This series of patches enable users to request to add/del pipe PMD request to the primary by REST API and CLI. The document will be provided by following patches. --- v2: * rebase on the newest master Itsuro Oda (5): shared: add PIPE port type primary: suport pipe PMD spp_nfv: ignore pipe PMD spp-ctl: enable add pipe port to the primary cli: support pipe PMD src/cli/commands/pri.py | 10 +++ src/nfv/main.c | 2 +- src/nfv/nfv_status.c | 5 ++ src/primary/main.c | 86 +++++++++++++++++-- src/shared/common.c | 9 ++ src/shared/common.h | 2 + src/shared/secondary/add_port.c | 34 ++++++++ src/shared/secondary/add_port.h | 16 ++++ .../secondary/spp_worker_th/cmd_utils.c | 2 + src/spp-ctl/spp_proc.py | 7 +- src/spp-ctl/spp_webapi.py | 24 +++++- 11 files changed, 182 insertions(+), 15 deletions(-) -- 2.17.1
This patch adds PIPE port type and related functions. Signed-off-by: Itsuro Oda <oda@valinux.co.jp> --- src/shared/common.c | 9 +++++ src/shared/common.h | 2 ++ src/shared/secondary/add_port.c | 34 +++++++++++++++++++ src/shared/secondary/add_port.h | 16 +++++++++ .../secondary/spp_worker_th/cmd_utils.c | 2 ++ 5 files changed, 63 insertions(+) diff --git a/src/shared/common.c b/src/shared/common.c index d878c5a..d1c3e36 100644 --- a/src/shared/common.c +++ b/src/shared/common.c @@ -139,6 +139,15 @@ int parse_dev_name(char *dev_name, int *port_type, int *port_id) *port_id = (int)strtol(pid_str, NULL, 10); *port_type = NULLPMD; + } else if (strncmp(dev_name, VDEV_SPP_PIPE, + strlen(VDEV_SPP_PIPE)) == 0) { + dev_str_len = strlen(VDEV_SPP_PIPE); + pid_len = dev_name_len - dev_str_len; + strncpy(pid_str, dev_name + strlen(VDEV_SPP_PIPE), + pid_len); + *port_id = (int)strtol(pid_str, NULL, 10); + *port_type = PIPE; + /* TODO(yasufum) add checking invalid port type and return -1 */ } else { *port_id = 0; diff --git a/src/shared/common.h b/src/shared/common.h index d311e82..fd3102c 100644 --- a/src/shared/common.h +++ b/src/shared/common.h @@ -57,6 +57,7 @@ #define VDEV_ETH_TAP "eth_tap" #define VDEV_NET_TAP "net_tap" #define VDEV_NET_MEMIF "net_memif" +#define VDEV_SPP_PIPE "spp_pipe" #define VDEV_ETH_NULL "eth_null" @@ -109,6 +110,7 @@ enum port_type { NULLPMD, TAP, MEMIF, + PIPE, UNDEF, }; diff --git a/src/shared/secondary/add_port.c b/src/shared/secondary/add_port.c index 652ef69..a7b7261 100644 --- a/src/shared/secondary/add_port.c +++ b/src/shared/secondary/add_port.c @@ -62,6 +62,14 @@ get_null_pmd_name(int id) return buffer; } +static inline const char * +get_pipe_pmd_name(int id) +{ + static char buffer[sizeof(PIPE_PMD_DEV_NAME) + 2]; + snprintf(buffer, sizeof(buffer) - 1, PIPE_PMD_DEV_NAME, id); + return buffer; +} + /* * Create an empty rx pcap file to given path if it does not exit * Return 0 for succeeded, or -1 for failed. @@ -447,3 +455,29 @@ add_null_pmd(int index) return null_pmd_port_id; } + +/* + * Create a pipe. Note that this function used by primary only. + * Because a pipe is used by an application as a normal ether + * device, this function does creation only but does not do + * configuration etc. + */ +int +add_pipe_pmd(int index, const char *rx_ring, const char *tx_ring) +{ + const char *name; + char devargs[64]; + uint16_t pipe_pmd_port_id; + + int ret; + + name = get_pipe_pmd_name(index); + sprintf(devargs, "%s,rx=%s,tx=%s", name, rx_ring, tx_ring); + ret = dev_attach_by_devargs(devargs, &pipe_pmd_port_id); + if (ret < 0) + return ret; + + RTE_LOG(DEBUG, SHARED, "pipe port id %d\n", pipe_pmd_port_id); + + return pipe_pmd_port_id; +} diff --git a/src/shared/secondary/add_port.h b/src/shared/secondary/add_port.h index d686f20..39feb50 100644 --- a/src/shared/secondary/add_port.h +++ b/src/shared/secondary/add_port.h @@ -15,6 +15,7 @@ #define PCAP_PMD_DEV_NAME "eth_pcap%u" #define MEMIF_PMD_DEV_NAME "net_memif%u" #define NULL_PMD_DEV_NAME "eth_null%u" +#define PIPE_PMD_DEV_NAME "spp_pipe%u" #define PCAP_IFACE_RX "/tmp/spp-rx%d.pcap" #define PCAP_IFACE_TX "/tmp/spp-tx%d.pcap" @@ -108,4 +109,19 @@ add_memif_pmd(int index); int add_null_pmd(int index); +/** + * Create a pipe PMD with given ID. + * + * @param port_id + * ID of the next possible valid port. + * @param rx_ring + * Ring name for rx + * @param tx_ring + * Ring name for tx + * @return + * Unique port ID + */ +int +add_pipe_pmd(int index, const char *rx_ring, const char *tx_ring); + #endif diff --git a/src/shared/secondary/spp_worker_th/cmd_utils.c b/src/shared/secondary/spp_worker_th/cmd_utils.c index 3dea02c..9f0d3fb 100644 --- a/src/shared/secondary/spp_worker_th/cmd_utils.c +++ b/src/shared/secondary/spp_worker_th/cmd_utils.c @@ -470,6 +470,8 @@ init_host_port_info(void) p_iface_info->ring[port_id].iface_type = port_type; p_iface_info->ring[port_id].ethdev_port_id = port_id; break; + case PIPE: + break; default: RTE_LOG(ERR, WK_CMD_UTILS, "Unsupported port on host, " -- 2.17.1
This patch enables the primary to handle add/del request of pipe PMD. The primary comes to return infomation of pipes in the response of status request too. Signed-off-by: Itsuro Oda <oda@valinux.co.jp> --- src/primary/main.c | 86 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 8 deletions(-) diff --git a/src/primary/main.c b/src/primary/main.c index 4ef9cb1..872f820 100644 --- a/src/primary/main.c +++ b/src/primary/main.c @@ -28,7 +28,9 @@ */ #define PRI_BUF_SIZE_LCORE 128 #define PRI_BUF_SIZE_PHY 30720 -#define PRI_BUF_SIZE_RING (MSG_SIZE - PRI_BUF_SIZE_LCORE - PRI_BUF_SIZE_PHY) +#define PRI_BUF_SIZE_PIPE 512 +#define PRI_BUF_SIZE_RING \ + (MSG_SIZE - PRI_BUF_SIZE_LCORE - PRI_BUF_SIZE_PHY - PRI_BUF_SIZE_PIPE) #define SPP_PATH_LEN 1024 /* seems enough for path of spp procs */ #define NOF_TOKENS 48 /* seems enough to contain tokens */ @@ -50,6 +52,7 @@ struct port_id_map { int port_id; enum port_type type; + int rx_ring_id, tx_ring_id; /* for pipe */ }; struct port_id_map port_id_list[RTE_MAX_ETHPORTS]; @@ -436,6 +439,10 @@ append_port_info_json(char *str) sprintf(str + strlen(str), "\"memif:%u\",", port_map[i].id); break; + case PIPE: + sprintf(str + strlen(str), "\"pipe:%u\",", + port_map[i].id); + break; case UNDEF: /* TODO(yasufum) Need to remove print for undefined ? */ sprintf(str + strlen(str), "\"udf\","); @@ -518,6 +525,12 @@ append_patch_info_json(char *str) "\"memif:%u\",", port_map[i].id); break; + case PIPE: + RTE_LOG(INFO, SHARED, "Type: PIPE\n"); + sprintf(patch_str + strlen(patch_str), + "\"pipe:%u\",", + port_map[i].id); + break; case UNDEF: RTE_LOG(INFO, PRIMARY, "Type: UDF\n"); /* TODO(yasufum) Need to remove print for undefined ? */ @@ -580,6 +593,12 @@ append_patch_info_json(char *str) "\"memif:%u\"", port_map[j].id); break; + case PIPE: + RTE_LOG(INFO, SHARED, "Type: PIPE\n"); + sprintf(patch_str + strlen(patch_str), + "\"pipe:%u\"", + port_map[j].id); + break; case UNDEF: RTE_LOG(INFO, PRIMARY, "Type: UDF\n"); /* @@ -740,6 +759,34 @@ ring_port_stats_json(char *str) return 0; } +static int +pipes_json(char *str) +{ + uint16_t dev_id; + char pipe_buf[30]; /* it is enough if port_id < 1000 */ + int find = 0; + + strcpy(str, "\"pipes\":["); + for (dev_id = 0; dev_id < RTE_MAX_ETHPORTS; dev_id++) { + if (port_id_list[dev_id].type != PIPE) + continue; + sprintf(pipe_buf, "{\"id\":%d,\"rx\":%d,\"tx\":%d}", + port_id_list[dev_id].port_id, + port_id_list[dev_id].rx_ring_id, + port_id_list[dev_id].tx_ring_id); + if (strlen(str) + strlen(pipe_buf) > PRI_BUF_SIZE_PIPE - 3) { + RTE_LOG(ERR, PRIMARY, "Cannot send all of pipes\n"); + break; + } + if (find) + strcat(str, ","); + find = 1; + strcat(str, pipe_buf); + } + strcat(str, "]"); + return 0; +} + /** * Retrieve all of statu of ports as JSON format managed by primary. * @@ -781,28 +828,33 @@ get_status_json(char *str) char buf_lcores[PRI_BUF_SIZE_LCORE]; char buf_phy_ports[PRI_BUF_SIZE_PHY]; char buf_ring_ports[PRI_BUF_SIZE_RING]; + char buf_pipes[PRI_BUF_SIZE_PIPE]; memset(buf_phy_ports, '\0', PRI_BUF_SIZE_PHY); memset(buf_ring_ports, '\0', PRI_BUF_SIZE_RING); memset(buf_lcores, '\0', PRI_BUF_SIZE_LCORE); + memset(buf_pipes, '\0', PRI_BUF_SIZE_PIPE); append_lcore_info_json(buf_lcores, lcore_id_used); phy_port_stats_json(buf_phy_ports); ring_port_stats_json(buf_ring_ports); + pipes_json(buf_pipes); - RTE_LOG(INFO, PRIMARY, "%s, %s\n", buf_phy_ports, buf_ring_ports); + RTE_LOG(INFO, PRIMARY, "%s, %s, %s\n", buf_phy_ports, buf_ring_ports, + buf_pipes); if (get_forwarding_flg() == 1) { char tmp_buf[512]; memset(tmp_buf, '\0', sizeof(tmp_buf)); forwarder_status_json(tmp_buf); - sprintf(str, "{%s,%s,%s,%s}", + sprintf(str, "{%s,%s,%s,%s,%s}", buf_lcores, tmp_buf, buf_phy_ports, - buf_ring_ports); + buf_ring_ports, buf_pipes); } else { - sprintf(str, "{%s,%s,%s}", - buf_lcores, buf_phy_ports, buf_ring_ports); + sprintf(str, "{%s,%s,%s,%s}", + buf_lcores, buf_phy_ports, buf_ring_ports, + buf_pipes); } return 0; @@ -814,7 +866,7 @@ get_status_json(char *str) */ /* TODO(yasufum) consider to merge do_add in nfv/commands.h */ static int -add_port(char *p_type, int p_id) +add_port(char *p_type, int p_id, char **token_list) { uint16_t dev_id; uint16_t port_id; @@ -851,6 +903,18 @@ add_port(char *p_type, int p_id) res = add_null_pmd(p_id); port_id_list[cnt].port_id = p_id; port_id_list[cnt].type = NULLPMD; + } else if (!strcmp(p_type, "pipe")) { + char *dummy_type; + uint16_t dummy_queue; + res = add_pipe_pmd(p_id, token_list[0], token_list[1]); + if (res < 0) + return -1; + port_id_list[cnt].port_id = p_id; + port_id_list[cnt].type = PIPE; + parse_resource_uid(token_list[0], &dummy_type, + &port_id_list[cnt].rx_ring_id, &dummy_queue); + parse_resource_uid(token_list[1], &dummy_type, + &port_id_list[cnt].tx_ring_id, &dummy_queue); } if (res < 0) @@ -933,6 +997,12 @@ del_port(char *p_type, int p_id) if (dev_id == PORT_RESET) return -1; dev_detach_by_port_id(dev_id); + + } else if (!strcmp(p_type, "pipe")) { + dev_id = find_ethdev_id(p_id, PIPE); + if (dev_id == PORT_RESET) + return -1; + dev_detach_by_port_id(dev_id); } port_id_list[dev_id].port_id = PORT_RESET; @@ -1037,7 +1107,7 @@ parse_command(char *str) return ret; } - if (add_port(p_type, p_id) < 0) { + if (add_port(p_type, p_id, &token_list[2]) < 0) { RTE_LOG(ERR, PRIMARY, "Failed to add_port()\n"); sprintf(result, "%s", "\"failed\""); } else -- 2.17.1
Because spp_nfv does not handle pipe PMDs, spp_nfv ignores them. Signed-off-by: Itsuro Oda <oda@valinux.co.jp> --- src/nfv/main.c | 2 +- src/nfv/nfv_status.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/nfv/main.c b/src/nfv/main.c index 32f1074..2b76672 100644 --- a/src/nfv/main.c +++ b/src/nfv/main.c @@ -212,7 +212,7 @@ main(int argc, char *argv[]) if (port_type == PHY) { port_id = nof_phy_port; nof_phy_port++; - } else if (port_type == VHOST) + } else if (port_type == VHOST || port_type == PIPE) continue; /* NOTE: vhost may be used another process. even if no * process uses, it is necessary to "add vhost" explicitly. diff --git a/src/nfv/nfv_status.c b/src/nfv/nfv_status.c index d5d7f44..134fb3f 100644 --- a/src/nfv/nfv_status.c +++ b/src/nfv/nfv_status.c @@ -125,6 +125,8 @@ append_port_info_json(char *str) sprintf(str + strlen(str), "\"memif:%u\",", port_map[i].id); break; + case PIPE: + break; case UNDEF: /* * TODO(yasufum) Need to remove print for @@ -189,6 +191,9 @@ append_port_string(char *str, enum port_type port_type, sprintf(str, "\"memif:%u\"", port_id); break; + case PIPE: + break; + case UNDEF: RTE_LOG(INFO, SHARED, "Type: UDF\n"); /* TODO(yasufum) Need to remove print for undefined ? */ -- 2.17.1
This patch adds pipe type to add port REST API to the primary. Note that del port API is common among all port types including pipe. Signed-off-by: Itsuro Oda <oda@valinux.co.jp> --- src/spp-ctl/spp_proc.py | 7 +++++-- src/spp-ctl/spp_webapi.py | 24 ++++++++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/spp-ctl/spp_proc.py b/src/spp-ctl/spp_proc.py index d584f7f..caccc81 100644 --- a/src/spp-ctl/spp_proc.py +++ b/src/spp-ctl/spp_proc.py @@ -294,8 +294,11 @@ class PrimaryProc(SppProc): return "clear" @exec_command - def port_add(self, port): - return "add {port}".format(**locals()) + def port_add(self, port, rx=None, tx=None): + if rx is not None and tx is not None: + return "add {port} {rx} {tx}".format(**locals()) + else: + return "add {port}".format(**locals()) @exec_command def port_del(self, port): diff --git a/src/spp-ctl/spp_webapi.py b/src/spp-ctl/spp_webapi.py index d8e6e73..65998a9 100644 --- a/src/spp-ctl/spp_webapi.py +++ b/src/spp-ctl/spp_webapi.py @@ -13,7 +13,8 @@ import sys import spp_proc -PORT_TYPES = ["phy", "vhost", "ring", "pcap", "nullpmd", "tap", "memif"] +PORT_TYPES = ["phy", "vhost", "ring", "pcap", "nullpmd", "tap", "memif", + "pipe"] VF_PORT_TYPES = ["phy", "vhost", "ring"] # TODO(yasufum) add other ports # TODO(yasufum) consider PCAP_PORT_TYPES is required. @@ -64,10 +65,10 @@ class BaseHandler(bottle.Bottle): res.content_type = "text/plain" return res.body - def _validate_port(self, port): + def _validate_port(self, port, port_types=PORT_TYPES): try: if_type, if_num = port.split(":") - if if_type not in PORT_TYPES: + if if_type not in port_types: raise if if_type == "phy" and "nq" in if_num: port_num, queue_num = if_num.split("nq") @@ -545,12 +546,27 @@ class V1PrimaryHandler(BaseHandler): raise KeyInvalid('action', body['action']) self._validate_port(body['port']) + def _validate_pipe_args(self, rx_ring, tx_ring): + try: + self._validate_port(rx_ring, ["ring"]) + except Exception: + raise KeyInvalid('rx', rx_ring) + try: + self._validate_port(tx_ring, ["ring"]) + except Exception: + raise KeyInvalid('tx', tx_ring) + def primary_port(self, body): self._validate_nfv_port(body) proc = self._get_proc() if body['action'] == "add": - proc.port_add(body['port']) + if body['port'].startswith("pipe:"): + self._validate_pipe_args(body.get('rx', ""), + body.get('tx', "")) + proc.port_add(body['port'], body['rx'], body['tx']) + else: + proc.port_add(body['port']) else: proc.port_del(body['port']) -- 2.17.1
This patch adds add pipe command to the primary. Infomation about pipe is added to the output of status command of the primary too. Signed-off-by: Itsuro Oda <oda@valinux.co.jp> --- src/cli/commands/pri.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/cli/commands/pri.py b/src/cli/commands/pri.py index dbe56d5..6fc7f00 100644 --- a/src/cli/commands/pri.py +++ b/src/cli/commands/pri.py @@ -229,6 +229,12 @@ class SppPrimary(object): else: print(' - {} -> {}'.format(port, dst)) + if ('pipes' in json_obj): + print(' - pipes:') + for pipe in json_obj['pipes']: + print(' - pipe:{} ring:{} ring:{}'.format(pipe['id'], + pipe['rx'], pipe['tx'])) + if ('phy_ports' in json_obj) or ('ring_ports' in json_obj): print('- stats') @@ -798,6 +804,10 @@ class SppPrimary(object): print("'%s' is already added." % params[0]) else: req_params = {'action': 'add', 'port': params[0]} + if len(params) == 3: + # add pipe:X ring:A ring:B + req_params['rx'] = params[1] + req_params['tx'] = params[2] res = self.spp_ctl_cli.put('primary/ports', req_params) if res is not None: -- 2.17.1