2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-29 05:18:13 +00:00

Implement QoS framework.

ovs-vswitchd doesn't declare its QoS capabilities in the database yet,
so the controller has to know what they are.  We can add that later.

The linux-htb QoS class has been tested to the extent that I can see that
it sets up the queues I expect when I run "tc qdisc show" and "tc class
show".  I haven't tested that the effects on flows are what we expect them
to be.  I am sure that there will be problems in that area that we will
have to fix.
This commit is contained in:
Ben Pfaff 2010-06-17 15:04:12 -07:00
parent a90b56b770
commit c1c9c9c4b6
18 changed files with 2730 additions and 99 deletions

View File

@ -444,6 +444,7 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
* then freeing the original skbuff is wasteful. So the following code * then freeing the original skbuff is wasteful. So the following code
* is slightly obscure just to avoid that. */ * is slightly obscure just to avoid that. */
int prev_port = -1; int prev_port = -1;
u32 priority = skb->priority;
int err; int err;
if (dp->sflow_probability) { if (dp->sflow_probability) {
@ -516,6 +517,14 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
case ODPAT_SET_TP_DST: case ODPAT_SET_TP_DST:
skb = set_tp_port(skb, key, &a->tp_port, gfp); skb = set_tp_port(skb, key, &a->tp_port, gfp);
break; break;
case ODPAT_SET_PRIORITY:
skb->priority = a->priority.priority;
break;
case ODPAT_POP_PRIORITY:
skb->priority = priority;
break;
} }
if (!skb) if (!skb)
return -ENOMEM; return -ENOMEM;

View File

@ -419,6 +419,18 @@ struct ofp_action_header {
}; };
OFP_ASSERT(sizeof(struct ofp_action_header) == 8); OFP_ASSERT(sizeof(struct ofp_action_header) == 8);
/* OFPAT_ENQUEUE action struct: send packets to given queue on port. */
struct ofp_action_enqueue {
uint16_t type; /* OFPAT_ENQUEUE. */
uint16_t len; /* Len is 16. */
uint16_t port; /* Port that queue belongs. Should
refer to a valid physical port
(i.e. < OFPP_MAX) or OFPP_IN_PORT. */
uint8_t pad[6]; /* Pad for 64-bit alignment. */
uint32_t queue_id; /* Where to enqueue the packets. */
};
OFP_ASSERT(sizeof(struct ofp_action_enqueue) == 16);
union ofp_action { union ofp_action {
uint16_t type; uint16_t type;
struct ofp_action_header header; struct ofp_action_header header;
@ -713,8 +725,8 @@ enum ofp_stats_types {
OFPST_PORT, OFPST_PORT,
/* Queue statistics for a port /* Queue statistics for a port
* The request body defines the port * The request body is struct ofp_queue_stats_request.
* The reply body is an array of struct ofp_queue_stats */ * The reply body is an array of struct ofp_queue_stats. */
OFPST_QUEUE, OFPST_QUEUE,
/* Vendor extension. /* Vendor extension.
@ -859,6 +871,29 @@ struct ofp_port_stats {
}; };
OFP_ASSERT(sizeof(struct ofp_port_stats) == 104); OFP_ASSERT(sizeof(struct ofp_port_stats) == 104);
/* All ones is used to indicate all queues in a port (for stats retrieval). */
#define OFPQ_ALL 0xffffffff
/* Body for ofp_stats_request of type OFPST_QUEUE. */
struct ofp_queue_stats_request {
uint16_t port_no; /* All ports if OFPP_ALL. */
uint8_t pad[2]; /* Align to 32-bits. */
uint32_t queue_id; /* All queues if OFPQ_ALL. */
};
OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 8);
/* Body for ofp_stats_reply of type OFPST_QUEUE consists of an array of this
* structure type. */
struct ofp_queue_stats {
uint16_t port_no;
uint8_t pad[2]; /* Align to 32-bits. */
uint32_t queue_id; /* Queue id. */
uint64_t tx_bytes; /* Number of transmitted bytes. */
uint64_t tx_packets; /* Number of transmitted packets. */
uint64_t tx_errors; /* Number of packets dropped due to overrun. */
};
OFP_ASSERT(sizeof(struct ofp_queue_stats) == 32);
/* Vendor extension. */ /* Vendor extension. */
struct ofp_vendor_header { struct ofp_vendor_header {
struct ofp_header header; /* Type OFPT_VENDOR. */ struct ofp_header header; /* Type OFPT_VENDOR. */

View File

@ -279,7 +279,9 @@ struct odp_flowvec {
#define ODPAT_SET_TP_SRC 11 /* TCP/UDP source port. */ #define ODPAT_SET_TP_SRC 11 /* TCP/UDP source port. */
#define ODPAT_SET_TP_DST 12 /* TCP/UDP destination port. */ #define ODPAT_SET_TP_DST 12 /* TCP/UDP destination port. */
#define ODPAT_SET_TUNNEL 13 /* Set the encapsulating tunnel ID. */ #define ODPAT_SET_TUNNEL 13 /* Set the encapsulating tunnel ID. */
#define ODPAT_N_ACTIONS 14 #define ODPAT_SET_PRIORITY 14 /* Set skb->priority. */
#define ODPAT_POP_PRIORITY 15 /* Restore original skb->priority. */
#define ODPAT_N_ACTIONS 16
struct odp_action_output { struct odp_action_output {
uint16_t type; /* ODPAT_OUTPUT. */ uint16_t type; /* ODPAT_OUTPUT. */
@ -353,6 +355,13 @@ struct odp_action_tp_port {
uint16_t reserved2; uint16_t reserved2;
}; };
/* Action structure for ODPAT_SET_PRIORITY. */
struct odp_action_priority {
uint16_t type; /* ODPAT_SET_PRIORITY. */
uint16_t reserved;
uint32_t priority; /* skb->priority value. */
};
union odp_action { union odp_action {
uint16_t type; uint16_t type;
struct odp_action_output output; struct odp_action_output output;
@ -365,6 +374,7 @@ union odp_action {
struct odp_action_nw_addr nw_addr; struct odp_action_nw_addr nw_addr;
struct odp_action_nw_tos nw_tos; struct odp_action_nw_tos nw_tos;
struct odp_action_tp_port tp_port; struct odp_action_tp_port tp_port;
struct odp_action_priority priority;
}; };
struct odp_execute { struct odp_execute {

View File

@ -256,7 +256,18 @@ const struct netdev_class netdev_gre_class = {
NULL, /* get_features */ NULL, /* get_features */
NULL, /* set_advertisements */ NULL, /* set_advertisements */
NULL, /* get_vlan_vid */ NULL, /* get_vlan_vid */
NULL, /* set_policing */ NULL, /* set_policing */
NULL, /* get_qos_types */
NULL, /* get_qos_capabilities */
NULL, /* get_qos */
NULL, /* set_qos */
NULL, /* get_queue */
NULL, /* set_queue */
NULL, /* delete_queue */
NULL, /* get_queue_stats */
NULL, /* dump_queues */
NULL, /* dump_queue_stats */
NULL, /* get_in4 */ NULL, /* get_in4 */
NULL, /* set_in4 */ NULL, /* set_in4 */

File diff suppressed because it is too large Load Diff

View File

@ -207,7 +207,18 @@ const struct netdev_class netdev_patch_class = {
NULL, /* get_features */ NULL, /* get_features */
NULL, /* set_advertisements */ NULL, /* set_advertisements */
NULL, /* get_vlan_vid */ NULL, /* get_vlan_vid */
NULL, /* set_policing */ NULL, /* set_policing */
NULL, /* get_qos_types */
NULL, /* get_qos_capabilities */
NULL, /* get_qos */
NULL, /* set_qos */
NULL, /* get_queue */
NULL, /* set_queue */
NULL, /* delete_queue */
NULL, /* get_queue_stats */
NULL, /* dump_queues */
NULL, /* dump_queue_stats */
NULL, /* get_in4 */ NULL, /* get_in4 */
NULL, /* set_in4 */ NULL, /* set_in4 */

View File

@ -313,6 +313,155 @@ struct netdev_class {
int (*set_policing)(struct netdev *netdev, unsigned int kbits_rate, int (*set_policing)(struct netdev *netdev, unsigned int kbits_rate,
unsigned int kbits_burst); unsigned int kbits_burst);
/* Adds to 'types' all of the forms of QoS supported by 'netdev', or leaves
* it empty if 'netdev' does not support QoS. Any names added to 'types'
* should be documented as valid for the "type" column in the "QoS" table
* in vswitchd/vswitch.xml (which is built as ovs-vswitchd.conf.db(8)).
*
* Every network device must support disabling QoS with a type of "", but
* this function must not add "" to 'types'.
*
* The caller is responsible for initializing 'types' (e.g. with
* svec_init()) before calling this function. The caller takes ownership
* of the strings added to 'types'.
*
* May be NULL if 'netdev' does not support QoS at all. */
int (*get_qos_types)(const struct netdev *netdev, struct svec *types);
/* Queries 'netdev' for its capabilities regarding the specified 'type' of
* QoS. On success, initializes 'caps' with the QoS capabilities.
*
* Should return EOPNOTSUPP if 'netdev' does not support 'type'. May be
* NULL if 'netdev' does not support QoS at all. */
int (*get_qos_capabilities)(const struct netdev *netdev,
const char *type,
struct netdev_qos_capabilities *caps);
/* Queries 'netdev' about its currently configured form of QoS. If
* successful, stores the name of the current form of QoS into '*typep'
* and any details of configuration as string key-value pairs in
* 'details'.
*
* A '*typep' of "" indicates that QoS is currently disabled on 'netdev'.
*
* The caller initializes 'details' before calling this function. The
* caller takes ownership of the string key-values pairs added to
* 'details'.
*
* The netdev retains ownership of '*typep'.
*
* '*typep' will be one of the types returned by netdev_get_qos_types() for
* 'netdev'. The contents of 'details' should be documented as valid for
* '*typep' in the "other_config" column in the "QoS" table in
* vswitchd/vswitch.xml (which is built as ovs-vswitchd.conf.db(8)).
*
* May be NULL if 'netdev' does not support QoS at all. */
int (*get_qos)(const struct netdev *netdev,
const char **typep, struct shash *details);
/* Attempts to reconfigure QoS on 'netdev', changing the form of QoS to
* 'type' with details of configuration from 'details'.
*
* On error, the previous QoS configuration is retained.
*
* When this function changes the type of QoS (not just 'details'), this
* also resets all queue configuration for 'netdev' to their defaults
* (which depend on the specific type of QoS). Otherwise, the queue
* configuration for 'netdev' is unchanged.
*
* 'type' should be "" (to disable QoS) or one of the types returned by
* netdev_get_qos_types() for 'netdev'. The contents of 'details' should
* be documented as valid for the given 'type' in the "other_config" column
* in the "QoS" table in vswitchd/vswitch.xml (which is built as
* ovs-vswitchd.conf.db(8)).
*
* May be NULL if 'netdev' does not support QoS at all. */
int (*set_qos)(struct netdev *netdev,
const char *type, const struct shash *details);
/* Queries 'netdev' for information about the queue numbered 'queue_id'.
* If successful, adds that information as string key-value pairs to
* 'details'. Returns 0 if successful, otherwise a positive errno value.
*
* Should return EINVAL if 'queue_id' is greater than or equal to the
* number of supported queues (as reported in the 'n_queues' member of
* struct netdev_qos_capabilities by 'get_qos_capabilities').
*
* The caller initializes 'details' before calling this function. The
* caller takes ownership of the string key-values pairs added to
* 'details'.
*
* The returned contents of 'details' should be documented as valid for the
* given 'type' in the "other_config" column in the "Queue" table in
* vswitchd/vswitch.xml (which is built as ovs-vswitchd.conf.db(8)).
*/
int (*get_queue)(const struct netdev *netdev,
unsigned int queue_id, struct shash *details);
/* Configures the queue numbered 'queue_id' on 'netdev' with the key-value
* string pairs in 'details'. The contents of 'details' should be
* documented as valid for the given 'type' in the "other_config" column in
* the "Queue" table in vswitchd/vswitch.xml (which is built as
* ovs-vswitchd.conf.db(8)). Returns 0 if successful, otherwise a positive
* errno value. On failure, the given queue's configuration should be
* unmodified.
*
* Should return EINVAL if 'queue_id' is greater than or equal to the
* number of supported queues (as reported in the 'n_queues' member of
* struct netdev_qos_capabilities by 'get_qos_capabilities'), or if
* 'details' is invalid for the type of queue.
*
* This function does not modify 'details', and the caller retains
* ownership of it.
*
* May be NULL if 'netdev' does not support QoS at all. */
int (*set_queue)(struct netdev *netdev,
unsigned int queue_id, const struct shash *details);
/* Attempts to delete the queue numbered 'queue_id' from 'netdev'.
*
* Should return EINVAL if 'queue_id' is greater than or equal to the
* number of supported queues (as reported in the 'n_queues' member of
* struct netdev_qos_capabilities by 'get_qos_capabilities'). Should
* return EOPNOTSUPP if 'queue_id' is valid but may not be deleted (e.g. if
* 'netdev' has a fixed set of queues with the current QoS mode).
*
* May be NULL if 'netdev' does not support QoS at all, or if all of its
* QoS modes have fixed sets of queues. */
int (*delete_queue)(struct netdev *netdev, unsigned int queue_id);
/* Obtains statistics about 'queue_id' on 'netdev'. Fills 'stats' with the
* queue's statistics. May set individual members of 'stats' to all-1-bits
* if the statistic is unavailable.
*
* May be NULL if 'netdev' does not support QoS at all. */
int (*get_queue_stats)(const struct netdev *netdev, unsigned int queue_id,
struct netdev_queue_stats *stats);
/* Iterates over all of 'netdev''s queues, calling 'cb' with the queue's
* ID, its configuration, and the 'aux' specified by the caller. The order
* of iteration is unspecified, but (when successful) each queue is visited
* exactly once.
*
* 'cb' will not modify or free the 'details' argument passed in. */
int (*dump_queues)(const struct netdev *netdev,
void (*cb)(unsigned int queue_id,
const struct shash *details,
void *aux),
void *aux);
/* Iterates over all of 'netdev''s queues, calling 'cb' with the queue's
* ID, its statistics, and the 'aux' specified by the caller. The order of
* iteration is unspecified, but (when successful) each queue must be
* visited exactly once.
*
* 'cb' will not modify or free the statistics passed in. */
int (*dump_queue_stats)(const struct netdev *netdev,
void (*cb)(unsigned int queue_id,
struct netdev_queue_stats *,
void *aux),
void *aux);
/* If 'netdev' has an assigned IPv4 address, sets '*address' to that /* If 'netdev' has an assigned IPv4 address, sets '*address' to that
* address and '*netmask' to the associated netmask. * address and '*netmask' to the associated netmask.
* *

View File

@ -963,6 +963,285 @@ netdev_set_policing(struct netdev *netdev, uint32_t kbits_rate,
: EOPNOTSUPP); : EOPNOTSUPP);
} }
/* Adds to 'types' all of the forms of QoS supported by 'netdev', or leaves it
* empty if 'netdev' does not support QoS. Any names added to 'types' should
* be documented as valid for the "type" column in the "QoS" table in
* vswitchd/vswitch.xml (which is built as ovs-vswitchd.conf.db(8)).
*
* Every network device supports disabling QoS with a type of "", but this type
* will not be added to 'types'.
*
* The caller must initialize 'types' (e.g. with svec_init()) before calling
* this function. The caller is responsible for destroying 'types' (e.g. with
* svec_destroy()) when it is no longer needed.
*
* Returns 0 if successful, otherwise a positive errno value. */
int
netdev_get_qos_types(const struct netdev *netdev, struct svec *types)
{
const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
return (class->get_qos_types
? class->get_qos_types(netdev, types)
: 0);
}
/* Queries 'netdev' for its capabilities regarding the specified 'type' of QoS,
* which should be "" or one of the types returned by netdev_get_qos_types()
* for 'netdev'. Returns 0 if successful, otherwise a positive errno value.
* On success, initializes 'caps' with the QoS capabilities; on failure, clears
* 'caps' to all zeros. */
int
netdev_get_qos_capabilities(const struct netdev *netdev, const char *type,
struct netdev_qos_capabilities *caps)
{
const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
if (*type) {
int retval = (class->get_qos_capabilities
? class->get_qos_capabilities(netdev, type, caps)
: EOPNOTSUPP);
if (retval) {
memset(caps, 0, sizeof *caps);
}
return retval;
} else {
/* Every netdev supports turning off QoS. */
memset(caps, 0, sizeof *caps);
return 0;
}
}
/* Obtains the number of queues supported by 'netdev' for the specified 'type'
* of QoS. Returns 0 if successful, otherwise a positive errno value. Stores
* the number of queues (zero on failure) in '*n_queuesp'.
*
* This is just a simple wrapper around netdev_get_qos_capabilities(). */
int
netdev_get_n_queues(const struct netdev *netdev,
const char *type, unsigned int *n_queuesp)
{
struct netdev_qos_capabilities caps;
int retval;
retval = netdev_get_qos_capabilities(netdev, type, &caps);
*n_queuesp = caps.n_queues;
return retval;
}
/* Queries 'netdev' about its currently configured form of QoS. If successful,
* stores the name of the current form of QoS into '*typep', stores any details
* of configuration as string key-value pairs in 'details', and returns 0. On
* failure, sets '*typep' to NULL and returns a positive errno value.
*
* A '*typep' of "" indicates that QoS is currently disabled on 'netdev'.
*
* The caller must initialize 'details' as an empty shash (e.g. with
* shash_init()) before calling this function. The caller must free 'details',
* including 'data' members, when it is no longer needed (e.g. with
* shash_destroy_free_data()).
*
* The caller must not modify or free '*typep'.
*
* '*typep' will be one of the types returned by netdev_get_qos_types() for
* 'netdev'. The contents of 'details' should be documented as valid for
* '*typep' in the "other_config" column in the "QoS" table in
* vswitchd/vswitch.xml (which is built as ovs-vswitchd.conf.db(8)). */
int
netdev_get_qos(const struct netdev *netdev,
const char **typep, struct shash *details)
{
const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
int retval;
if (class->get_qos) {
retval = class->get_qos(netdev, typep, details);
if (retval) {
*typep = NULL;
shash_clear_free_data(details);
}
return retval;
} else {
/* 'netdev' doesn't support QoS, so report that QoS is disabled. */
*typep = "";
return 0;
}
}
/* Attempts to reconfigure QoS on 'netdev', changing the form of QoS to 'type'
* with details of configuration from 'details'. Returns 0 if successful,
* otherwise a positive errno value. On error, the previous QoS configuration
* is retained.
*
* When this function changes the type of QoS (not just 'details'), this also
* resets all queue configuration for 'netdev' to their defaults (which depend
* on the specific type of QoS). Otherwise, the queue configuration for
* 'netdev' is unchanged.
*
* 'type' should be "" (to disable QoS) or one of the types returned by
* netdev_get_qos_types() for 'netdev'. The contents of 'details' should be
* documented as valid for the given 'type' in the "other_config" column in the
* "QoS" table in vswitchd/vswitch.xml (which is built as
* ovs-vswitchd.conf.db(8)).
*
* NULL may be specified for 'details' if there are no configuration
* details. */
int
netdev_set_qos(struct netdev *netdev,
const char *type, const struct shash *details)
{
const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
if (!type) {
type = "";
}
if (class->set_qos) {
if (!details) {
static struct shash empty = SHASH_INITIALIZER(&empty);
details = &empty;
}
return class->set_qos(netdev, type, details);
} else {
return *type ? EOPNOTSUPP : 0;
}
}
/* Queries 'netdev' for information about the queue numbered 'queue_id'. If
* successful, adds that information as string key-value pairs to 'details'.
* Returns 0 if successful, otherwise a positive errno value.
*
* 'queue_id' must be less than the number of queues supported by 'netdev' for
* the current form of QoS (e.g. as returned by netdev_get_n_queues(netdev)).
*
* The returned contents of 'details' should be documented as valid for the
* given 'type' in the "other_config" column in the "Queue" table in
* vswitchd/vswitch.xml (which is built as ovs-vswitchd.conf.db(8)).
*
* The caller must initialize 'details' (e.g. with shash_init()) before calling
* this function. The caller must free 'details', including 'data' members,
* when it is no longer needed (e.g. with shash_destroy_free_data()). */
int
netdev_get_queue(const struct netdev *netdev,
unsigned int queue_id, struct shash *details)
{
const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
int retval;
retval = (class->get_queue
? class->get_queue(netdev, queue_id, details)
: EOPNOTSUPP);
if (retval) {
shash_clear_free_data(details);
}
return retval;
}
/* Configures the queue numbered 'queue_id' on 'netdev' with the key-value
* string pairs in 'details'. The contents of 'details' should be documented
* as valid for the given 'type' in the "other_config" column in the "Queue"
* table in vswitchd/vswitch.xml (which is built as ovs-vswitchd.conf.db(8)).
* Returns 0 if successful, otherwise a positive errno value. On failure, the
* given queue's configuration should be unmodified.
*
* 'queue_id' must be less than the number of queues supported by 'netdev' for
* the current form of QoS (e.g. as returned by netdev_get_n_queues(netdev)).
*
* This function does not modify 'details', and the caller retains ownership of
* it.
*/
int
netdev_set_queue(struct netdev *netdev,
unsigned int queue_id, const struct shash *details)
{
const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
return (class->set_queue
? class->set_queue(netdev, queue_id, details)
: EOPNOTSUPP);
}
/* Attempts to delete the queue numbered 'queue_id' from 'netdev'. Some kinds
* of QoS may have a fixed set of queues, in which case attempts to delete them
* will fail with EOPNOTSUPP.
*
* Returns 0 if successful, otherwise a positive errno value. On failure, the
* given queue will be unmodified.
*
* 'queue_id' must be less than the number of queues supported by 'netdev' for
* the current form of QoS (e.g. as returned by
* netdev_get_n_queues(netdev)). */
int
netdev_delete_queue(struct netdev *netdev, unsigned int queue_id)
{
const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
return (class->delete_queue
? class->delete_queue(netdev, queue_id)
: EOPNOTSUPP);
}
/* Obtains statistics about 'queue_id' on 'netdev'. On success, returns 0 and
* fills 'stats' with the queue's statistics; individual members of 'stats' may
* be set to all-1-bits if the statistic is unavailable. On failure, returns a
* positive errno value and fills 'stats' with all-1-bits. */
int
netdev_get_queue_stats(const struct netdev *netdev, unsigned int queue_id,
struct netdev_queue_stats *stats)
{
const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
int retval;
retval = (class->get_queue_stats
? class->get_queue_stats(netdev, queue_id, stats)
: EOPNOTSUPP);
if (retval) {
memset(stats, 0xff, sizeof *stats);
}
return retval;
}
/* Iterates over all of 'netdev''s queues, calling 'cb' with the queue's ID,
* its configuration, and the 'aux' specified by the caller. The order of
* iteration is unspecified, but (when successful) each queue is visited
* exactly once.
*
* Calling this function may be more efficient than calling netdev_get_queue()
* for every queue.
*
* 'cb' must not modify or free the 'details' argument passed in.
*
* Returns 0 if successful, otherwise a positive errno value. On error, some
* configured queues may not have been included in the iteration. */
int
netdev_dump_queues(const struct netdev *netdev,
netdev_dump_queues_cb *cb, void *aux)
{
const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
return (class->dump_queues
? class->dump_queues(netdev, cb, aux)
: EOPNOTSUPP);
}
/* Iterates over all of 'netdev''s queues, calling 'cb' with the queue's ID,
* its statistics, and the 'aux' specified by the caller. The order of
* iteration is unspecified, but (when successful) each queue is visited
* exactly once.
*
* Calling this function may be more efficient than calling
* netdev_get_queue_stats() for every queue.
*
* 'cb' must not modify or free the statistics passed in.
*
* Returns 0 if successful, otherwise a positive errno value. On error, some
* configured queues may not have been included in the iteration. */
int
netdev_dump_queue_stats(const struct netdev *netdev,
netdev_dump_queue_stats_cb *cb, void *aux)
{
const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
return (class->dump_queue_stats
? class->dump_queue_stats(netdev, cb, aux)
: EOPNOTSUPP);
}
/* If 'netdev' is a VLAN network device (e.g. one created with vconfig(8)), /* If 'netdev' is a VLAN network device (e.g. one created with vconfig(8)),
* sets '*vlan_vid' to the VLAN VID associated with that device and returns 0. * sets '*vlan_vid' to the VLAN VID associated with that device and returns 0.
* Otherwise returns a errno value (specifically ENOENT if 'netdev_name' is the * Otherwise returns a errno value (specifically ENOENT if 'netdev_name' is the

View File

@ -97,6 +97,7 @@ int netdev_register_provider(const struct netdev_class *);
int netdev_unregister_provider(const char *type); int netdev_unregister_provider(const char *type);
void netdev_enumerate_types(struct svec *types); void netdev_enumerate_types(struct svec *types);
/* Open and close. */
int netdev_open(struct netdev_options *, struct netdev **); int netdev_open(struct netdev_options *, struct netdev **);
int netdev_open_default(const char *name, struct netdev **); int netdev_open_default(const char *name, struct netdev **);
int netdev_reconfigure(struct netdev *, const struct shash *args); int netdev_reconfigure(struct netdev *, const struct shash *args);
@ -107,11 +108,13 @@ bool netdev_is_open(const char *name);
int netdev_enumerate(struct svec *); int netdev_enumerate(struct svec *);
/* Basic properties. */
const char *netdev_get_name(const struct netdev *); const char *netdev_get_name(const struct netdev *);
const char *netdev_get_type(const struct netdev *); const char *netdev_get_type(const struct netdev *);
int netdev_get_mtu(const struct netdev *, int *mtup); int netdev_get_mtu(const struct netdev *, int *mtup);
int netdev_get_ifindex(const struct netdev *); int netdev_get_ifindex(const struct netdev *);
/* Packet send and receive. */
int netdev_recv(struct netdev *, struct ofpbuf *); int netdev_recv(struct netdev *, struct ofpbuf *);
void netdev_recv_wait(struct netdev *); void netdev_recv_wait(struct netdev *);
int netdev_drain(struct netdev *); int netdev_drain(struct netdev *);
@ -119,9 +122,11 @@ int netdev_drain(struct netdev *);
int netdev_send(struct netdev *, const struct ofpbuf *); int netdev_send(struct netdev *, const struct ofpbuf *);
void netdev_send_wait(struct netdev *); void netdev_send_wait(struct netdev *);
/* Hardware address. */
int netdev_set_etheraddr(struct netdev *, const uint8_t mac[6]); int netdev_set_etheraddr(struct netdev *, const uint8_t mac[6]);
int netdev_get_etheraddr(const struct netdev *, uint8_t mac[6]); int netdev_get_etheraddr(const struct netdev *, uint8_t mac[6]);
/* PHY interface. */
int netdev_get_carrier(const struct netdev *, bool *carrier); int netdev_get_carrier(const struct netdev *, bool *carrier);
int netdev_get_features(struct netdev *, int netdev_get_features(struct netdev *,
uint32_t *current, uint32_t *advertised, uint32_t *current, uint32_t *advertised,
@ -130,6 +135,7 @@ uint64_t netdev_features_to_bps(uint32_t features);
bool netdev_features_is_full_duplex(uint32_t features); bool netdev_features_is_full_duplex(uint32_t features);
int netdev_set_advertisements(struct netdev *, uint32_t advertise); int netdev_set_advertisements(struct netdev *, uint32_t advertise);
/* TCP/IP stack interface. */
int netdev_get_in4(const struct netdev *, struct in_addr *address, int netdev_get_in4(const struct netdev *, struct in_addr *address,
struct in_addr *netmask); struct in_addr *netmask);
int netdev_set_in4(struct netdev *, struct in_addr addr, struct in_addr mask); int netdev_set_in4(struct netdev *, struct in_addr addr, struct in_addr mask);
@ -143,15 +149,62 @@ int netdev_get_flags(const struct netdev *, enum netdev_flags *);
int netdev_set_flags(struct netdev *, enum netdev_flags, bool permanent); int netdev_set_flags(struct netdev *, enum netdev_flags, bool permanent);
int netdev_turn_flags_on(struct netdev *, enum netdev_flags, bool permanent); int netdev_turn_flags_on(struct netdev *, enum netdev_flags, bool permanent);
int netdev_turn_flags_off(struct netdev *, enum netdev_flags, bool permanent); int netdev_turn_flags_off(struct netdev *, enum netdev_flags, bool permanent);
int netdev_get_stats(const struct netdev *, struct netdev_stats *);
int netdev_set_stats(struct netdev *, const struct netdev_stats *);
int netdev_set_policing(struct netdev *, uint32_t kbits_rate,
uint32_t kbits_burst);
int netdev_get_vlan_vid(const struct netdev *, int *vlan_vid);
struct netdev *netdev_find_dev_by_in4(const struct in_addr *); struct netdev *netdev_find_dev_by_in4(const struct in_addr *);
/* Statistics. */
int netdev_get_stats(const struct netdev *, struct netdev_stats *);
int netdev_set_stats(struct netdev *, const struct netdev_stats *);
/* Quality of service. */
struct netdev_qos_capabilities {
unsigned int n_queues;
};
struct netdev_queue_stats {
/* Values of unsupported statistics are set to all-1-bits (UINT64_MAX). */
uint64_t tx_bytes;
uint64_t tx_packets;
uint64_t tx_errors;
};
int netdev_set_policing(struct netdev *, uint32_t kbits_rate,
uint32_t kbits_burst);
int netdev_get_qos_types(const struct netdev *, struct svec *types);
int netdev_get_qos_capabilities(const struct netdev *,
const char *type,
struct netdev_qos_capabilities *);
int netdev_get_n_queues(const struct netdev *,
const char *type, unsigned int *n_queuesp);
int netdev_get_qos(const struct netdev *,
const char **typep, struct shash *details);
int netdev_set_qos(struct netdev *,
const char *type, const struct shash *details);
int netdev_get_queue(const struct netdev *,
unsigned int queue_id, struct shash *details);
int netdev_set_queue(struct netdev *,
unsigned int queue_id, const struct shash *details);
int netdev_delete_queue(struct netdev *, unsigned int queue_id);
int netdev_get_queue_stats(const struct netdev *, unsigned int queue_id,
struct netdev_queue_stats *);
typedef void netdev_dump_queues_cb(unsigned int queue_id,
const struct shash *details, void *aux);
int netdev_dump_queues(const struct netdev *,
netdev_dump_queues_cb *, void *aux);
typedef void netdev_dump_queue_stats_cb(unsigned int queue_id,
struct netdev_queue_stats *,
void *aux);
int netdev_dump_queue_stats(const struct netdev *,
netdev_dump_queue_stats_cb *, void *aux);
/* Linux stuff. */
int netdev_get_vlan_vid(const struct netdev *, int *vlan_vid);
/* Monitoring for changes in network device status. */
struct netdev_monitor *netdev_monitor_create(void); struct netdev_monitor *netdev_monitor_create(void);
void netdev_monitor_destroy(struct netdev_monitor *); void netdev_monitor_destroy(struct netdev_monitor *);
int netdev_monitor_add(struct netdev_monitor *, struct netdev *); int netdev_monitor_add(struct netdev_monitor *, struct netdev *);

View File

@ -22,6 +22,7 @@
#include "ofpbuf.h" #include "ofpbuf.h"
#include "packets.h" #include "packets.h"
#include "random.h" #include "random.h"
#include "xtoxll.h"
#define THIS_MODULE VLM_ofp_util #define THIS_MODULE VLM_ofp_util
#include "vlog.h" #include "vlog.h"
@ -489,8 +490,11 @@ check_action_exact_len(const union ofp_action *a, unsigned int len,
return 0; return 0;
} }
/* Checks that 'port' is a valid output port for the OFPAT_OUTPUT action, given
* that the switch will never have more than 'max_ports' ports. Returns 0 if
* 'port' is valid, otherwise an ofp_mkerr() return code. */
static int static int
check_action_port(int port, int max_ports) check_output_port(uint16_t port, int max_ports)
{ {
switch (port) { switch (port) {
case OFPP_IN_PORT: case OFPP_IN_PORT:
@ -503,7 +507,7 @@ check_action_port(int port, int max_ports)
return 0; return 0;
default: default:
if (port >= 0 && port < max_ports) { if (port < max_ports) {
return 0; return 0;
} }
VLOG_WARN_RL(&bad_ofmsg_rl, "unknown output port %x", port); VLOG_WARN_RL(&bad_ofmsg_rl, "unknown output port %x", port);
@ -511,6 +515,31 @@ check_action_port(int port, int max_ports)
} }
} }
/* Checks that 'action' is a valid OFPAT_ENQUEUE action, given that the switch
* will never have more than 'max_ports' ports. Returns 0 if 'port' is valid,
* otherwise an ofp_mkerr() return code. */
static int
check_enqueue_action(const union ofp_action *a, unsigned int len,
int max_ports)
{
const struct ofp_action_enqueue *oae;
uint16_t port;
int error;
error = check_action_exact_len(a, len, 16);
if (error) {
return error;
}
oae = (const struct ofp_action_enqueue *) a;
port = ntohs(oae->port);
if (port < max_ports || port == OFPP_IN_PORT) {
return 0;
}
VLOG_WARN_RL(&bad_ofmsg_rl, "unknown enqueue port %x", port);
return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT);
}
static int static int
check_nicira_action(const union ofp_action *a, unsigned int len) check_nicira_action(const union ofp_action *a, unsigned int len)
{ {
@ -539,8 +568,11 @@ check_action(const union ofp_action *a, unsigned int len, int max_ports)
switch (ntohs(a->type)) { switch (ntohs(a->type)) {
case OFPAT_OUTPUT: case OFPAT_OUTPUT:
error = check_action_port(ntohs(a->output.port), max_ports); error = check_action_exact_len(a, len, 8);
return error ? error : check_action_exact_len(a, len, 8); if (error) {
return error;
}
return check_output_port(ntohs(a->output.port), max_ports);
case OFPAT_SET_VLAN_VID: case OFPAT_SET_VLAN_VID:
case OFPAT_SET_VLAN_PCP: case OFPAT_SET_VLAN_PCP:
@ -561,6 +593,9 @@ check_action(const union ofp_action *a, unsigned int len, int max_ports)
? check_nicira_action(a, len) ? check_nicira_action(a, len)
: ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR)); : ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR));
case OFPAT_ENQUEUE:
return check_enqueue_action(a, len, max_ports);
default: default:
VLOG_WARN_RL(&bad_ofmsg_rl, "unknown action type %"PRIu16, VLOG_WARN_RL(&bad_ofmsg_rl, "unknown action type %"PRIu16,
ntohs(a->type)); ntohs(a->type));
@ -603,6 +638,21 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
return 0; return 0;
} }
/* Returns true if 'action' outputs to 'port' (which must be in network byte
* order), false otherwise. */
bool
action_outputs_to_port(const union ofp_action *action, uint16_t port)
{
switch (ntohs(action->type)) {
case OFPAT_OUTPUT:
return action->output.port == port;
case OFPAT_ENQUEUE:
return ((const struct ofp_action_enqueue *) action)->port == port;
default:
return false;
}
}
/* The set of actions must either come from a trusted source or have been /* The set of actions must either come from a trusted source or have been
* previously validated with validate_actions(). */ * previously validated with validate_actions(). */
const union ofp_action * const union ofp_action *

View File

@ -18,6 +18,7 @@
#define OFP_UTIL_H 1 #define OFP_UTIL_H 1
#include <assert.h> #include <assert.h>
#include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "flow.h" #include "flow.h"
@ -77,6 +78,7 @@ const union ofp_action *actions_first(struct actions_iterator *,
const union ofp_action *actions_next(struct actions_iterator *); const union ofp_action *actions_next(struct actions_iterator *);
int validate_actions(const union ofp_action *, size_t n_actions, int validate_actions(const union ofp_action *, size_t n_actions,
int max_ports); int max_ports);
bool action_outputs_to_port(const union ofp_action *, uint16_t port);
void normalize_match(struct ofp_match *); void normalize_match(struct ofp_match *);

View File

@ -59,6 +59,9 @@
#include "vconn.h" #include "vconn.h"
#include "xtoxll.h" #include "xtoxll.h"
#include <linux/types.h> /* XXX */
#include <linux/pkt_sched.h> /* XXX */
#define THIS_MODULE VLM_ofproto #define THIS_MODULE VLM_ofproto
#include "vlog.h" #include "vlog.h"
@ -1798,7 +1801,7 @@ rule_has_out_port(const struct rule *rule, uint16_t out_port)
} }
for (oa = actions_first(&i, rule->actions, rule->n_actions); oa; for (oa = actions_first(&i, rule->actions, rule->n_actions); oa;
oa = actions_next(&i)) { oa = actions_next(&i)) {
if (oa->type == htons(OFPAT_OUTPUT) && oa->output.port == out_port) { if (action_outputs_to_port(oa, out_port)) {
return true; return true;
} }
} }
@ -2070,15 +2073,11 @@ is_controller_rule(struct rule *rule)
* NetFlow expiration messages since it is just part of the control * NetFlow expiration messages since it is just part of the control
* logic for the network and not real traffic. */ * logic for the network and not real traffic. */
if (rule && rule->super) { return (rule
struct rule *super = rule->super; && rule->super
&& rule->super->n_actions == 1
return super->n_actions == 1 && && action_outputs_to_port(&rule->super->actions[0],
super->actions[0].type == htons(OFPAT_OUTPUT) && htons(OFPP_CONTROLLER)));
super->actions[0].output.port == htons(OFPP_CONTROLLER);
}
return false;
} }
static void static void
@ -2195,7 +2194,8 @@ handle_features_request(struct ofproto *p, struct ofconn *ofconn,
(1u << OFPAT_SET_NW_DST) | (1u << OFPAT_SET_NW_DST) |
(1u << OFPAT_SET_NW_TOS) | (1u << OFPAT_SET_NW_TOS) |
(1u << OFPAT_SET_TP_SRC) | (1u << OFPAT_SET_TP_SRC) |
(1u << OFPAT_SET_TP_DST)); (1u << OFPAT_SET_TP_DST) |
(1u << OFPAT_ENQUEUE));
PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) { PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) {
hton_ofp_phy_port(ofpbuf_put(buf, &port->opp, sizeof port->opp)); hton_ofp_phy_port(ofpbuf_put(buf, &port->opp, sizeof port->opp));
@ -2423,6 +2423,48 @@ xlate_output_action(struct action_xlate_ctx *ctx,
} }
} }
/* If the final ODP action in 'ctx' is "pop priority", drop it, as an
* optimization, because we're going to add another action that sets the
* priority immediately after, or because there are no actions following the
* pop. */
static void
remove_pop_action(struct action_xlate_ctx *ctx)
{
size_t n = ctx->out->n_actions;
if (n > 0 && ctx->out->actions[n - 1].type == ODPAT_POP_PRIORITY) {
ctx->out->n_actions--;
}
}
static void
xlate_enqueue_action(struct action_xlate_ctx *ctx,
const struct ofp_action_enqueue *oae)
{
uint16_t ofp_port, odp_port;
/* Figure out ODP output port. */
ofp_port = ntohs(oae->port);
if (ofp_port != OFPP_IN_PORT) {
odp_port = ofp_port_to_odp_port(ofp_port);
} else {
odp_port = ctx->flow.in_port;
}
/* Add ODP actions. */
remove_pop_action(ctx);
odp_actions_add(ctx->out, ODPAT_SET_PRIORITY)->priority.priority
= TC_H_MAKE(1, ntohl(oae->queue_id)); /* XXX */
add_output_action(ctx, odp_port);
odp_actions_add(ctx->out, ODPAT_POP_PRIORITY);
/* Update NetFlow output port. */
if (ctx->nf_output_iface == NF_OUT_DROP) {
ctx->nf_output_iface = odp_port;
} else if (ctx->nf_output_iface != NF_OUT_FLOOD) {
ctx->nf_output_iface = NF_OUT_MULTI;
}
}
static void static void
xlate_nicira_action(struct action_xlate_ctx *ctx, xlate_nicira_action(struct action_xlate_ctx *ctx,
const struct nx_action_header *nah) const struct nx_action_header *nah)
@ -2446,7 +2488,7 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
break; break;
/* If you add a new action here that modifies flow data, don't forget to /* If you add a new action here that modifies flow data, don't forget to
* update the flow key in ctx->flow in the same key. */ * update the flow key in ctx->flow at the same time. */
default: default:
VLOG_DBG_RL(&rl, "unknown Nicira action type %"PRIu16, subtype); VLOG_DBG_RL(&rl, "unknown Nicira action type %"PRIu16, subtype);
@ -2540,6 +2582,10 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
xlate_nicira_action(ctx, (const struct nx_action_header *) ia); xlate_nicira_action(ctx, (const struct nx_action_header *) ia);
break; break;
case OFPAT_ENQUEUE:
xlate_enqueue_action(ctx, (const struct ofp_action_enqueue *) ia);
break;
default: default:
VLOG_DBG_RL(&rl, "unknown action type %"PRIu16, type); VLOG_DBG_RL(&rl, "unknown action type %"PRIu16, type);
break; break;
@ -2567,6 +2613,7 @@ xlate_actions(const union ofp_action *in, size_t n_in,
ctx.may_set_up_flow = true; ctx.may_set_up_flow = true;
ctx.nf_output_iface = NF_OUT_DROP; ctx.nf_output_iface = NF_OUT_DROP;
do_xlate_actions(in, n_in, &ctx); do_xlate_actions(in, n_in, &ctx);
remove_pop_action(&ctx);
/* Check with in-band control to see if we're allowed to set up this /* Check with in-band control to see if we're allowed to set up this
* flow. */ * flow. */
@ -3144,6 +3191,95 @@ handle_aggregate_stats_request(struct ofproto *p, struct ofconn *ofconn,
return 0; return 0;
} }
struct queue_stats_cbdata {
struct ofconn *ofconn;
struct ofpbuf *msg;
uint16_t port_no;
};
static void
put_queue_stats(struct queue_stats_cbdata *cbdata, uint16_t queue_id,
const struct netdev_queue_stats *stats)
{
struct ofp_queue_stats *reply;
reply = append_stats_reply(sizeof *reply, cbdata->ofconn, &cbdata->msg);
reply->port_no = htons(cbdata->port_no);
memset(reply->pad, 0, sizeof reply->pad);
reply->queue_id = htonl(queue_id);
reply->tx_bytes = htonll(stats->tx_bytes);
reply->tx_packets = htonll(stats->tx_packets);
reply->tx_errors = htonll(stats->tx_errors);
}
static void
handle_queue_stats_dump_cb(unsigned int queue_id,
struct netdev_queue_stats *stats,
void *cbdata_)
{
struct queue_stats_cbdata *cbdata = cbdata_;
put_queue_stats(cbdata, queue_id, stats);
}
static void
handle_queue_stats_for_port(struct ofport *port, uint16_t port_no,
uint16_t queue_id,
struct queue_stats_cbdata *cbdata)
{
cbdata->port_no = port_no;
if (queue_id == OFPQ_ALL) {
netdev_dump_queue_stats(port->netdev,
handle_queue_stats_dump_cb, cbdata);
} else {
struct netdev_queue_stats stats;
netdev_get_queue_stats(port->netdev, queue_id, &stats);
put_queue_stats(cbdata, queue_id, &stats);
}
}
static int
handle_queue_stats_request(struct ofproto *ofproto, struct ofconn *ofconn,
const struct ofp_stats_request *osr,
size_t arg_size)
{
struct ofp_queue_stats_request *qsr;
struct queue_stats_cbdata cbdata;
struct ofport *port;
unsigned int port_no;
uint32_t queue_id;
if (arg_size != sizeof *qsr) {
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
}
qsr = (struct ofp_queue_stats_request *) osr->body;
COVERAGE_INC(ofproto_queue_req);
cbdata.ofconn = ofconn;
cbdata.msg = start_stats_reply(osr, 128);
port_no = ntohs(qsr->port_no);
queue_id = ntohl(qsr->queue_id);
if (port_no == OFPP_ALL) {
PORT_ARRAY_FOR_EACH (port, &ofproto->ports, port_no) {
handle_queue_stats_for_port(port, port_no, queue_id, &cbdata);
}
} else if (port_no < ofproto->max_ports) {
port = port_array_get(&ofproto->ports, port_no);
if (port) {
handle_queue_stats_for_port(port, port_no, queue_id, &cbdata);
}
} else {
ofpbuf_delete(cbdata.msg);
return ofp_mkerr(OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT);
}
queue_tx(cbdata.msg, ofconn, ofconn->reply_counter);
return 0;
}
static int static int
handle_stats_request(struct ofproto *p, struct ofconn *ofconn, handle_stats_request(struct ofproto *p, struct ofconn *ofconn,
struct ofp_header *oh) struct ofp_header *oh)
@ -3175,6 +3311,9 @@ handle_stats_request(struct ofproto *p, struct ofconn *ofconn,
case OFPST_PORT: case OFPST_PORT:
return handle_port_stats_request(p, ofconn, osr, arg_size); return handle_port_stats_request(p, ofconn, osr, arg_size);
case OFPST_QUEUE:
return handle_queue_stats_request(p, ofconn, osr, arg_size);
case OFPST_VENDOR: case OFPST_VENDOR:
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR); return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);

View File

@ -92,6 +92,26 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="QoS">
<attribute name="title">
<string>QoS</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_10">
<item row="0" column="0">
<widget class="QTableWidget" name="QoSTable"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="Queue">
<attribute name="title">
<string>Queue</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_11">
<item row="0" column="0">
<widget class="QTableWidget" name="QueueTable"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="sFlow"> <widget class="QWidget" name="sFlow">
<attribute name="title"> <attribute name="title">
<string>sFlow</string> <string>sFlow</string>

View File

@ -1,15 +1,17 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'MainWindow.ui' # Form implementation generated from reading ui file '../ovsdb/ovsdbmonitor/MainWindow.ui'
# #
# Created: Fri May 7 17:20:33 2010 # Created: Mon May 17 16:23:47 2010
# by: PyQt4 UI code generator 4.4.2 # by: PyQt4 UI code generator 4.7.3
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
try: try:
from OVEStandard import globalForcePySide from OVEStandard import globalForcePySide
if globalForcePySide: raise Exception() if globalForcePySide:
raise Exception()
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
except: except:
from PySide import QtCore, QtGui from PySide import QtCore, QtGui
@ -17,7 +19,7 @@ except:
class Ui_MainWindow(object): class Ui_MainWindow(object):
def setupUi(self, MainWindow): def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow") MainWindow.setObjectName("MainWindow")
MainWindow.resize(800,600) MainWindow.resize(800, 600)
self.centralwidget = QtGui.QWidget(MainWindow) self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget") self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtGui.QGridLayout(self.centralwidget) self.gridLayout = QtGui.QGridLayout(self.centralwidget)
@ -32,72 +34,110 @@ class Ui_MainWindow(object):
self.gridLayout_2.setObjectName("gridLayout_2") self.gridLayout_2.setObjectName("gridLayout_2")
self.BridgeTable = QtGui.QTableWidget(self.Bridge) self.BridgeTable = QtGui.QTableWidget(self.Bridge)
self.BridgeTable.setObjectName("BridgeTable") self.BridgeTable.setObjectName("BridgeTable")
self.gridLayout_2.addWidget(self.BridgeTable,0,0,1,1) self.BridgeTable.setColumnCount(0)
self.tabWidget.addTab(self.Bridge,"") self.BridgeTable.setRowCount(0)
self.gridLayout_2.addWidget(self.BridgeTable, 0, 0, 1, 1)
self.tabWidget.addTab(self.Bridge, "")
self.Controller = QtGui.QWidget() self.Controller = QtGui.QWidget()
self.Controller.setObjectName("Controller") self.Controller.setObjectName("Controller")
self.gridLayout_3 = QtGui.QGridLayout(self.Controller) self.gridLayout_3 = QtGui.QGridLayout(self.Controller)
self.gridLayout_3.setObjectName("gridLayout_3") self.gridLayout_3.setObjectName("gridLayout_3")
self.ControllerTable = QtGui.QTableWidget(self.Controller) self.ControllerTable = QtGui.QTableWidget(self.Controller)
self.ControllerTable.setObjectName("ControllerTable") self.ControllerTable.setObjectName("ControllerTable")
self.gridLayout_3.addWidget(self.ControllerTable,0,0,1,1) self.ControllerTable.setColumnCount(0)
self.tabWidget.addTab(self.Controller,"") self.ControllerTable.setRowCount(0)
self.gridLayout_3.addWidget(self.ControllerTable, 0, 0, 1, 1)
self.tabWidget.addTab(self.Controller, "")
self.Interface = QtGui.QWidget() self.Interface = QtGui.QWidget()
self.Interface.setObjectName("Interface") self.Interface.setObjectName("Interface")
self.gridLayout_4 = QtGui.QGridLayout(self.Interface) self.gridLayout_4 = QtGui.QGridLayout(self.Interface)
self.gridLayout_4.setObjectName("gridLayout_4") self.gridLayout_4.setObjectName("gridLayout_4")
self.InterfaceTable = QtGui.QTableWidget(self.Interface) self.InterfaceTable = QtGui.QTableWidget(self.Interface)
self.InterfaceTable.setObjectName("InterfaceTable") self.InterfaceTable.setObjectName("InterfaceTable")
self.gridLayout_4.addWidget(self.InterfaceTable,0,0,1,1) self.InterfaceTable.setColumnCount(0)
self.tabWidget.addTab(self.Interface,"") self.InterfaceTable.setRowCount(0)
self.gridLayout_4.addWidget(self.InterfaceTable, 0, 0, 1, 1)
self.tabWidget.addTab(self.Interface, "")
self.Mirror = QtGui.QWidget() self.Mirror = QtGui.QWidget()
self.Mirror.setObjectName("Mirror") self.Mirror.setObjectName("Mirror")
self.gridLayout_5 = QtGui.QGridLayout(self.Mirror) self.gridLayout_5 = QtGui.QGridLayout(self.Mirror)
self.gridLayout_5.setObjectName("gridLayout_5") self.gridLayout_5.setObjectName("gridLayout_5")
self.MirrorTable = QtGui.QTableWidget(self.Mirror) self.MirrorTable = QtGui.QTableWidget(self.Mirror)
self.MirrorTable.setObjectName("MirrorTable") self.MirrorTable.setObjectName("MirrorTable")
self.gridLayout_5.addWidget(self.MirrorTable,0,0,1,1) self.MirrorTable.setColumnCount(0)
self.tabWidget.addTab(self.Mirror,"") self.MirrorTable.setRowCount(0)
self.gridLayout_5.addWidget(self.MirrorTable, 0, 0, 1, 1)
self.tabWidget.addTab(self.Mirror, "")
self.NetFlow = QtGui.QWidget() self.NetFlow = QtGui.QWidget()
self.NetFlow.setObjectName("NetFlow") self.NetFlow.setObjectName("NetFlow")
self.gridLayout_6 = QtGui.QGridLayout(self.NetFlow) self.gridLayout_6 = QtGui.QGridLayout(self.NetFlow)
self.gridLayout_6.setObjectName("gridLayout_6") self.gridLayout_6.setObjectName("gridLayout_6")
self.NetFlowTable = QtGui.QTableWidget(self.NetFlow) self.NetFlowTable = QtGui.QTableWidget(self.NetFlow)
self.NetFlowTable.setObjectName("NetFlowTable") self.NetFlowTable.setObjectName("NetFlowTable")
self.gridLayout_6.addWidget(self.NetFlowTable,0,0,1,1) self.NetFlowTable.setColumnCount(0)
self.tabWidget.addTab(self.NetFlow,"") self.NetFlowTable.setRowCount(0)
self.gridLayout_6.addWidget(self.NetFlowTable, 0, 0, 1, 1)
self.tabWidget.addTab(self.NetFlow, "")
self.Open_vSwitch = QtGui.QWidget() self.Open_vSwitch = QtGui.QWidget()
self.Open_vSwitch.setObjectName("Open_vSwitch") self.Open_vSwitch.setObjectName("Open_vSwitch")
self.gridLayout_7 = QtGui.QGridLayout(self.Open_vSwitch) self.gridLayout_7 = QtGui.QGridLayout(self.Open_vSwitch)
self.gridLayout_7.setObjectName("gridLayout_7") self.gridLayout_7.setObjectName("gridLayout_7")
self.Open_vSwitchTable = QtGui.QTableWidget(self.Open_vSwitch) self.Open_vSwitchTable = QtGui.QTableWidget(self.Open_vSwitch)
self.Open_vSwitchTable.setObjectName("Open_vSwitchTable") self.Open_vSwitchTable.setObjectName("Open_vSwitchTable")
self.gridLayout_7.addWidget(self.Open_vSwitchTable,0,0,1,1) self.Open_vSwitchTable.setColumnCount(0)
self.tabWidget.addTab(self.Open_vSwitch,"") self.Open_vSwitchTable.setRowCount(0)
self.gridLayout_7.addWidget(self.Open_vSwitchTable, 0, 0, 1, 1)
self.tabWidget.addTab(self.Open_vSwitch, "")
self.Port = QtGui.QWidget() self.Port = QtGui.QWidget()
self.Port.setObjectName("Port") self.Port.setObjectName("Port")
self.gridLayout_8 = QtGui.QGridLayout(self.Port) self.gridLayout_8 = QtGui.QGridLayout(self.Port)
self.gridLayout_8.setObjectName("gridLayout_8") self.gridLayout_8.setObjectName("gridLayout_8")
self.PortTable = QtGui.QTableWidget(self.Port) self.PortTable = QtGui.QTableWidget(self.Port)
self.PortTable.setObjectName("PortTable") self.PortTable.setObjectName("PortTable")
self.gridLayout_8.addWidget(self.PortTable,0,0,1,1) self.PortTable.setColumnCount(0)
self.tabWidget.addTab(self.Port,"") self.PortTable.setRowCount(0)
self.gridLayout_8.addWidget(self.PortTable, 0, 0, 1, 1)
self.tabWidget.addTab(self.Port, "")
self.QoS = QtGui.QWidget()
self.QoS.setObjectName("QoS")
self.gridLayout_10 = QtGui.QGridLayout(self.QoS)
self.gridLayout_10.setObjectName("gridLayout_10")
self.QoSTable = QtGui.QTableWidget(self.QoS)
self.QoSTable.setObjectName("QoSTable")
self.QoSTable.setColumnCount(0)
self.QoSTable.setRowCount(0)
self.gridLayout_10.addWidget(self.QoSTable, 0, 0, 1, 1)
self.tabWidget.addTab(self.QoS, "")
self.Queue = QtGui.QWidget()
self.Queue.setObjectName("Queue")
self.gridLayout_11 = QtGui.QGridLayout(self.Queue)
self.gridLayout_11.setObjectName("gridLayout_11")
self.QueueTable = QtGui.QTableWidget(self.Queue)
self.QueueTable.setObjectName("QueueTable")
self.QueueTable.setColumnCount(0)
self.QueueTable.setRowCount(0)
self.gridLayout_11.addWidget(self.QueueTable, 0, 0, 1, 1)
self.tabWidget.addTab(self.Queue, "")
self.sFlow = QtGui.QWidget() self.sFlow = QtGui.QWidget()
self.sFlow.setObjectName("sFlow") self.sFlow.setObjectName("sFlow")
self.gridLayout_9 = QtGui.QGridLayout(self.sFlow) self.gridLayout_9 = QtGui.QGridLayout(self.sFlow)
self.gridLayout_9.setObjectName("gridLayout_9") self.gridLayout_9.setObjectName("gridLayout_9")
self.sFlowTable = QtGui.QTableWidget(self.sFlow) self.sFlowTable = QtGui.QTableWidget(self.sFlow)
self.sFlowTable.setObjectName("sFlowTable") self.sFlowTable.setObjectName("sFlowTable")
self.gridLayout_9.addWidget(self.sFlowTable,0,0,1,1) self.sFlowTable.setColumnCount(0)
self.tabWidget.addTab(self.sFlow,"") self.sFlowTable.setRowCount(0)
self.gridLayout_9.addWidget(self.sFlowTable, 0, 0, 1, 1)
self.tabWidget.addTab(self.sFlow, "")
self.SSL = QtGui.QWidget() self.SSL = QtGui.QWidget()
self.SSL.setObjectName("SSL") self.SSL.setObjectName("SSL")
self.gridLayout_10 = QtGui.QGridLayout(self.SSL) self.gridLayout_101 = QtGui.QGridLayout(self.SSL)
self.gridLayout_10.setObjectName("gridLayout_10") self.gridLayout_101.setObjectName("gridLayout_101")
self.SSLTable = QtGui.QTableWidget(self.SSL) self.SSLTable = QtGui.QTableWidget(self.SSL)
self.SSLTable.setObjectName("SSLTable") self.SSLTable.setObjectName("SSLTable")
self.gridLayout_10.addWidget(self.SSLTable,0,0,1,1) self.SSLTable.setColumnCount(0)
self.tabWidget.addTab(self.SSL,"") self.SSLTable.setRowCount(0)
self.gridLayout_101.addWidget(self.SSLTable, 0, 0, 1, 1)
self.tabWidget.addTab(self.SSL, "")
self.verticalLayout.addWidget(self.tabWidget) self.verticalLayout.addWidget(self.tabWidget)
self.horizontalLayout = QtGui.QHBoxLayout() self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout") self.horizontalLayout.setObjectName("horizontalLayout")
@ -116,16 +156,16 @@ class Ui_MainWindow(object):
self.intervalSpinBox.setMaximum(1000000) self.intervalSpinBox.setMaximum(1000000)
self.intervalSpinBox.setObjectName("intervalSpinBox") self.intervalSpinBox.setObjectName("intervalSpinBox")
self.horizontalLayout.addWidget(self.intervalSpinBox) self.horizontalLayout.addWidget(self.intervalSpinBox)
spacerItem = QtGui.QSpacerItem(40,20,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Minimum) spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem) self.horizontalLayout.addItem(spacerItem)
self.fetchButton = QtGui.QPushButton(self.centralwidget) self.fetchButton = QtGui.QPushButton(self.centralwidget)
self.fetchButton.setObjectName("fetchButton") self.fetchButton.setObjectName("fetchButton")
self.horizontalLayout.addWidget(self.fetchButton) self.horizontalLayout.addWidget(self.fetchButton)
self.verticalLayout.addLayout(self.horizontalLayout) self.verticalLayout.addLayout(self.horizontalLayout)
self.gridLayout.addLayout(self.verticalLayout,0,0,1,1) self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget) MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow) self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0,0,800,28)) self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 28))
self.menubar.setObjectName("menubar") self.menubar.setObjectName("menubar")
self.menuFile = QtGui.QMenu(self.menubar) self.menuFile = QtGui.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile") self.menuFile.setObjectName("menuFile")
@ -158,41 +198,16 @@ class Ui_MainWindow(object):
def retranslateUi(self, MainWindow): def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "OVSDB Monitor", None, QtGui.QApplication.UnicodeUTF8)) MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "OVSDB Monitor", None, QtGui.QApplication.UnicodeUTF8))
self.BridgeTable.clear()
self.BridgeTable.setColumnCount(0)
self.BridgeTable.setRowCount(0)
self.tabWidget.setTabText(self.tabWidget.indexOf(self.Bridge), QtGui.QApplication.translate("MainWindow", "Bridge", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.Bridge), QtGui.QApplication.translate("MainWindow", "Bridge", None, QtGui.QApplication.UnicodeUTF8))
self.ControllerTable.clear()
self.ControllerTable.setColumnCount(0)
self.ControllerTable.setRowCount(0)
self.tabWidget.setTabText(self.tabWidget.indexOf(self.Controller), QtGui.QApplication.translate("MainWindow", "Controller", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.Controller), QtGui.QApplication.translate("MainWindow", "Controller", None, QtGui.QApplication.UnicodeUTF8))
self.InterfaceTable.clear()
self.InterfaceTable.setColumnCount(0)
self.InterfaceTable.setRowCount(0)
self.tabWidget.setTabText(self.tabWidget.indexOf(self.Interface), QtGui.QApplication.translate("MainWindow", "Interface", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.Interface), QtGui.QApplication.translate("MainWindow", "Interface", None, QtGui.QApplication.UnicodeUTF8))
self.MirrorTable.clear()
self.MirrorTable.setColumnCount(0)
self.MirrorTable.setRowCount(0)
self.tabWidget.setTabText(self.tabWidget.indexOf(self.Mirror), QtGui.QApplication.translate("MainWindow", "Mirror", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.Mirror), QtGui.QApplication.translate("MainWindow", "Mirror", None, QtGui.QApplication.UnicodeUTF8))
self.NetFlowTable.clear()
self.NetFlowTable.setColumnCount(0)
self.NetFlowTable.setRowCount(0)
self.tabWidget.setTabText(self.tabWidget.indexOf(self.NetFlow), QtGui.QApplication.translate("MainWindow", "NetFlow", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.NetFlow), QtGui.QApplication.translate("MainWindow", "NetFlow", None, QtGui.QApplication.UnicodeUTF8))
self.Open_vSwitchTable.clear()
self.Open_vSwitchTable.setColumnCount(0)
self.Open_vSwitchTable.setRowCount(0)
self.tabWidget.setTabText(self.tabWidget.indexOf(self.Open_vSwitch), QtGui.QApplication.translate("MainWindow", "Open_vSwitch", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.Open_vSwitch), QtGui.QApplication.translate("MainWindow", "Open_vSwitch", None, QtGui.QApplication.UnicodeUTF8))
self.PortTable.clear()
self.PortTable.setColumnCount(0)
self.PortTable.setRowCount(0)
self.tabWidget.setTabText(self.tabWidget.indexOf(self.Port), QtGui.QApplication.translate("MainWindow", "Port", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.Port), QtGui.QApplication.translate("MainWindow", "Port", None, QtGui.QApplication.UnicodeUTF8))
self.sFlowTable.clear() self.tabWidget.setTabText(self.tabWidget.indexOf(self.QoS), QtGui.QApplication.translate("MainWindow", "QoS", None, QtGui.QApplication.UnicodeUTF8))
self.sFlowTable.setColumnCount(0) self.tabWidget.setTabText(self.tabWidget.indexOf(self.Queue), QtGui.QApplication.translate("MainWindow", "Queue", None, QtGui.QApplication.UnicodeUTF8))
self.sFlowTable.setRowCount(0)
self.tabWidget.setTabText(self.tabWidget.indexOf(self.sFlow), QtGui.QApplication.translate("MainWindow", "sFlow", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.sFlow), QtGui.QApplication.translate("MainWindow", "sFlow", None, QtGui.QApplication.UnicodeUTF8))
self.SSLTable.clear()
self.SSLTable.setColumnCount(0)
self.SSLTable.setRowCount(0)
self.tabWidget.setTabText(self.tabWidget.indexOf(self.SSL), QtGui.QApplication.translate("MainWindow", "SSL", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.SSL), QtGui.QApplication.translate("MainWindow", "SSL", None, QtGui.QApplication.UnicodeUTF8))
self.hostLabel.setText(QtGui.QApplication.translate("MainWindow", "Host", None, QtGui.QApplication.UnicodeUTF8)) self.hostLabel.setText(QtGui.QApplication.translate("MainWindow", "Host", None, QtGui.QApplication.UnicodeUTF8))
self.intervalCheckBox.setText(QtGui.QApplication.translate("MainWindow", "Auto-refetch every", None, QtGui.QApplication.UnicodeUTF8)) self.intervalCheckBox.setText(QtGui.QApplication.translate("MainWindow", "Auto-refetch every", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -1904,6 +1904,14 @@ static const struct vsctl_table_class tables[] = {
{{&ovsrec_table_port, &ovsrec_port_col_name, NULL}, {{&ovsrec_table_port, &ovsrec_port_col_name, NULL},
{NULL, NULL, NULL}}}, {NULL, NULL, NULL}}},
{&ovsrec_table_qos,
{{&ovsrec_table_port, &ovsrec_port_col_name, &ovsrec_port_col_qos},
{NULL, NULL, NULL}}},
{&ovsrec_table_queue,
{{NULL, NULL, NULL},
{NULL, NULL, NULL}}},
{&ovsrec_table_ssl, {&ovsrec_table_ssl,
{{&ovsrec_table_open_vswitch, NULL, &ovsrec_open_vswitch_col_ssl}}}, {{&ovsrec_table_open_vswitch, NULL, &ovsrec_open_vswitch_col_ssl}}},

View File

@ -253,6 +253,7 @@ static struct iface *iface_from_dp_ifidx(const struct bridge *,
uint16_t dp_ifidx); uint16_t dp_ifidx);
static bool iface_is_internal(const struct bridge *, const char *name); static bool iface_is_internal(const struct bridge *, const char *name);
static void iface_set_mac(struct iface *); static void iface_set_mac(struct iface *);
static void iface_update_qos(struct iface *, const struct ovsrec_qos *);
/* Hooks into ofproto processing. */ /* Hooks into ofproto processing. */
static struct ofhooks bridge_ofhooks; static struct ofhooks bridge_ofhooks;
@ -832,9 +833,14 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
LIST_FOR_EACH (br, struct bridge, node, &all_bridges) { LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
for (i = 0; i < br->n_ports; i++) { for (i = 0; i < br->n_ports; i++) {
struct port *port = br->ports[i]; struct port *port = br->ports[i];
int j;
port_update_vlan_compat(port); port_update_vlan_compat(port);
port_update_bonding(port); port_update_bonding(port);
for (j = 0; j < port->n_ifaces; j++) {
iface_update_qos(port->ifaces[j], port->cfg->qos);
}
} }
} }
LIST_FOR_EACH (br, struct bridge, node, &all_bridges) { LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
@ -3644,6 +3650,90 @@ iface_set_mac(struct iface *iface)
} }
} }
} }
static void
shash_from_ovs_idl_map(char **keys, char **values, size_t n,
struct shash *shash)
{
size_t i;
shash_init(shash);
for (i = 0; i < n; i++) {
shash_add(shash, keys[i], values[i]);
}
}
struct iface_delete_queues_cbdata {
struct netdev *netdev;
const int64_t *queue_ids;
size_t n_queue_ids;
};
static bool
queue_ids_include(const int64_t *ids, size_t n, int64_t target)
{
size_t low = 0;
size_t high = n;
while (low < high) {
size_t mid = low + (high - low) / 2;
if (target > ids[mid]) {
high = mid;
} else if (target < ids[mid]) {
low = mid + 1;
} else {
return true;
}
}
return false;
}
static void
iface_delete_queues(unsigned int queue_id,
const struct shash *details OVS_UNUSED, void *cbdata_)
{
struct iface_delete_queues_cbdata *cbdata = cbdata_;
if (!queue_ids_include(cbdata->queue_ids, cbdata->n_queue_ids, queue_id)) {
netdev_delete_queue(cbdata->netdev, queue_id);
}
}
static void
iface_update_qos(struct iface *iface, const struct ovsrec_qos *qos)
{
if (!qos || qos->type[0] == '\0') {
netdev_set_qos(iface->netdev, NULL, NULL);
} else {
struct iface_delete_queues_cbdata cbdata;
struct shash details;
size_t i;
/* Configure top-level Qos for 'iface'. */
shash_from_ovs_idl_map(qos->key_other_config, qos->value_other_config,
qos->n_other_config, &details);
netdev_set_qos(iface->netdev, qos->type, &details);
shash_destroy(&details);
/* Deconfigure queues that were deleted. */
cbdata.netdev = iface->netdev;
cbdata.queue_ids = qos->key_queues;
cbdata.n_queue_ids = qos->n_queues;
netdev_dump_queues(iface->netdev, iface_delete_queues, &cbdata);
/* Configure queues for 'iface'. */
for (i = 0; i < qos->n_queues; i++) {
const struct ovsrec_queue *queue = qos->value_queues[i];
unsigned int queue_id = qos->key_queues[i];
shash_from_ovs_idl_map(queue->key_other_config,
queue->value_other_config,
queue->n_other_config, &details);
netdev_set_queue(iface->netdev, queue_id, &details);
shash_destroy(&details);
}
}
}
/* Port mirroring. */ /* Port mirroring. */

View File

@ -22,8 +22,18 @@
"next_cfg": { "next_cfg": {
"type": "integer"}, "type": "integer"},
"cur_cfg": { "cur_cfg": {
"type": "integer"}}, "type": "integer"},
"capabilities": {
"type": {"key": "string",
"value": {"type": "uuid",
"refTable": "Capability"},
"min": 0, "max": "unlimited"}}},
"maxRows": 1}, "maxRows": 1},
"Capability": {
"columns": {
"details": {
"type": {"key": "string", "value": "string",
"min": 0, "max": "unlimited"}}}},
"Bridge": { "Bridge": {
"columns": { "columns": {
"name": { "name": {
@ -80,6 +90,10 @@
"minInteger": 0, "minInteger": 0,
"maxInteger": 4095}, "maxInteger": 4095},
"min": 0, "max": 1}}, "min": 0, "max": 1}},
"qos": {
"type": {"key": {"type": "uuid",
"refTable": "QoS"},
"min": 0, "max": 1}},
"mac": { "mac": {
"type": {"key": {"type": "string"}, "type": {"key": {"type": "string"},
"min": 0, "max": 1}}, "min": 0, "max": 1}},
@ -117,6 +131,25 @@
"ofport": { "ofport": {
"type": {"key": "integer", "min": 0, "max": 1}, "type": {"key": "integer", "min": 0, "max": 1},
"ephemeral": true}}}, "ephemeral": true}}},
"QoS": {
"columns": {
"type": {
"type": "string"},
"queues": {
"type": {"key": {"type": "integer",
"minInteger": 0,
"maxInteger": 4294967295},
"value": {"type": "uuid",
"refTable": "Queue"},
"min": 0, "max": "unlimited"}},
"other_config": {
"type": {"key": "string", "value": "string",
"min": 0, "max": "unlimited"}}}},
"Queue": {
"columns": {
"other_config": {
"type": {"key": "string", "value": "string",
"min": 0, "max": "unlimited"}}}},
"Mirror": { "Mirror": {
"columns": { "columns": {
"name": { "name": {

View File

@ -56,6 +56,14 @@
<ref column="next_cfg"/> after it finishes applying a set of <ref column="next_cfg"/> after it finishes applying a set of
configuration changes. configuration changes.
</column> </column>
<column name="capabilities">
Describes functionality supported by the hardware and software platform
on which this Open vSwitch is based. Clients should not modify this
column. See the <ref table="Capability"/> description for defined
capability categories and the meaning of associated
<ref table="Capability"/> records.
</column>
</group> </group>
</table> </table>
@ -253,6 +261,10 @@
</group> </group>
<group title="Other Features"> <group title="Other Features">
<column name="qos">
Quality of Service configuration for this port.
</column>
<column name="mac"> <column name="mac">
The MAC address to use for this port for the purpose of choosing the The MAC address to use for this port for the purpose of choosing the
bridge's MAC address. This column does not necessarily reflect the bridge's MAC address. This column does not necessarily reflect the
@ -509,6 +521,87 @@
</group> </group>
</table> </table>
<table name="QoS" title="Quality of Service configuration">
<p>Quality of Service (QoS) configuration for each Port that
references it.</p>
<column name="type">
<p>The type of QoS to implement. The <ref table="Open_vSwitch"
column="capabilities"/> column in the <ref table="Open_vSwitch"/> table
identifies the types that a switch actually supports. The currently
defined types are listed below:</p>
<dl>
<dt><code>linux-htb</code></dt>
<dd>Linux ``hierarchy token bucket'' classifier.</dd>
</dl>
</column>
<column name="queues">
<p>A map from queue numbers to <ref table="Queue"/> records. The
supported range of queue numbers depend on <ref column="type"/>. The
queue numbers are the same as the <code>queue_id</code> used in
OpenFlow in <code>struct ofp_action_enqueue</code> and other
structures. Queue 0 is used by OpenFlow output actions that do not
specify a specific queue.</p>
</column>
<column name="other_config">
<p>Key-value pairs for configuring QoS features that depend on
<ref column="type"/>.</p>
<p>The <code>linux-htb</code> class supports the following key-value
pairs:</p>
<dl>
<dt><code>max-rate</code></dt>
<dd>Maximum rate shared by all queued traffic, in bit/s.
Optional. If not specified, for physical interfaces, the
default is the link rate. For other interfaces or if the
link rate cannot be determined, the default is currently 100
Mbps.</dd>
</dl>
</column>
</table>
<table name="Queue" title="QoS output queue.">
<p>A configuration for a port output queue, used in configuring Quality of
Service (QoS) features. May be referenced by <ref column="queues"
table="QoS"/> column in <ref table="QoS"/> table.</p>
<column name="other_config">
<p>Key-value pairs for configuring the output queue. The supported
key-value pairs and their meanings depend on the <ref column="type"/>
of the <ref column="QoS"/> records that reference this row.</p>
<p>The key-value pairs defined for <ref table="QoS"/> <ref table="QoS"
column="type"/> of <code>min-rate</code> are:</p>
<dl>
<dt><code>min-rate</code></dt>
<dd>Minimum guaranteed bandwidth, in bit/s. Required.</dd>
</dl>
<p>The key-value pairs defined for <ref table="QoS"/> <ref table="QoS"
column="type"/> of <code>linux-htb</code> are:</p>
<dl>
<dt><code>min-rate</code></dt>
<dd>Minimum guaranteed bandwidth, in bit/s. Required.</dd>
<dt><code>max-rate</code></dt>
<dd>Maximum allowed bandwidth, in bit/s. Optional. If specified, the
queue's rate will not be allowed to exceed the specified value, even
if excess bandwidth is available. If unspecified, defaults to no
limit.</dd>
<dt><code>burst</code></dt>
<dd>Burst size, in bits. This is the maximum amount of ``credits''
that a queue can accumulate while it is idle. Optional. Details of
the <code>linux-htb</code> implementation require a minimum burst
size, so a too-small <code>burst</code> will be silently
ignored.</dd>
<dt><code>priority</code></dt>
<dd>A nonnegative 32-bit integer. Defaults to 0 if
unspecified. A queue with a smaller <code>priority</code>
will receive all the excess bandwidth that it can use before
a queue with a larger value receives any. Specific priority
values are unimportant; only relative ordering matters.</dd>
</dl>
</column>
</table>
<table name="Mirror" title="Port mirroring (SPAN/RSPAN)."> <table name="Mirror" title="Port mirroring (SPAN/RSPAN).">
<p>A port mirror within a <ref table="Bridge"/>.</p> <p>A port mirror within a <ref table="Bridge"/>.</p>
<p>A port mirror configures a bridge to send selected frames to special <p>A port mirror configures a bridge to send selected frames to special
@ -920,4 +1013,46 @@
<code><var>ip</var>:<var>port</var></code>. <code><var>ip</var>:<var>port</var></code>.
</column> </column>
</table> </table>
<table name="Capability">
<p>Records in this table describe functionality supported by the hardware
and software platform on which this Open vSwitch is based. Clients
should not modify this table.</p>
<p>A record in this table is meaningful only if it is referenced by the
<ref table="Open_vSwitch" column="capabilities"/> column in the
<ref table="Open_vSwitch"/> table. The key used to reference it, called
the record's ``category,'' determines the meanings of the
<ref column="details"/> column. The following general forms of
categories are currently defined:</p>
<dl>
<dt><code>qos-<var>type</var></code></dt>
<dd><var>type</var> is supported as the value for
<ref column="type" table="QoS"/> in the <ref table="QoS"/> table.
</dd>
</dl>
<column name="details">
<p>Key-value pairs that describe capabilities. The meaning of the pairs
depends on the category key that the <ref table="Open_vSwitch"
column="capabilities"/> column in the <ref table="Open_vSwitch"/> table
uses to reference this record, as described above.</p>
<p>The presence of a record for category <code>qos-<var>type</var></code>
indicates that the switch supports <var>type</var> as the value of
the <ref table="QoS" column="type"/> column in the <ref table="QoS"/>
table. The following key-value pairs are defined to further describe
QoS capabilities:</p>
<dl>
<dt><code>n-queues</code></dt>
<dd>Number of supported queues, as a positive integer. Keys in the
<ref table="QoS" column="queues"/> column for <ref table="QoS"/>
records whose <ref table="QoS" column="type"/> value
equals <var>type</var> must range between 0 and this value minus one,
inclusive.</dd>
</dl>
</column>
</table>
</database> </database>