1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132#! /usr/bin/python
'''
Copyright 2016 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
'''
from cmd import Cmd
import os
import subprocess
import re
import sys
from optparse import OptionParser
try:
import readline
except ImportError:
readline = None
persishist = os.path.expanduser('~/.vpphistory')
persishist_size = 1000
if not persishist:
os.mknod(persishist, stat.S_IFREG)
class Vppctl(Cmd):
def __init__(self,api_prefix=None):
Cmd.__init__(self)
self.api_prefix = api_prefix
def historyWrite(self):
if readline:
readline.set_history_length(persishist_size)
readline.write_history_file(persishist)
def runVat(self, line):
input_prefix = "exec "
input_command = input_prefix + line
line_remove = '^load_one_plugin:'
s = '\n'
if ( self.api_prefix is None):
command = ['vpp_api_test']
else:
command = ['vpp_api_test',"chroot prefix %s " % self.api_prefix]
if os.geteuid() != 0:
command = ['sudo'] + command
vpp_process = subprocess.Popen(command,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
stdout_value = vpp_process.communicate(input_command)[0]
buffer_stdout = stdout_value.splitlines()
buffer_stdout[:] = [b for b in buffer_stdout
if line_remove not in b]
for i, num in enumerate(buffer_stdout):
buffer_stdout[i] = num.replace('vat# ','')
stdout_value = s.join(buffer_stdout)
print stdout_value
def do_help(self, line):
self.runVat("help")
def default(self, line):
self.runVat(line)
def do_exit(self, line):
self.historyWrite()
raise SystemExit
def emptyline(self):
pass
def do_EOF(self,line):
self.historyWrite()
sys.stdout.write('\n')
raise SystemExit
def preloop(self):
if readline and os.path.exists(persishist
@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
/* SPDX-License-Identifier: Apache-2.0
* Copyright (c) 2023 Cisco Systems, Inc.
*/
#include <vnet/vnet.h>
#include <vnet/ethernet/ethernet.h>
#include <vnet/dev/dev.h>
#include <vnet/dev/counters.h>
#include <vnet/dev/log.h>
VLIB_REGISTER_LOG_CLASS (dev_log, static) = {
.class_name = "dev",
.subclass_name = "port",
};
static uword
dummy_input_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_frame_t *frame)
{
ASSERT (0);
return 0;
}
VLIB_REGISTER_NODE (port_rx_eth_node) = {
.function = dummy_input_fn,
.name = "port-rx-eth",
.runtime_data_bytes = sizeof (vnet_dev_rx_node_runtime_t),
.type = VLIB_NODE_TYPE_INPUT,
.state = VLIB_NODE_STATE_DISABLED,
.n_next_nodes = VNET_DEV_ETH_RX_PORT_N_NEXTS,
.next_nodes = {
#define _(n, s) [VNET_DEV_ETH_RX_PORT_NEXT_##n] = s,
foreach_vnet_dev_port_rx_next
#undef _
},
};
u16 vnet_dev_default_next_index_by_port_type[] = {
[VNET_DEV_PORT_TYPE_ETHERNET] = VNET_DEV_ETH_RX_PORT_NEXT_ETH_INPUT,
};
VNET_FEATURE_ARC_INIT (eth_port_rx, static) = {
.arc_name = "port-rx-eth",
.start_nodes = VNET_FEATURES ("port-rx-eth"),
.last_in_arc = "ethernet-input",
.arc_index_ptr = &vnet_dev_main.eth_port_rx_feature_arc_index,
};
VNET_FEATURE_INIT (l2_patch, static) = {
.arc_name = "port-rx-eth",
.node_name = "l2-patch",
.runs_before = VNET_FEATURES ("ethernet-input"),
};
VNET_FEATURE_INIT (worker_handoff, static) = {
.arc_name = "port-rx-eth",
.node_name = "worker-handoff",
.runs_before = VNET_FEATURES ("ethernet-input"),
};
VNET_FEATURE_INIT (span_input, static) = {
.arc_name = "port-rx-eth",
.node_name = "span-input",
.runs_before = VNET_FEATURES ("ethernet-input"),
};
VNET_FEATURE_INIT (p2p_ethernet_node, static) = {
.arc_name = "port-rx-eth",
.node_name = "p2p-ethernet-input",
.runs_before = VNET_FEATURES ("ethernet-input"),
};
VNET_FEATURE_INIT (ethernet_input, static) = {
.arc_name = "port-rx-eth",
.node_name = "ethernet-input",
.runs_before = 0, /* not before any other features */
};
void
vnet_dev_port_free (vlib_main_t *vm, vnet_dev_port_t *port)
{
vnet_dev_t *dev = port->dev;
vnet_dev_port_validate (vm, port);
ASSERT (port->started == 0);
log_debug (dev, "port %u", port->port_id);
if (port->port_ops.free)
port->port_ops.free (vm, port);
pool_free (port->secondary_hw_addr);
pool_free (port->rx_queues);
pool_free (port->tx_queues);
pool_put_index (dev->ports, port->index);
clib_mem_free (port);
}
void
vnet_dev_port_update_tx_node_runtime (vlib_main_t *vm, vnet_dev_port_t *port)
{
vnet_dev_port_validate (vm, port);
foreach_vnet_dev_port_tx_queue (q, port)
{
u32 ti;
clib_bitmap_foreach (ti, q->assigned_threads)
{
vlib_main_t *tvm = vlib_get_main_by_index (ti);
vlib_node_runtime_t *nr =
vlib_node_get_runtime (tvm, port->intf.tx_node_index);
vnet_dev_tx_node_runtime_t *tnr = vnet_dev_get_tx_node_runtime (nr);
tnr->hw_if_index = port->intf.hw_if_index;
tnr->tx_queue = q;
}
}
}
void
vnet_dev_port_stop (vlib_main_t *vm, vnet_dev_port_t *port)
{
vnet_dev_t *dev = port->dev;
vnet_dev_rt_op_t *ops = 0;
u16 n_threads = vlib_get_n_threads ();
log_debug (dev, "stopping port %u", port->port_id);
for (u16 i = 0; i < n_threads; i++)
{
vnet_dev_rt_op_t op = { .thread_index = i, .port = port };
vec_add1 (ops, op);
}
vnet_dev_rt_exec_ops (vm, dev, ops, vec_len (ops));
vec_free (ops);
port->port_ops.stop (vm, port);
foreach_vnet_dev_port_rx_queue (q, port)
{
q->started = 0;
log_debug (dev, "port %u rx queue %u stopped", port->port_id,
q->queue_id);
}
foreach_vnet_dev_port_tx_queue (q, port)
{
q->started = 0;
log_debug (dev, "port %u tx queue %u stopped", port->port_id,
q->queue_id);
}
log_debug (dev, "port %u stopped", port->port_id);
port->started = 0;
}
vnet_dev_rv_t
vnet_dev_port_start_all_rx_queues (vlib_main_t *vm, vnet_dev_port_t *port)
{
vnet_dev_rv_t rv = VNET_DEV_OK;
vnet_dev_port_validate (vm, port);
foreach_vnet_dev_port_rx_queue (q, port)
{
rv = vnet_dev_rx_queue_start (vm, q);
if (rv != VNET_DEV_OK)
return rv;
}
return rv;
}
vnet_dev_rv_t
vnet_dev_port_start_all_tx_queues (vlib_main_t *vm, vnet_dev_port_t *port)
{
vnet_dev_rv_t rv = VNET_DEV_OK;
vnet_dev_port_validate (vm, port);
foreach_vnet_dev_port_tx_queue (q, port)
{
rv = vnet_dev_tx_queue_start (vm, q);
if (rv != VNET_DEV_OK)
return rv;
}
return rv;
}
vnet_dev_rv_t
vnet_dev_port_start (vlib_main_t *vm, vnet_dev_port_t *port)
{
u16 n_threads = vlib_get_n_threads ();
vnet_dev_t *dev = port->dev;
vnet_dev_rt_op_t *ops = 0;
vnet_dev_rv_t rv;
vnet_dev_port_validate (vm, port);
log_debug (dev, "starting port %u", port->port_id);
vnet_dev_port_update_tx_node_runtime (vm, port);
if ((rv = port->port_ops.start (vm, port)) != VNET_DEV_OK)
{
vnet_dev_port_stop (vm, port);
return rv;
}
for (u16 i = 0; i < n_threads; i++)
{
vnet_dev_rt_op_t op = { .thread_index = i, .port = port };
vec_add1 (ops, op);
}
vnet_dev_rt_exec_ops (vm, dev, ops, vec_len (ops));
vec_free (ops);
foreach_vnet_dev_port_rx_queue (q, port)
if (q->enabled)
{
log_debug (dev, "port %u rx queue %u started", port->port_id,
q->queue_id);
q->started = 1;
}
foreach_vnet_dev_port_tx_queue (q, port)
if (q->enabled)
{
log_debug (dev, "port %u tx queue %u started", port->port_id,
q->queue_id);
q->started = 1;
}
port->started = 1;
log_debug (dev, "port %u started", port->port_id);
return VNET_DEV_OK;
}
vnet_dev_rv_t
vnet_dev_port_add (vlib_main_t *vm, vnet_dev_t *dev, vnet_dev_port_id_t id,
vnet_dev_port_add_args_t *args)
{
vnet_dev_port_t **pp, *port;
vnet_dev_rv_t rv = VNET_DEV_OK;
ASSERT (args->port.attr.type != VNET_DEV_PORT_TYPE_UNKNOWN);
ASSERT (args->port.attr.max_supported_frame_size);
port =
vnet_dev_alloc_with_data (sizeof (vnet_dev_port_t), args->port.data_size);
pool_get (dev->ports, pp);
pp[0] = port;
clib_memcpy (vnet_dev_get_port_data (port), args->port.initial_data,
args->port.data_size);
port->port_id = id;
port->index = pp - dev->ports;
port->dev = dev;
port->attr = args->port.attr;
port->rx_queue_config = args->rx_queue.config;
port->tx_queue_config = args->tx_queue.config;
port->rx_queue_ops = args->rx_queue.ops;
port->tx_queue_ops = args->tx_queue.ops;
port->port_ops = args->port.ops;
port->rx_node = *args->rx_node;
port->tx_node = *args->tx_node;
/* defaults out of port attributes */
port->max_frame_size = args->port.attr.max_supported_frame_size;
port->primary_hw_addr = args->port.attr.hw_addr;
if (port->port_ops.alloc)
rv = port->port_ops.alloc (vm, port);
if (rv == VNET_DEV_OK)
port->initialized = 1;
return rv;
}
vnet_dev_rv_t
vnet_dev_port_cfg_change_req_validate (vlib_main_t *vm, vnet_dev_port_t *port,
vnet_dev_port_cfg_change_req_t *req)
{
vnet_dev_rv_t rv;
vnet_dev_hw_addr_t *addr;
int found;
if (req->validated)
return VNET_DEV_OK;
switch (req->type)
{
case VNET_DEV_PORT_CFG_MAX_FRAME_SIZE:
if (req->max_frame_size > port->attr.max_supported_frame_size)
return VNET_DEV_ERR_INVALID_VALUE;
if (req->max_frame_size == port->max_frame_size)
return VNET_DEV_ERR_NO_CHANGE;
break;
case VNET_DEV_PORT_CFG_PROMISC_MODE:
if (req->promisc == port->promisc)
return VNET_DEV_ERR_NO_CHANGE;
break;
case VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR:
if (clib_memcmp (&req->addr, &port->primary_hw_addr,
sizeof (vnet_dev_hw_addr_t)) == 0)
return VNET_DEV_ERR_NO_CHANGE;
break;
case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
pool_foreach (addr, port->secondary_hw_addr)
if (clib_memcmp (addr, &req->addr, sizeof (*addr)) == 0)
return VNET_DEV_ERR_ALREADY_EXISTS;
break;
case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
found = 0;
pool_foreach (addr, port->secondary_hw_addr)
if (clib_memcmp (addr, &req->addr, sizeof (*addr)) == 0)
found = 1;
if (!found)
return VNET_DEV_ERR_NO_SUCH_ENTRY;
break;
default:
break;
}
if (port->port_ops.config_change_validate)
{
rv = port->port_ops.config_change_validate (vm, port, req);
if (rv != VNET_DEV_OK)
return rv;
}
req->validated = 1;
return VNET_DEV_OK;
}
vnet_dev_rv_t
vnet_dev_port_cfg_change (vlib_main_t *vm, vnet_dev_port_t *port,
vnet_dev_port_cfg_change_req_t *req)
{
vnet_dev_rv_t rv = VNET_DEV_OK;
vnet_dev_hw_addr_t *a;
vnet_dev_rx_queue_t *rxq = 0;
u8 enable = 0;
vnet_dev_port_validate (vm, port);
if (req->type == VNET_DEV_PORT_CFG_RXQ_INTR_MODE_ENABLE ||
req->type == VNET_DEV_PORT_CFG_RXQ_INTR_MODE_DISABLE)
{
if (req->all_queues == 0)
{
rxq = vnet_dev_port_get_rx_queue_by_id (port, req->queue_id);
if (rxq == 0)
return VNET_DEV_ERR_BUG;
}
}
if ((rv = vnet_dev_port_cfg_change_req_validate (vm, port, req)))
return rv;
if (port->port_ops.config_change)
rv = port->port_ops.config_change (vm, port, req);
if (rv != VNET_DEV_OK)
return rv;
switch (req->type)
{
case VNET_DEV_PORT_CFG_MAX_FRAME_SIZE:
port->max_frame_size = req->max_frame_size;
break;
case VNET_DEV_PORT_CFG_PROMISC_MODE:
port->promisc = req->promisc;
break;
case VNET_DEV_PORT_CFG_RXQ_INTR_MODE_ENABLE:
enable = 1;
case VNET_DEV_PORT_CFG_RXQ_INTR_MODE_DISABLE:
if (req->all_queues)
{
clib_bitmap_t *bmp = 0;
vnet_dev_rt_op_t *ops = 0;
u32 i;
foreach_vnet_dev_port_rx_queue (q, port)
{
q->interrupt_mode = enable;
bmp = clib_bitmap_set (bmp, q->rx_thread_index, 1);
}
clib_bitmap_foreach (i, bmp)
{
vnet_dev_rt_op_t op = { .port = port, .thread_index = i };
vec_add1 (ops, op);
}
vnet_dev_rt_exec_ops (vm, port->dev, ops, vec_len (ops));
clib_bitmap_free (bmp);
vec_free (ops);
}
else
{
rxq->interrupt_mode = enable;
vnet_dev_rt_exec_ops (vm, port->dev,
&(vnet_dev_rt_op_t){
.port = port,
.thread_index = rxq->rx_thread_index,
},
1);
}
break;
case VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR:
clib_memcpy (&port->primary_hw_addr, &req->addr,
sizeof (vnet_dev_hw_addr_t));
break;
case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
pool_get (port->secondary_hw_addr, a);
clib_memcpy (a, &req->addr, sizeof (vnet_dev_hw_addr_t));
break;
case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
pool_foreach (a, port->secondary_hw_addr)
if (clib_memcmp (a, &req->addr, sizeof (vnet_dev_hw_addr_t)) == 0)
{
pool_put (port->secondary_hw_addr, a);
break;
}
break;
default:
break;
}
return VNET_DEV_OK;
}
void
vnet_dev_port_state_change (vlib_main_t *vm, vnet_dev_port_t *port,
vnet_dev_port_state_changes_t changes)
{
vnet_main_t *vnm = vnet_get_main ();
vnet_dev_port_validate (vm, port);
if (changes.change.link_speed)
{
port->speed = changes.link_speed;
if (port->interface_created)
vnet_hw_interface_set_link_speed (vnm, port->intf.hw_if_index,
changes.link_speed);
log_debug (port->dev, "port speed changed to %u", changes.link_speed);
}
if (changes.change.link_state)
{
port->link_up = changes.link_state;
if (port->interface_created)
vnet_hw_interface_set_flags (
vnm, port->intf.hw_if_index,
changes.link_state ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
log_debug (port->dev, "port link state changed to %s",
changes.link_state ? "up" : "down");
}
}
void
vnet_dev_port_add_counters (vlib_main_t *vm, vnet_dev_port_t *port,
vnet_dev_counter_t *counters, u16 n_counters)
{
vnet_dev_port_validate (vm, port);
port->counter_main =
vnet_dev_counters_alloc (vm, counters, n_counters, "%s port %u counters",
port->dev->device_id, port->port_id);
}
void
vnet_dev_port_free_counters (vlib_main_t *vm, vnet_dev_port_t *port)
{
vnet_dev_port_validate (vm, port);
if (port->counter_main)
vnet_dev_counters_free (vm, port->counter_main);
}
vnet_dev_rv_t
vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port)
{
vnet_main_t *vnm = vnet_get_main ();
u16 n_threads = vlib_get_n_threads ();
vnet_dev_main_t *dm = &vnet_dev_main;
vnet_dev_t *dev = port->dev;
vnet_dev_port_t **pp;
vnet_dev_rv_t rv;
u16 ti = 0;
if (port->intf.name[0] == 0)
{
u8 *s;
s = format (0, "%s%u/%u",
dm->drivers[port->dev->driver_index].registration->name,
port->dev->index, port->index);
u32 n = vec_len (s);
if (n >= sizeof (port->intf.name))
{
vec_free (s);
return VNET_DEV_ERR_BUG;
}
clib_memcpy (port->intf.name, s, n);
port->intf.name[n] = 0;
vec_free (s);
}
log_debug (
dev, "allocating %u rx queues with size %u and %u tx queues with size %u",
port->intf.num_rx_queues, port->intf.rxq_sz, port->intf.num_tx_queues,
port->intf.txq_sz);
for (int i = 0; i < port->intf.num_rx_queues; i++)
if ((rv = vnet_dev_rx_queue_alloc (vm, port, port->intf.rxq_sz)) !=
VNET_DEV_OK)
goto error;
for (u32 i = 0; i < port->intf.num_tx_queues; i++)
if ((rv = vnet_dev_tx_queue_alloc (vm, port, port->intf.txq_sz)) !=
VNET_DEV_OK)
goto error;
foreach_vnet_dev_port_tx_queue (q, port)
{
q->assigned_threads = clib_bitmap_set (q->assigned_threads, ti, 1);
log_debug (dev, "port %u tx queue %u assigned to thread %u",
port->port_id, q->queue_id, ti);
if (++ti >= n_threads)
break;
}
/* pool of port pointers helps us to assign unique dev_instance */
pool_get (dm->ports_by_dev_instance, pp);
port->intf.dev_instance = pp - dm->ports_by_dev_instance;
pp[0] = port;
if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET)
{
vnet_device_class_t *dev_class;
vnet_dev_driver_t *driver;
vnet_sw_interface_t *sw;
vnet_hw_interface_t *hw;
u32 rx_node_index;
driver = pool_elt_at_index (dm->drivers, dev->driver_index);
/* hack to provide per-port tx node function */
dev_class = vnet_get_device_class (vnm, driver->dev_class_index);
dev_class->tx_fn_registrations = port->tx_node.registrations;
dev_class->format_tx_trace = port->tx_node.format_trace;
dev_class->tx_function_error_counters = port->tx_node.error_counters;
dev_class->tx_function_n_errors = port->tx_node.n_error_counters;
/* create new interface including tx and output nodes */
port->intf.hw_if_index = vnet_eth_register_interface (
vnm, &(vnet_eth_interface_registration_t){
.address = port->primary_hw_addr.eth_mac,
.max_frame_size = port->max_frame_size,
.dev_class_index = driver->dev_class_index,
.dev_instance = port->intf.dev_instance,
.cb.set_max_frame_size = vnet_dev_port_set_max_frame_size,
.cb.flag_change = vnet_dev_port_eth_flag_change,
});
sw = vnet_get_hw_sw_interface (vnm, port->intf.hw_if_index);
hw = vnet_get_hw_interface (vnm, port->intf.hw_if_index);
port->intf.sw_if_index = sw->sw_if_index;
vnet_hw_interface_set_flags (
vnm, port->intf.hw_if_index,
port->link_up ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
if (port->speed)
vnet_hw_interface_set_link_speed (vnm, port->intf.hw_if_index,
port->speed);
port->intf.tx_node_index = hw->tx_node_index;
/* create / reuse rx node */
if (vec_len (dm->free_rx_node_indices))
{
vlib_node_t *n;
rx_node_index = vec_pop (dm->free_rx_node_indices);
vlib_node_rename (vm, rx_node_index, "%s-rx", port->intf.name);
n = vlib_get_node (vm, rx_node_index);
n->function = vlib_node_get_preferred_node_fn_variant (
vm, port->rx_node.registrations);
n->format_trace = port->rx_node.format_trace;
vlib_register_errors (vm, rx_node_index,
port->rx_node.n_error_counters, 0,
port->rx_node.error_counters);
}
else
{
dev_class->format_tx_trace = port->tx_node.format_trace;
dev_class->tx_function_error_counters = port->tx_node.error_counters;
dev_class->tx_function_n_errors = port->tx_node.n_error_counters;
vlib_node_registration_t rx_node_reg = {
.sibling_of = "port-rx-eth",
.type = VLIB_NODE_TYPE_INPUT,
.state = VLIB_NODE_STATE_DISABLED,
.flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
.node_fn_registrations = port->rx_node.registrations,
.format_trace = port->rx_node.format_trace,
.error_counters = port->rx_node.error_counters,
.n_errors = port->rx_node.n_error_counters,
};
rx_node_index =
vlib_register_node (vm, &rx_node_reg, "%s-rx", port->intf.name);
}
port->rx_node_assigned = 1;
port->intf.rx_node_index = rx_node_index;
port->intf.rx_next_index =
vnet_dev_default_next_index_by_port_type[port->attr.type];
vlib_worker_thread_node_runtime_update ();
log_debug (dev,
"ethernet interface created, hw_if_index %u sw_if_index %u "
"rx_node_index %u tx_node_index %u",
port->intf.hw_if_index, port->intf.sw_if_index,
port->intf.rx_node_index, port->intf.tx_node_index);
}
port->interface_created = 1;
foreach_vnet_dev_port_rx_queue (q, port)
{
vnet_buffer (&q->buffer_template)->sw_if_index[VLIB_RX] =
port->intf.sw_if_index;
/* poison to catch node not calling runtime update function */
q->next_index = ~0;
q->interrupt_mode = port->intf.default_is_intr_mode;
vnet_dev_rx_queue_rt_request (
vm, q, (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1 });
}
vnet_dev_port_update_tx_node_runtime (vm, port);
if (port->port_ops.init)
rv = port->port_ops.init (vm, port);
error:
if (rv != VNET_DEV_OK)
vnet_dev_port_if_remove (vm, port);
return rv;
}
vnet_dev_rv_t
vnet_dev_port_if_remove (vlib_main_t *vm, vnet_dev_port_t *port)
{
vnet_dev_main_t *dm = &vnet_dev_main;
vnet_main_t *vnm = vnet_get_main ();
vnet_dev_port_validate (vm, port);
if (port->started)
vnet_dev_port_stop (vm, port);
if (port->rx_node_assigned)
{
vlib_node_rename (vm, port->intf.rx_node_index, "deleted-%u",
port->intf.rx_node_index);
vec_add1 (dm->free_rx_node_indices, port->intf.rx_node_index);
port->rx_node_assigned = 0;
}
if (port->interface_created)
{
vlib_worker_thread_barrier_sync (vm);
vnet_delete_hw_interface (vnm, port->intf.hw_if_index);
vlib_worker_thread_barrier_release (vm);
pool_put_index (dm->ports_by_dev_instance, port->intf.dev_instance);
port->interface_created = 0;
}
port->intf = (typeof (port->intf)){};
if (port->port_ops.deinit)
port->port_ops.deinit (vm, port);
foreach_vnet_dev_port_tx_queue (q, port)
vnet_dev_tx_queue_free (vm, q);
foreach_vnet_dev_port_rx_queue (q, port)
vnet_dev_rx_queue_free (vm, q);
vnet_dev_port_free_counters (vm, port);
return VNET_DEV_OK;
}
void
vnet_dev_port_clear_counters (vlib_main_t *vm, vnet_dev_port_t *port)
{
if (port->counter_main)
vnet_dev_counters_clear (vm, port->counter_main);
foreach_vnet_dev_port_rx_queue (q, port)
if (q->counter_main)
vnet_dev_counters_clear (vm, q->counter_main);
foreach_vnet_dev_port_tx_queue (q, port)
if (q->counter_main)
vnet_dev_counters_clear (vm, q->counter_main);
log_notice (port->dev, "counters cleared on port %u", port->port_id);
}
|