mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 09:58:01 +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:
parent
a90b56b770
commit
c1c9c9c4b6
@ -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
|
||||
* is slightly obscure just to avoid that. */
|
||||
int prev_port = -1;
|
||||
u32 priority = skb->priority;
|
||||
int err;
|
||||
|
||||
if (dp->sflow_probability) {
|
||||
@ -516,6 +517,14 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
|
||||
case ODPAT_SET_TP_DST:
|
||||
skb = set_tp_port(skb, key, &a->tp_port, gfp);
|
||||
break;
|
||||
|
||||
case ODPAT_SET_PRIORITY:
|
||||
skb->priority = a->priority.priority;
|
||||
break;
|
||||
|
||||
case ODPAT_POP_PRIORITY:
|
||||
skb->priority = priority;
|
||||
break;
|
||||
}
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
@ -419,6 +419,18 @@ struct ofp_action_header {
|
||||
};
|
||||
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 {
|
||||
uint16_t type;
|
||||
struct ofp_action_header header;
|
||||
@ -713,8 +725,8 @@ enum ofp_stats_types {
|
||||
OFPST_PORT,
|
||||
|
||||
/* Queue statistics for a port
|
||||
* The request body defines the port
|
||||
* The reply body is an array of struct ofp_queue_stats */
|
||||
* The request body is struct ofp_queue_stats_request.
|
||||
* The reply body is an array of struct ofp_queue_stats. */
|
||||
OFPST_QUEUE,
|
||||
|
||||
/* Vendor extension.
|
||||
@ -859,6 +871,29 @@ struct ofp_port_stats {
|
||||
};
|
||||
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. */
|
||||
struct ofp_vendor_header {
|
||||
struct ofp_header header; /* Type OFPT_VENDOR. */
|
||||
|
@ -279,7 +279,9 @@ struct odp_flowvec {
|
||||
#define ODPAT_SET_TP_SRC 11 /* TCP/UDP source port. */
|
||||
#define ODPAT_SET_TP_DST 12 /* TCP/UDP destination port. */
|
||||
#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 {
|
||||
uint16_t type; /* ODPAT_OUTPUT. */
|
||||
@ -353,6 +355,13 @@ struct odp_action_tp_port {
|
||||
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 {
|
||||
uint16_t type;
|
||||
struct odp_action_output output;
|
||||
@ -365,6 +374,7 @@ union odp_action {
|
||||
struct odp_action_nw_addr nw_addr;
|
||||
struct odp_action_nw_tos nw_tos;
|
||||
struct odp_action_tp_port tp_port;
|
||||
struct odp_action_priority priority;
|
||||
};
|
||||
|
||||
struct odp_execute {
|
||||
|
@ -256,7 +256,18 @@ const struct netdev_class netdev_gre_class = {
|
||||
NULL, /* get_features */
|
||||
NULL, /* set_advertisements */
|
||||
NULL, /* get_vlan_vid */
|
||||
|
||||
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, /* set_in4 */
|
||||
|
1616
lib/netdev-linux.c
1616
lib/netdev-linux.c
File diff suppressed because it is too large
Load Diff
@ -207,7 +207,18 @@ const struct netdev_class netdev_patch_class = {
|
||||
NULL, /* get_features */
|
||||
NULL, /* set_advertisements */
|
||||
NULL, /* get_vlan_vid */
|
||||
|
||||
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, /* set_in4 */
|
||||
|
@ -313,6 +313,155 @@ struct netdev_class {
|
||||
int (*set_policing)(struct netdev *netdev, unsigned int kbits_rate,
|
||||
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
|
||||
* address and '*netmask' to the associated netmask.
|
||||
*
|
||||
|
279
lib/netdev.c
279
lib/netdev.c
@ -963,6 +963,285 @@ netdev_set_policing(struct netdev *netdev, uint32_t kbits_rate,
|
||||
: 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 = ∅
|
||||
}
|
||||
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)),
|
||||
* 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
|
||||
|
57
lib/netdev.h
57
lib/netdev.h
@ -97,6 +97,7 @@ int netdev_register_provider(const struct netdev_class *);
|
||||
int netdev_unregister_provider(const char *type);
|
||||
void netdev_enumerate_types(struct svec *types);
|
||||
|
||||
/* Open and close. */
|
||||
int netdev_open(struct netdev_options *, struct netdev **);
|
||||
int netdev_open_default(const char *name, struct netdev **);
|
||||
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 *);
|
||||
|
||||
/* Basic properties. */
|
||||
const char *netdev_get_name(const struct netdev *);
|
||||
const char *netdev_get_type(const struct netdev *);
|
||||
int netdev_get_mtu(const struct netdev *, int *mtup);
|
||||
int netdev_get_ifindex(const struct netdev *);
|
||||
|
||||
/* Packet send and receive. */
|
||||
int netdev_recv(struct netdev *, struct ofpbuf *);
|
||||
void netdev_recv_wait(struct netdev *);
|
||||
int netdev_drain(struct netdev *);
|
||||
@ -119,9 +122,11 @@ int netdev_drain(struct netdev *);
|
||||
int netdev_send(struct netdev *, const struct ofpbuf *);
|
||||
void netdev_send_wait(struct netdev *);
|
||||
|
||||
/* Hardware address. */
|
||||
int netdev_set_etheraddr(struct netdev *, const 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_features(struct netdev *,
|
||||
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);
|
||||
int netdev_set_advertisements(struct netdev *, uint32_t advertise);
|
||||
|
||||
/* TCP/IP stack interface. */
|
||||
int netdev_get_in4(const struct netdev *, struct in_addr *address,
|
||||
struct in_addr *netmask);
|
||||
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_turn_flags_on(struct netdev *, enum netdev_flags, bool permanent);
|
||||
int netdev_turn_flags_off(struct netdev *, enum netdev_flags, bool permanent);
|
||||
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_vlan_vid(const struct netdev *, int *vlan_vid);
|
||||
struct netdev *netdev_find_dev_by_in4(const struct in_addr *);
|
||||
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);
|
||||
void netdev_monitor_destroy(struct netdev_monitor *);
|
||||
int netdev_monitor_add(struct netdev_monitor *, struct netdev *);
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "ofpbuf.h"
|
||||
#include "packets.h"
|
||||
#include "random.h"
|
||||
#include "xtoxll.h"
|
||||
|
||||
#define THIS_MODULE VLM_ofp_util
|
||||
#include "vlog.h"
|
||||
@ -489,8 +490,11 @@ check_action_exact_len(const union ofp_action *a, unsigned int len,
|
||||
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
|
||||
check_action_port(int port, int max_ports)
|
||||
check_output_port(uint16_t port, int max_ports)
|
||||
{
|
||||
switch (port) {
|
||||
case OFPP_IN_PORT:
|
||||
@ -503,7 +507,7 @@ check_action_port(int port, int max_ports)
|
||||
return 0;
|
||||
|
||||
default:
|
||||
if (port >= 0 && port < max_ports) {
|
||||
if (port < max_ports) {
|
||||
return 0;
|
||||
}
|
||||
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
|
||||
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)) {
|
||||
case OFPAT_OUTPUT:
|
||||
error = check_action_port(ntohs(a->output.port), max_ports);
|
||||
return error ? error : check_action_exact_len(a, len, 8);
|
||||
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_PCP:
|
||||
@ -561,6 +593,9 @@ check_action(const union ofp_action *a, unsigned int len, int max_ports)
|
||||
? check_nicira_action(a, len)
|
||||
: ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR));
|
||||
|
||||
case OFPAT_ENQUEUE:
|
||||
return check_enqueue_action(a, len, max_ports);
|
||||
|
||||
default:
|
||||
VLOG_WARN_RL(&bad_ofmsg_rl, "unknown action type %"PRIu16,
|
||||
ntohs(a->type));
|
||||
@ -603,6 +638,21 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
|
||||
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
|
||||
* previously validated with validate_actions(). */
|
||||
const union ofp_action *
|
||||
|
@ -18,6 +18,7 @@
|
||||
#define OFP_UTIL_H 1
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.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 *);
|
||||
int validate_actions(const union ofp_action *, size_t n_actions,
|
||||
int max_ports);
|
||||
bool action_outputs_to_port(const union ofp_action *, uint16_t port);
|
||||
|
||||
void normalize_match(struct ofp_match *);
|
||||
|
||||
|
@ -59,6 +59,9 @@
|
||||
#include "vconn.h"
|
||||
#include "xtoxll.h"
|
||||
|
||||
#include <linux/types.h> /* XXX */
|
||||
#include <linux/pkt_sched.h> /* XXX */
|
||||
|
||||
#define THIS_MODULE VLM_ofproto
|
||||
#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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -2070,15 +2073,11 @@ is_controller_rule(struct rule *rule)
|
||||
* NetFlow expiration messages since it is just part of the control
|
||||
* logic for the network and not real traffic. */
|
||||
|
||||
if (rule && rule->super) {
|
||||
struct rule *super = rule->super;
|
||||
|
||||
return super->n_actions == 1 &&
|
||||
super->actions[0].type == htons(OFPAT_OUTPUT) &&
|
||||
super->actions[0].output.port == htons(OFPP_CONTROLLER);
|
||||
}
|
||||
|
||||
return false;
|
||||
return (rule
|
||||
&& rule->super
|
||||
&& rule->super->n_actions == 1
|
||||
&& action_outputs_to_port(&rule->super->actions[0],
|
||||
htons(OFPP_CONTROLLER)));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2195,7 +2194,8 @@ handle_features_request(struct ofproto *p, struct ofconn *ofconn,
|
||||
(1u << OFPAT_SET_NW_DST) |
|
||||
(1u << OFPAT_SET_NW_TOS) |
|
||||
(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) {
|
||||
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
|
||||
xlate_nicira_action(struct action_xlate_ctx *ctx,
|
||||
const struct nx_action_header *nah)
|
||||
@ -2446,7 +2488,7 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
|
||||
break;
|
||||
|
||||
/* 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:
|
||||
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);
|
||||
break;
|
||||
|
||||
case OFPAT_ENQUEUE:
|
||||
xlate_enqueue_action(ctx, (const struct ofp_action_enqueue *) ia);
|
||||
break;
|
||||
|
||||
default:
|
||||
VLOG_DBG_RL(&rl, "unknown action type %"PRIu16, type);
|
||||
break;
|
||||
@ -2567,6 +2613,7 @@ xlate_actions(const union ofp_action *in, size_t n_in,
|
||||
ctx.may_set_up_flow = true;
|
||||
ctx.nf_output_iface = NF_OUT_DROP;
|
||||
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
|
||||
* flow. */
|
||||
@ -3144,6 +3191,95 @@ handle_aggregate_stats_request(struct ofproto *p, struct ofconn *ofconn,
|
||||
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
|
||||
handle_stats_request(struct ofproto *p, struct ofconn *ofconn,
|
||||
struct ofp_header *oh)
|
||||
@ -3175,6 +3311,9 @@ handle_stats_request(struct ofproto *p, struct ofconn *ofconn,
|
||||
case OFPST_PORT:
|
||||
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:
|
||||
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
|
||||
|
||||
|
@ -92,6 +92,26 @@
|
||||
</item>
|
||||
</layout>
|
||||
</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">
|
||||
<attribute name="title">
|
||||
<string>sFlow</string>
|
||||
|
@ -1,15 +1,17 @@
|
||||
# -*- 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
|
||||
# by: PyQt4 UI code generator 4.4.2
|
||||
# Created: Mon May 17 16:23:47 2010
|
||||
# by: PyQt4 UI code generator 4.7.3
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
|
||||
try:
|
||||
from OVEStandard import globalForcePySide
|
||||
if globalForcePySide: raise Exception()
|
||||
if globalForcePySide:
|
||||
raise Exception()
|
||||
from PyQt4 import QtCore, QtGui
|
||||
except:
|
||||
from PySide import QtCore, QtGui
|
||||
@ -17,7 +19,7 @@ except:
|
||||
class Ui_MainWindow(object):
|
||||
def setupUi(self, MainWindow):
|
||||
MainWindow.setObjectName("MainWindow")
|
||||
MainWindow.resize(800,600)
|
||||
MainWindow.resize(800, 600)
|
||||
self.centralwidget = QtGui.QWidget(MainWindow)
|
||||
self.centralwidget.setObjectName("centralwidget")
|
||||
self.gridLayout = QtGui.QGridLayout(self.centralwidget)
|
||||
@ -32,72 +34,110 @@ class Ui_MainWindow(object):
|
||||
self.gridLayout_2.setObjectName("gridLayout_2")
|
||||
self.BridgeTable = QtGui.QTableWidget(self.Bridge)
|
||||
self.BridgeTable.setObjectName("BridgeTable")
|
||||
self.gridLayout_2.addWidget(self.BridgeTable,0,0,1,1)
|
||||
self.tabWidget.addTab(self.Bridge,"")
|
||||
self.BridgeTable.setColumnCount(0)
|
||||
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.setObjectName("Controller")
|
||||
self.gridLayout_3 = QtGui.QGridLayout(self.Controller)
|
||||
self.gridLayout_3.setObjectName("gridLayout_3")
|
||||
self.ControllerTable = QtGui.QTableWidget(self.Controller)
|
||||
self.ControllerTable.setObjectName("ControllerTable")
|
||||
self.gridLayout_3.addWidget(self.ControllerTable,0,0,1,1)
|
||||
self.tabWidget.addTab(self.Controller,"")
|
||||
self.ControllerTable.setColumnCount(0)
|
||||
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.setObjectName("Interface")
|
||||
self.gridLayout_4 = QtGui.QGridLayout(self.Interface)
|
||||
self.gridLayout_4.setObjectName("gridLayout_4")
|
||||
self.InterfaceTable = QtGui.QTableWidget(self.Interface)
|
||||
self.InterfaceTable.setObjectName("InterfaceTable")
|
||||
self.gridLayout_4.addWidget(self.InterfaceTable,0,0,1,1)
|
||||
self.tabWidget.addTab(self.Interface,"")
|
||||
self.InterfaceTable.setColumnCount(0)
|
||||
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.setObjectName("Mirror")
|
||||
self.gridLayout_5 = QtGui.QGridLayout(self.Mirror)
|
||||
self.gridLayout_5.setObjectName("gridLayout_5")
|
||||
self.MirrorTable = QtGui.QTableWidget(self.Mirror)
|
||||
self.MirrorTable.setObjectName("MirrorTable")
|
||||
self.gridLayout_5.addWidget(self.MirrorTable,0,0,1,1)
|
||||
self.tabWidget.addTab(self.Mirror,"")
|
||||
self.MirrorTable.setColumnCount(0)
|
||||
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.setObjectName("NetFlow")
|
||||
self.gridLayout_6 = QtGui.QGridLayout(self.NetFlow)
|
||||
self.gridLayout_6.setObjectName("gridLayout_6")
|
||||
self.NetFlowTable = QtGui.QTableWidget(self.NetFlow)
|
||||
self.NetFlowTable.setObjectName("NetFlowTable")
|
||||
self.gridLayout_6.addWidget(self.NetFlowTable,0,0,1,1)
|
||||
self.tabWidget.addTab(self.NetFlow,"")
|
||||
self.NetFlowTable.setColumnCount(0)
|
||||
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.setObjectName("Open_vSwitch")
|
||||
self.gridLayout_7 = QtGui.QGridLayout(self.Open_vSwitch)
|
||||
self.gridLayout_7.setObjectName("gridLayout_7")
|
||||
self.Open_vSwitchTable = QtGui.QTableWidget(self.Open_vSwitch)
|
||||
self.Open_vSwitchTable.setObjectName("Open_vSwitchTable")
|
||||
self.gridLayout_7.addWidget(self.Open_vSwitchTable,0,0,1,1)
|
||||
self.tabWidget.addTab(self.Open_vSwitch,"")
|
||||
self.Open_vSwitchTable.setColumnCount(0)
|
||||
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.setObjectName("Port")
|
||||
self.gridLayout_8 = QtGui.QGridLayout(self.Port)
|
||||
self.gridLayout_8.setObjectName("gridLayout_8")
|
||||
self.PortTable = QtGui.QTableWidget(self.Port)
|
||||
self.PortTable.setObjectName("PortTable")
|
||||
self.gridLayout_8.addWidget(self.PortTable,0,0,1,1)
|
||||
self.tabWidget.addTab(self.Port,"")
|
||||
self.PortTable.setColumnCount(0)
|
||||
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.setObjectName("sFlow")
|
||||
self.gridLayout_9 = QtGui.QGridLayout(self.sFlow)
|
||||
self.gridLayout_9.setObjectName("gridLayout_9")
|
||||
self.sFlowTable = QtGui.QTableWidget(self.sFlow)
|
||||
self.sFlowTable.setObjectName("sFlowTable")
|
||||
self.gridLayout_9.addWidget(self.sFlowTable,0,0,1,1)
|
||||
self.tabWidget.addTab(self.sFlow,"")
|
||||
self.sFlowTable.setColumnCount(0)
|
||||
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.setObjectName("SSL")
|
||||
self.gridLayout_10 = QtGui.QGridLayout(self.SSL)
|
||||
self.gridLayout_10.setObjectName("gridLayout_10")
|
||||
self.gridLayout_101 = QtGui.QGridLayout(self.SSL)
|
||||
self.gridLayout_101.setObjectName("gridLayout_101")
|
||||
self.SSLTable = QtGui.QTableWidget(self.SSL)
|
||||
self.SSLTable.setObjectName("SSLTable")
|
||||
self.gridLayout_10.addWidget(self.SSLTable,0,0,1,1)
|
||||
self.tabWidget.addTab(self.SSL,"")
|
||||
self.SSLTable.setColumnCount(0)
|
||||
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.horizontalLayout = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
@ -116,16 +156,16 @@ class Ui_MainWindow(object):
|
||||
self.intervalSpinBox.setMaximum(1000000)
|
||||
self.intervalSpinBox.setObjectName("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.fetchButton = QtGui.QPushButton(self.centralwidget)
|
||||
self.fetchButton.setObjectName("fetchButton")
|
||||
self.horizontalLayout.addWidget(self.fetchButton)
|
||||
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)
|
||||
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.menuFile = QtGui.QMenu(self.menubar)
|
||||
self.menuFile.setObjectName("menuFile")
|
||||
@ -158,41 +198,16 @@ class Ui_MainWindow(object):
|
||||
|
||||
def retranslateUi(self, MainWindow):
|
||||
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.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.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.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.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.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.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.sFlowTable.clear()
|
||||
self.sFlowTable.setColumnCount(0)
|
||||
self.sFlowTable.setRowCount(0)
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.QoS), QtGui.QApplication.translate("MainWindow", "QoS", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.Queue), QtGui.QApplication.translate("MainWindow", "Queue", 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.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))
|
||||
|
@ -1904,6 +1904,14 @@ static const struct vsctl_table_class tables[] = {
|
||||
{{&ovsrec_table_port, &ovsrec_port_col_name, 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_open_vswitch, NULL, &ovsrec_open_vswitch_col_ssl}}},
|
||||
|
||||
|
@ -253,6 +253,7 @@ static struct iface *iface_from_dp_ifidx(const struct bridge *,
|
||||
uint16_t dp_ifidx);
|
||||
static bool iface_is_internal(const struct bridge *, const char *name);
|
||||
static void iface_set_mac(struct iface *);
|
||||
static void iface_update_qos(struct iface *, const struct ovsrec_qos *);
|
||||
|
||||
/* Hooks into ofproto processing. */
|
||||
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) {
|
||||
for (i = 0; i < br->n_ports; i++) {
|
||||
struct port *port = br->ports[i];
|
||||
int j;
|
||||
|
||||
port_update_vlan_compat(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) {
|
||||
@ -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. */
|
||||
|
||||
|
@ -22,8 +22,18 @@
|
||||
"next_cfg": {
|
||||
"type": "integer"},
|
||||
"cur_cfg": {
|
||||
"type": "integer"}},
|
||||
"type": "integer"},
|
||||
"capabilities": {
|
||||
"type": {"key": "string",
|
||||
"value": {"type": "uuid",
|
||||
"refTable": "Capability"},
|
||||
"min": 0, "max": "unlimited"}}},
|
||||
"maxRows": 1},
|
||||
"Capability": {
|
||||
"columns": {
|
||||
"details": {
|
||||
"type": {"key": "string", "value": "string",
|
||||
"min": 0, "max": "unlimited"}}}},
|
||||
"Bridge": {
|
||||
"columns": {
|
||||
"name": {
|
||||
@ -80,6 +90,10 @@
|
||||
"minInteger": 0,
|
||||
"maxInteger": 4095},
|
||||
"min": 0, "max": 1}},
|
||||
"qos": {
|
||||
"type": {"key": {"type": "uuid",
|
||||
"refTable": "QoS"},
|
||||
"min": 0, "max": 1}},
|
||||
"mac": {
|
||||
"type": {"key": {"type": "string"},
|
||||
"min": 0, "max": 1}},
|
||||
@ -117,6 +131,25 @@
|
||||
"ofport": {
|
||||
"type": {"key": "integer", "min": 0, "max": 1},
|
||||
"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": {
|
||||
"columns": {
|
||||
"name": {
|
||||
|
@ -56,6 +56,14 @@
|
||||
<ref column="next_cfg"/> after it finishes applying a set of
|
||||
configuration changes.
|
||||
</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>
|
||||
</table>
|
||||
|
||||
@ -253,6 +261,10 @@
|
||||
</group>
|
||||
|
||||
<group title="Other Features">
|
||||
<column name="qos">
|
||||
Quality of Service configuration for this port.
|
||||
</column>
|
||||
|
||||
<column name="mac">
|
||||
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
|
||||
@ -509,6 +521,87 @@
|
||||
</group>
|
||||
</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).">
|
||||
<p>A port mirror within a <ref table="Bridge"/>.</p>
|
||||
<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>.
|
||||
</column>
|
||||
</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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user