2
0
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:
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
* 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;

View File

@ -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. */

View File

@ -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 {

View File

@ -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 */

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, /* 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 */

View File

@ -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.
*

View File

@ -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 = &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)),
* 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

View File

@ -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 *);

View File

@ -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 *

View File

@ -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 *);

View File

@ -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);

View File

@ -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>

View File

@ -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
@ -32,6 +34,8 @@ class Ui_MainWindow(object):
self.gridLayout_2.setObjectName("gridLayout_2")
self.BridgeTable = QtGui.QTableWidget(self.Bridge)
self.BridgeTable.setObjectName("BridgeTable")
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()
@ -40,6 +44,8 @@ class Ui_MainWindow(object):
self.gridLayout_3.setObjectName("gridLayout_3")
self.ControllerTable = QtGui.QTableWidget(self.Controller)
self.ControllerTable.setObjectName("ControllerTable")
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()
@ -48,6 +54,8 @@ class Ui_MainWindow(object):
self.gridLayout_4.setObjectName("gridLayout_4")
self.InterfaceTable = QtGui.QTableWidget(self.Interface)
self.InterfaceTable.setObjectName("InterfaceTable")
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()
@ -56,6 +64,8 @@ class Ui_MainWindow(object):
self.gridLayout_5.setObjectName("gridLayout_5")
self.MirrorTable = QtGui.QTableWidget(self.Mirror)
self.MirrorTable.setObjectName("MirrorTable")
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()
@ -64,6 +74,8 @@ class Ui_MainWindow(object):
self.gridLayout_6.setObjectName("gridLayout_6")
self.NetFlowTable = QtGui.QTableWidget(self.NetFlow)
self.NetFlowTable.setObjectName("NetFlowTable")
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()
@ -72,6 +84,8 @@ class Ui_MainWindow(object):
self.gridLayout_7.setObjectName("gridLayout_7")
self.Open_vSwitchTable = QtGui.QTableWidget(self.Open_vSwitch)
self.Open_vSwitchTable.setObjectName("Open_vSwitchTable")
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()
@ -80,23 +94,49 @@ class Ui_MainWindow(object):
self.gridLayout_8.setObjectName("gridLayout_8")
self.PortTable = QtGui.QTableWidget(self.Port)
self.PortTable.setObjectName("PortTable")
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.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.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()
@ -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))

View File

@ -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}}},

View File

@ -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. */

View File

@ -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": {

View File

@ -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>