This text provides notes about the OF-CONFIG server implementation. First, we describe general overview of the OF-CONFIG implementation. Then we describe how the particular OF-CONFIG operations are implemented and finally we discuss how the specific OF-CONFIG configuration and state parameters are implemented. This part of the text is based on the division of the OF-CONFIG YANG data model parameters from the OF-CONFIG – OVSDB compatibility notes. We implemented parameters that:
- were directly mapped to the OVSDB,
- are applicable using some standard system tools/calls or
- are internally used by OF-CONFIG server.
Also the parameters from the “ambiguous meaning” category were implemented after clarifying their meaning.
The libnetconf library allows two different approaches to integrate a device configuration – a transAPI module or a datastore implementation. TransAPI modules allow rapid and easy development of a standalone module communicating and controlling a specific device or application. The datastore implementation is more complex, but it allows a tighter connection between the NETCONF (OF-CONFIG) server and the controlled device, since it allows the configuration server to directly use the configuration datastore of the device and better application of all OF-CONFIG operations to it.
The OVS project provides OVSDB Interface Definition Language (OVSDB IDL) (see Section [sec:ovsdb-interaction] for more details) which nicely fits into the second approach. Therefore, we decided to create a custom libnetconf datastore implementation for the OVS. However, the datastore is limited to the configuration data. The state data are not expected here, so we will implement also a simple transAPI module for providing status information. Both the custom datastore implementation as well as the transAPI module are going to share the source code (and probably some run-time data) to make things more simple and to avoid code duplication.
Communication with OVSDB for 1) obtaining status data and synchronizing configuration data as well as for 2) modifying configuration data of the OVS will be a core functionality of our OF-CONFIG server. There are two ways of interacting with the OVSDB server. Both are provided directly as libraries in the OVS project.
The first, lower level, way is to use the JSON-RPC interface directly by constructing and parsing JSON-RPC meassages according to the OVSDB specification . The second way is to utilize higher level API provided by one of OVS development libraries – OVSDB IDL. It maintains an in-memory copy of the OVSDB. So, while the client simply manipulates the local copy of the data, OVSDB IDL keeps it up-to-date and applies local changes to the OVSDB server by issuing any necessary JSON-RPC messages. Both APIs are available under the lib/ directory of the OVS source codes and as part of the openvswitch-devel package (the name can differ on different Linux distributions).
The first lower level approach is more flexible. However, we do not need this flexibility and we would need to implement functionality provided by the OVSDB IDL anyway. We plan to implement the OF-CONFIG server for OVS as a special implementation of the libnetconf datastore and the OVSDB IDL nicely fits into this approach. We propose to create an in-memory copy of the OVSDB database in the OF-CONFIG server. The data described in as directly mappable to OVSDB will be transformed from the OF-CONFIG format to the data structures provided by the OVSDB IDL API. The synchronization with the OVSDB server will be done automatically by the OVSDB IDL.
The description of OVSDB IDL usage as well as the provided data structures can be found inside the Section [sec:params-mapping].
Here we describe how the basic OF-CONFIG operations will be implemented by the OF-CONFIG server and, when necessary, how will they be mapped to the OVSDB IDL usage.
It should be noted that OVSDB IDL will handle only the running datastore. The startup and candidate datastores will be stored in the local files managed by the OF-CONFIG server. Their implementation will be taken from the current libnetconf file datastore implementation. Therefore, the following paragraphs focus on operations targeting the running datastore.
Almost for all operations (except <close-session> and <kill-session>) we need to transform data from the OF-CONFIG format (XML) to the OVSDB IDL format (internal C data structures) and vice versa. Since we can focus on a single data model, the mapping is not generic and therefore quite simple. For internal purposes we will need translation functions to be able to translate a specific OF-CONFIG parameter (especially for the <edit-config>) as well as a complete data (sub)tree (in case of e.g. <copy-config>).
The Section [sec:params-mapping] discusses how specific parts of the OF-CONFIG data maps to the OVSDB IDL data structures and how will the system tools be used. Besides the OVSDB IDL structures, we will need to also use several system tools or system calls as mentioned in the previous report . The details are also mentioned in the Section [sec:params-mapping].
<get-config> is a simple operation since we use automatic synchronization provided by OVSDB IDL. The only needed thing is to map OVSDB IDL structures into the XML form of the OF-CONFIG data. The description of this mapping can be found in Section [sec:params-mapping].
The <get> operation extends the previous <get-config> by providing status information in addition to the configuration data. In the libnetconf library, this part is actually covered by the transAPI module. So the datastore implementation part is the same as in the case of the <get-config> operation and status information is provided by the function from the transAPI module. To avoid code duplication, we will implement both, the custom datastore and transAPI callbacks. So the transAPI callback get_state_data() providing status information will also be able to get data from OVSDB IDL. The description of this mapping can be found in Section [sec:params-mapping].
source running
The retrieval of source data is transformed to <get-config> with the running datastore as the target.
target running
The inverse function to the <get-config> operation. Here we map OF-CONFIG data in the XML format to the OVSDB IDL structure. However, we use the same rules described in the Section [sec:params-mapping]. Note that because we are replacing the complete configuration before we start writing the new configuration data to the OVSDB structure, we have to remove all the previous configuration and make the database empty (perform <delete-config> operation).
Simply remove all the content from the OVSDB IDL data structures. It may remove even data not covered by the OF-CONFIG data model (mainly due to a garbage collection).
This is the most challenging operation when implementing libnetconf datastore. We need to parse the <edit-config> request and be able to remove, create, or update every single element from the OF-CONFIG data. The remove and create must also be applicable for larger data sets (subtrees). We can begin with a standard libnetconf file datastore implementation of the <edit-config>, but instead of updating the XML tree, we will need to store changes to the OVSDB IDL structures. Significant advantage, in comparison to a generic libnetconf file datastore implementation of the <edit-config>, is that we can focus only on the specific data model.
target running
The OVSDB does not implement any common mandatory locks. There are <lock>, <unlock> and <steal> JSON-RPC operations that provide advisory locking mechanism. There is no way how to force a generic OVSDB client using JSON-RPC interface to follow the advisory locks retrieved by an OF-CONFIG’s session.
OVSDB IDL contains a few functions that are related to locking. For the <lock> operation, there is <ovsdb_idl_set_lock()> that creates a lock request and <ovsdb_idl_has_lock()> to check whether the lock has been acquired. There is an internal mechanism in OVSDB IDL that handles locking after the initialization of an OVSDB IDL instance. Unfortunately, there is no public (non-static) function that would generate an <unlock> request by OVSDB IDL[3].
Therefore, NETCONF <lock> and <unlock> can affect only NETCONF clients. There is no way how to prevent other users of OVS from manipulating the OVSDB using a locking mechanism of OVSDB IDL or JSON-RPC.
These operations do not affect configuration datastores. The request will be processed internally in a standard way. No communication with OVSDB or any other tool will be needed.
OVSDB IDL is initialized by the ovsdb_idl_create() function:
struct ovsdb_idl *ovsdb_idl_create(const char *remote,
const struct ovsdb_idl_class *,
bool monitor_everything_by_default,
bool retry);The remote is the most important parameter because it is used to pass the path of the OVSDB communication socket. This parameter should be configurable for the OF-CONFIG server since it is system and installation dependent for OVS. The proposed approach is to let users to set path to the socket by a configure script or/and a command line parameter. In future, this could be covered by an augment OVS-specific YANG model for the OF-CONFIG YANG data model.
The monitor_everything_by_default and retry parameters will probably be constantly set to true. In addition, local OVSDB tables must be initialized by calling ovsrec_init(). The complete initialization is shown in Listing [example:init-read], which also covers a setting the verbosity level of the OVSDB IDL messages using the vlog_set_levels() function.
Accessing the OVSDB data is shown in the following source code fragment. It prints out the name, admin_state and mtu values of all the interfaces:
/* debug level */
vlog_set_levels(NULL, VLF_CONSOLE, VLL_DBG);
/* initialization */
ovsrec_init();
struct ovsdb_idl *idl = ovsdb_idl_create(...);
seqno = ovsdb_idl_get_seqno(idl);
for (;;) {
/* synchronize OVSDB */
ovsdb_idl_run(idl);
if (seqno != ovsdb_idl_get_seqno(idl)) {
/* reading interface data */
const struct ovsrec_interface *ifc;
OVSREC_INTERFACE_FOR_EACH(ifc, idl) {
printf("%s %s %"PRIi64"\n", ifc->name, ifc->admin_state,
ifc->mtu?ifc->mtu[0]:0);
}
} else {
ovsdb_idl_wait(idl);
poll_block();
}
}Data modification in OVSDB can be done using the functions for creation of a transaction and special setter functions defined for every column by OVSDB IDL. An example of data change is shown in Sec. [sec:ovsdb-idl-string-maps].
OVSDB IDL uses a string map data structure to store some additional options in OVSDB. The string map is defined as struct smap and API contains various functions and macros for data manipulation. An example of reading all stored items from a string map is shown using INTERFACE:options.
struct smap opt_cl;
const struct smap_node *oc;
// clone existing string map
smap_clone(&opt_cl, &ifc->options);
// read and print all options of the interface
SMAP_FOR_EACH(oc, &ifc->options) {
printf("%s: %s\n", oc->key, oc->value);
}
// remove entry
smap_remove(&opt_cl, "local_ip");
// insert entry
smap_add_once(&opt_cl, "local_ip", "1.1.1.1");
// set string map options for the interface
smap_add_once(&opt_cl, "local_ip", "1.1.1.2");
status_txn = ovsdb_idl_txn_create(idl);
ovsrec_interface_set_options(ifc, &opt_cl);
ovsrec_interface_verify_options(ifc);
status = ovsdb_idl_txn_commit(status_txn);
ovsdb_idl_txn_destroy(status_txn);
// Note: do not try to modify smap in the SMAP_FOR_EACH() loopOVSDB defines some items as <integer, Table> pairs, e.g. QOS:queues that is an array of <key, Queue> pairs. QOS:queues can be used as an example of a description of the representation in OVSDB. QOS:queues maps to n_queues, key_queues, value_queues as follows: n_queues contains the size of the array, key_queues is an array of the integer keys and values_queues is an array of ovsrec_queue pointers. The same index i in key_queues and values_queues is used to obtain a particular <key, Queue> pair.
It is needed to map a resource-id to the OVSDB row, whereas resource-id is used as a unique identifier in OF-CONFIG. OVSDB uses Universally Unique IDentifier (UUID) as a unique identifier of each row. The OVSDB row is represented by struct ovsdb_idl_row header_ that contains UUID declared as struct uuid.
The UUID data structure has API for data manipulation, therefore, it is possible to convert UUID into a string or it can be used as a unique number that identifies the row. resource-id from OF-CONFIG is defined as inet:uri that means it can possibly contain any string.
There are two use-cases causing the necessity of mapping resource-id and UUID:
Direction from OF-CONFIG to OVSDB
– e.g., client modifies data in libnetconf datastore which causes an update of the existing data in OVSDB. The task of the libnetconf datastore is to find out the right rows in OVSD and edit them.
Direction from OVSDB to OF-CONFIG
– e.g., reading the current OVSDB content which causes an update of the libnetconf datastore. During this operation, the libnetconf datastore must be able to translate all identifiers returned by OVSDB into the identifiers used by an OF-CONFIG client.
In order to map resource-id to UUID and vice-versa, the libnetconf datastore must use an array of pairs of identifiers that maps every resource-id to corresponding UUID. Use-case 1) as well as use-case 2) may cause a value of identifier that must be completed for the mapping to be missing. This situation can happen when 1) a client passes resource-id of data that is inserted – OVSDB will return a new UUID that must be written into the pair of identifiers with the given resource-id or 2) OVSDB returns data that does not exist in the libnetconf datastore yet – any resource-id can be chosen (to be stored into the libnetconf datastore) and for the sake of simplicity, it can be equal to UUID.
This section describes data structures provided by the OVSDB IDL API. These data structures are referenced in the following section where the implementation of the specific OF-CONFIG parts is described. The structures map to the schema of the particular tables in OVSDB. A detailed description can be found in the ovs/lib/vswitch-idl.h file that is automatically generated according to the OVSDB schema.
struct ovsrec_bridge {
struct ovsdb_idl_row header_;
/* controller column. */
struct ovsrec_controller **controller;
size_t n_controller;
/* datapath_id column. */
char *datapath_id;
/* datapath_type column. */
char *datapath_type; /* Always nonnull. */
/* external_ids column. */
struct smap external_ids;
/* fail_mode column. */
char *fail_mode;
/* flood_vlans column. */
int64_t *flood_vlans;
size_t n_flood_vlans;
/* flow_tables column. */
int64_t *key_flow_tables;
struct ovsrec_flow_table **value_flow_tables;
size_t n_flow_tables;
/* ipfix column. */
struct ovsrec_ipfix *ipfix;
/* mirrors column. */
struct ovsrec_mirror **mirrors;
size_t n_mirrors;
/* name column. */
char *name; /* Always nonnull. */
/* netflow column. */
struct ovsrec_netflow *netflow;
/* other_config column. */
struct smap other_config;
/* ports column. */
struct ovsrec_port **ports;
size_t n_ports;
/* protocols column. */
char **protocols;
size_t n_protocols;
/* sflow column. */
struct ovsrec_sflow *sflow;
/* status column. */
struct smap status;
/* stp_enable column. */
bool stp_enable;
}; struct ovsrec_port {
struct ovsdb_idl_row header_;
/* bond_active_slave column. */
char *bond_active_slave;
/* bond_downdelay column. */
int64_t bond_downdelay;
/* bond_fake_iface column. */
bool bond_fake_iface;
/* bond_mode column. */
char *bond_mode;
/* bond_updelay column. */
int64_t bond_updelay;
/* external_ids column. */
struct smap external_ids;
/* fake_bridge column. */
bool fake_bridge;
/* interfaces column. */
struct ovsrec_interface **interfaces;
size_t n_interfaces;
/* lacp column. */
char *lacp;
/* mac column. */
char *mac;
/* name column. */
char *name; /* Always nonnull. */
/* other_config column. */
struct smap other_config;
/* qos column. */
struct ovsrec_qos *qos;
/* rstp_statistics column. */
char **key_rstp_statistics;
int64_t *value_rstp_statistics;
size_t n_rstp_statistics;
/* rstp_status column. */
struct smap rstp_status;
/* statistics column. */
char **key_statistics;
int64_t *value_statistics;
size_t n_statistics;
/* status column. */
struct smap status;
/* tag column. */
int64_t *tag;
size_t n_tag;
/* trunks column. */
int64_t *trunks;
size_t n_trunks;
/* vlan_mode column. */
char *vlan_mode;
}; struct ovsrec_interface {
struct ovsdb_idl_row header_;
/* admin_state column. */
char *admin_state;
/* bfd column. */
struct smap bfd;
/* bfd_status column. */
struct smap bfd_status;
/* cfm_fault column. */
bool *cfm_fault;
size_t n_cfm_fault;
/* cfm_fault_status column. */
char **cfm_fault_status;
size_t n_cfm_fault_status;
/* cfm_flap_count column. */
int64_t *cfm_flap_count;
size_t n_cfm_flap_count;
/* cfm_health column. */
int64_t *cfm_health;
size_t n_cfm_health;
/* cfm_mpid column. */
int64_t *cfm_mpid;
size_t n_cfm_mpid;
/* cfm_remote_mpids column. */
int64_t *cfm_remote_mpids;
size_t n_cfm_remote_mpids;
/* cfm_remote_opstate column. */
char *cfm_remote_opstate;
/* duplex column. */
char *duplex;
/* error column. */
char *error;
/* external_ids column. */
struct smap external_ids;
/* ifindex column. */
int64_t *ifindex;
size_t n_ifindex;
/* ingress_policing_burst column. */
int64_t ingress_policing_burst;
/* ingress_policing_rate column. */
int64_t ingress_policing_rate;
/* lacp_current column. */
bool *lacp_current;
size_t n_lacp_current;
/* link_resets column. */
int64_t *link_resets;
size_t n_link_resets;
/* link_speed column. */
int64_t *link_speed;
size_t n_link_speed;
/* link_state column. */
char *link_state;
/* mac column. */
char *mac;
/* mac_in_use column. */
char *mac_in_use;
/* mtu column. */
int64_t *mtu;
size_t n_mtu;
/* name column. */
char *name; /* Always nonnull. */
/* ofport column. */
int64_t *ofport;
size_t n_ofport;
/* ofport_request column. */
int64_t *ofport_request;
size_t n_ofport_request;
/* options column. */
struct smap options;
/* other_config column. */
struct smap other_config;
/* statistics column. */
char **key_statistics;
int64_t *value_statistics;
size_t n_statistics;
/* status column. */
struct smap status;
/* type column. */
char *type; /* Always nonnull. */
}; struct ovsrec_qos {
struct ovsdb_idl_row header_;
/* external_ids column. */
struct smap external_ids;
/* other_config column. */
struct smap other_config;
/* queues column. */
int64_t *key_queues;
struct ovsrec_queue **value_queues;
size_t n_queues;
/* type column. */
char *type; /* Always nonnull. */
}; struct ovsrec_queue {
struct ovsdb_idl_row header_;
/* dscp column. */
int64_t *dscp;
size_t n_dscp;
/* external_ids column. */
struct smap external_ids;
/* other_config column. */
struct smap other_config;
}; struct ovsrec_ssl {
struct ovsdb_idl_row header_;
/* bootstrap_ca_cert column. */
bool bootstrap_ca_cert;
/* ca_cert column. */
char *ca_cert; /* Always nonnull. */
/* certificate column. */
char *certificate; /* Always nonnull. */
/* external_ids column. */
struct smap external_ids;
/* private_key column. */
char *private_key; /* Always nonnull. */
}; struct ovsrec_flow_table {
struct ovsdb_idl_row header_;
/* external_ids column. */
struct smap external_ids;
/* flow_limit column. */
int64_t *flow_limit;
size_t n_flow_limit;
/* groups column. */
char **groups;
size_t n_groups;
/* name column. */
char *name;
/* overflow_policy column. */
char *overflow_policy;
/* prefixes column. */
char **prefixes;
size_t n_prefixes;
}; struct ovsrec_controller {
struct ovsdb_idl_row header_;
/* connection_mode column. */
char *connection_mode;
/* controller_burst_limit column. */
int64_t *controller_burst_limit;
size_t n_controller_burst_limit;
/* controller_rate_limit column. */
int64_t *controller_rate_limit;
size_t n_controller_rate_limit;
/* enable_async_messages column. */
bool *enable_async_messages;
size_t n_enable_async_messages;
/* external_ids column. */
struct smap external_ids;
/* inactivity_probe column. */
int64_t *inactivity_probe;
size_t n_inactivity_probe;
/* is_connected column. */
bool is_connected;
/* local_gateway column. */
char *local_gateway;
/* local_ip column. */
char *local_ip;
/* local_netmask column. */
char *local_netmask;
/* max_backoff column. */
int64_t *max_backoff;
size_t n_max_backoff;
/* other_config column. */
struct smap other_config;
/* role column. */
char *role;
/* status column. */
struct smap status;
/* target column. */
char *target; /* Always nonnull. */
};+--rw capable-switch
+--rw id string
+--ro config-version? string
- Implementation: Neither value is actually mapped to the OVS.
id: stored internally.config-version: Static value “1.2”.
#+--rw capable-switch
# +--rw configuration-points
# +--rw configuration-point* [id]
# +--rw id OFConfigId
# +--rw uri inet:uri
# +--rw protocol? OFConfigurationPointProtocolType
- Note: This part was removed in current draft for OF-CONFIG 1.3.
- Implementation: Do not implement.
+--rw capable-switch
+--rw resources
+--rw port* [resource-id]
+--rw resource-id inet:uri
+--ro number? uint64
+--rw requested-number? uint64
! +--ro name? string
+--ro current-rate? uint32
+--ro max-rate? uint32
- Note: This is not implementable, since there is no way of mapping a port instance to a system interface. We need to define
nameas the key of the list. - Note: OVS has different types of ports (
system,internal,tapand tunnels). The system ports are those connected to a hardware (that can also be virtualized, of course) and they are the ports configured here. OVS automatically creates some internal ports usually connected with the created bridges (also called “local interface”). The tap is a TUN/TAP device managed by OVS. Since OF-CONFIG does not differentiate between the port types, the OF-CONFIG server will not be able to create a tap port – simply - Note: In OVSDB, each port can include multiple interfaces. This relationship could be set/get from the
interfacesarray of sizen_interfacesin theovsrec_port(Listing [struct:port]), however, OF-CONFIG does not support binding a port. - Implementation: Configurable data maps to OVSDB and status data can be obtained using ioctl() or OpenFlow (ovs-ofctl(8) or OpenFlow message abstraction from OVS).
resource-id: Stored internally, mapped to UUID.number: Maps to theofportarray ofn_ofportsize from theovsrec_interface.- Note: OF-CONFIG specifies the range similarly as in
INTERFACE:ofport_request. It is set automatically by OVS.
- Note: OF-CONFIG specifies the range similarly as in
requested-number: Maps to theofport_requestarray ofn_ofport_requestsize from theovsrec_interface.- Note: It should be set only during the creation of a new port. The later change may take effect, but it might confuse controllers.
name: Maps to thenamefrom theovsrec_interface.- Note: Until the
nameis changed to a key, we can consider the name to actually be (a part of)resource-idof the port and use it for mapping to the system interfaces. When thenamewill be changed to the key, it can be directly mapped to thePORT:name. This problem should be discussed more.
- Note: Until the
current-rate,max-rate: Use ioctl() with SIOCETHTOOL request and the ETHTOOL_GSET command. The data are retrieved from the struct ethtool_cmd structure. The current rate is available as mergedspeedandspeed_himembers. The max rate is the maximal supported rate from thesupportedbitmask.
Alternatively, use ovs-ofctl(8):# ovs-ofctl show <SWITCH>The values can be found as:speed: <CURRENT> now, <MAX> max
+--rw capable-switch
+--rw resources
+--rw port* [resource-id]
+--rw configuration
+--rw admin-state? OFUpDownStateType
+--rw no-receive? boolean
+--rw no-forward? boolean
+--rw no-packet-in? boolean
- Implementation:
admin-state: Use ioctl() with SIOCGIFFLAGS/SIOCSIFFLAGS to get/set the admin state of the port using the struct ifreq structure. To set a new value, properly set theifr_flagsmember. Alternatively, use ip(8) to set the value:# ip link set <PART NAME> up|downGet asadmin_statevalue from theovsrec_interface.no-receive,no-forward,no-packet-in: Use ovs-ofctl(8) to get values:# ovs-ofctl show <SWITCH>- Note: The values can be found on the line:
config: ...Theno-receiveis true ifNO_RECVis found. Theno-forwardis true ifNO_FWDis found. Theno-packet-inis true ifNO_PACKET_INis found. Use ovs-ofctl(8) to set values:# ovs-ofctl mod-port <SWITCH> <PORT> <no-receive|receive># ovs-ofctl mod-port <SWITCH> <PORT> <no-forward|forward># ovs-ofctl mod-port <SWITCH> <PORT> <no-packet-in|packet-in>
- Note: The values can be found on the line:
+--rw capable-switch
+--rw resources
+--rw port* [resource-id]
+--ro state
+--ro oper-state? OFUpDownStateType
+--ro blocked? boolean
+--ro live? boolean
- Implementation:
oper-state: Maps tolink_statefrom theovsrec_interface(Listing [struct:interface]).blocked: Thetruevalue maps to theblocking(and possiblydisabled) values of thestp_stateentry in thestatusstring map from theovsrec_interface(Listing [struct:interface]).live: Can be observed using ovs-ofctl(8):# ovs-ofctl show <SWITCH>- Note: The value is true if
LIVEis found on the line:state: ... - Note: OVS manages fast failover automatically and does not provide information about interface aliveness via OVSDB.
- Note: The value is true if
+--rw capable-switch
+--rw resources
+--rw port* [resource-id]
+--rw features
+--ro current
| +--ro rate? OFPortRateType
| +--ro auto-negotiate? boolean
| +--ro medium? enumeration
! | +--ro pause? enumeration +--rw advertised ! | +--rw rate* OFPortRateType | +--rw auto-negotiate? boolean | +--rw medium* enumeration | +--rw pause enumeration +--ro supported | +--ro rate* OFPortRateType | +--ro auto-negotiate? boolean | +--ro medium* enumeration | +--ro pause enumeration +--ro advertised-peer +--ro rate* OFPortRateType +--ro auto-negotiate? boolean +--ro medium* enumeration +--ro pause enumeration
- Note: Sometimes the information (or specific group of information) is not available (for various reasons, usually due to missing support by the device driver) and we do not provide it.
- Implementation:
-
Note: ovs-ofctl(8) and ethtool(8) provide all the data required in this part. However, they do not meet the requirements for setting the parameters (needed for the advertised part. ovs-ofctl(8) does not allow to set anything and ethtool(8) is limited (e.g. in case of a pause). Therefore, we will use ioctl() calls directly.
-
Getting data: Use ioctl() with SIOCETHTOOL request and the ETHTOOL_GSET command. Data are retrieved as a struct ethtool_cmd structure.
-
Setting data: Use ioctl() with SIOCETHTOOL request and the ETHTOOL_SSET command. Data are passed as a struct ethtool_cmd structure.
-
Reference: See the
include/linux/ethtool.hsystem header file. -
Note: The internal OVS ports do not have a physical layer, so there is nothing advertised nor supported. Since the
pauseelement in thesupportedandadvertisedcontainers is mandatory, the value must be set to unsupported. -
Note: The pause feature under the current container is not filled (neither by OVS for
of_portstructure). The values for the flow control from the advertised and advertised-peer are actually used to set the pause frame handling separately for the TX and RX (according to IEEE 802.3-2005 table 28B-3). So we are going to put here the same value as set in the advertised container. -
Note: Setting up the advertised rate values is limited to 10Gb max. The higher values are not currently supported (neither by OVS).
-
Note: Setting up the advertised values is limited to the supported values. For example, it does not make sense to set the pause parameter when flow control is not supported by the device.
-
+--rw capable-switch
+--rw resources
+--rw port* [resource-id]
+--rw (tunnel-type)?
+--:(tunnel)
! +--rw tunnel
+--rw (endpoints)
+--:(v4-endpoints)
| +--rw local-endpoint-ipv4-adress? inet:ipv4-address
| +--rw remote-endpoint-ipv4-adress? inet:ipv4-address
# +--:(v6-endpoints)
# | +--rw local-endpoint-ipv6-adress? inet:ipv6-address
# | +--rw remote-endpoint-ipv6-adress? inet:ipv6-address
# +--:(mac-endpoints)
# +--rw local-endpoint-mac-adress? yang:mac-address
# +--rw remote-endpoint-mac-adress? yang:mac-address
- Note: OVS supports only IPv4 tunnel endpoints. It would be nice to have other endpoint types under the YANG
if-featurestatement. - Note: Configured interface should be of a tunnel type (
typein theovsrec_interfacestructure is set togregre64,geneve,vxlan, orlisp) and thein_keyentry of theoptionsstring map from theovsrec_interface(Listing [struct:interface]) is not set. - Implementation:
local-endpoint-ipv4-adress: Local address of the tunnel, maps to thelocal_ipentry of theoptionsstring map from theovsrec_interface(Listing [struct:interface]).remote-endpoint-ipv4-adress: Remote address of the tunnel, maps to theremote_ipentry of theoptionsstring map from theovsrec_interface(Listing [struct:interface]).
+--rw capable-switch
+--rw resources
+--rw port* [resource-id]
+--rw (tunnel-type)?
+--:(ipgre-tunnel)
+--rw ipgre-tunnel
+--rw (endpoints)
| +--:(v4-endpoints)
| | +--rw local-endpoint-ipv4-adress? inet:ipv4-address
| | +--rw remote-endpoint-ipv4-adress? inet:ipv4-address
# | +--:(v6-endpoints)
# | | +--rw local-endpoint-ipv6-adress? inet:ipv6-address
# | | +--rw remote-endpoint-ipv6-adress? inet:ipv6-address
# | +--:(mac-endpoints)
# | +--rw local-endpoint-mac-adress? yang:mac-address
# | +--rw remote-endpoint-mac-adress? yang:mac-address
+--rw checksum-present? boolean
+--rw key-present? boolean
+--rw key uint32
# +--rw sequence-number-present? boolean
- Note: Configured interface has the
gretype (thetypein theovsrec_interfacestructure ([struct:interface]). - Note: The OVS’s
gre64type is not supported since the type of thekeyparameter here isuint32. - Implementation:
local-endpoint-ipv4-adress: Local address of the tunnel, maps tolocal_ipentry of theoptionsstring map from theovsrec_interface(Listing [struct:interface]).remote-endpoint-ipv4-adress: Remote address of the tunnel, maps toremote_ipentry of theoptionsstring map from theovsrec_interface(Listing [struct:interface]).checksum-present: Maps tocsumentry of theoptionsstring map from theovsrec_interface(Listing [struct:interface]).key*: Maps tokeyentry of theoptionsstring map from theovsrec_interface(Listing [struct:interface]).- Note: It is not clear why these two items are separated.
+--rw capable-switch
+--rw resources
+--rw port* [resource-id]
+--rw (tunnel-type)?
+--:(vxlan-tunnel)
+--rw vxlan-tunnel
+--rw (endpoints)
| +--:(v4-endpoints)
| | +--rw local-endpoint-ipv4-adress? inet:ipv4-address
| | +--rw remote-endpoint-ipv4-adress? inet:ipv4-address
# | +--:(v6-endpoints)
# | | +--rw local-endpoint-ipv6-adress? inet:ipv6-address
# | | +--rw remote-endpoint-ipv6-adress? inet:ipv6-address
# | +--:(mac-endpoints)
# | +--rw local-endpoint-mac-adress? yang:mac-address
# | +--rw remote-endpoint-mac-adress? yang:mac-address
# +--rw vni-valid? boolean
+--rw vni? uint32
# +--rw vni-multicast-group? inet:ip-address
# +--rw udp-source-port? inet:port-number
# +--rw udp-dest-port? inet:port-number
# +--rw udp-checksum? boolean
- Note: Configured interface has the
vxlantype (thetypein theovsrec_interfacestructure ([struct:interface]). - Implementation:
local-endpoint-ipv4-adress: Local address of the tunnel, maps tolocal_ipentry of theoptionsstring map from theovsrec_interface(Listing [struct:interface]).remote-endpoint-ipv4-adress: Remote address of the tunnel, maps toremote_ipentry of theoptionsstring map from theovsrec_interface(Listing [struct:interface]).vni: Maps tokeyin theoptionsstring map from theovsrec_interface(Listing [struct:interface]).- Note: In OVSDB, the
keyentry is actually limited to 24-bits in case of thevxlanport type.
- Note: In OVSDB, the
+--rw capable-switch
+--rw resources
+--rw port* [resource-id]
+--rw (tunnel-type)?
# +--:(nvgre-tunnel)
# +--rw nvgre-tunnel
# +--rw (endpoints)
# | +--:(v4-endpoints)
# | | +--rw local-endpoint-ipv4-adress? inet:ipv4-address
# | | +--rw remote-endpoint-ipv4-adress? inet:ipv4-address
# | +--:(v6-endpoints)
# | | +--rw local-endpoint-ipv6-adress? inet:ipv6-address
# | | +--rw remote-endpoint-ipv6-adress? inet:ipv6-address
# | +--:(mac-endpoints)
# | +--rw local-endpoint-mac-adress? yang:mac-address
# | +--rw remote-endpoint-mac-adress? yang:mac-address
# +--rw vsid? uint32
# +--rw flow-id? uint8
- Note: NVGRE tunnels are not supported by OVS. It would be nice to cover this with the YANG
if-featurestatement.
+--rw capable-switch
+--rw resources
+--rw queue* [resource-id]
+--rw resource-id inet:uri
+--rw id uint64
+--rw port? -> /capable-switch/resources/port/resource-id
+--rw properties
+--rw min-rate? OFTenthOfAPercentType
+--rw max-rate? OFTenthOfAPercentType
+--rw experimenter-id? OFExperimenterId
+--rw experimenter-data? hex-binary
- Implementation:
resource-id: Stored internally, mapped to UUID.id: Maps to the key from the<key, Queue>pair, it is stored in thekey_queuesarray from theovsrec_qos(Listing [struct:qos]). An explanation of<key, Table>pairs is presented in Sec. [sec:key-table-pair].port:QUEUEis related toPORTvia theqospointer in theovsrec_portstructure,QOScontains an array of<key, Queue>pairs. See Section [sec:key-table-pair] for an explanation of<integer, Table>pairs.properties/min-rate: Maps tomin-ratein theother_configstring map from theovsrec_queue(Listing [struct:queue]).properties/min-rate: Maps tomax-ratein theother_configstring map from theovsrec_queue(Listing [struct:queue]).properties/experimenter*: Stored internally.
+--rw capable-switch
+--rw resources
! +--rw owned-certificate* [resource-id]
| +--rw resource-id inet:uri
| +--rw certificate string
| +--rw private-key
| +--rw (key-type)
| +--:(dsa)
| | +--rw DSAKeyValue
| | +--rw P binary
| | +--rw Q binary
| | +--rw J? binary
| | +--rw G? binary
| | +--rw Y binary
| | +--rw Seed binary
| | +--rw PgenCounter binary
| +--:(rsa)
| +--rw RSAKeyValue
| +--rw Modulus binary
| +--rw Exponent binary
+--rw external-certificate* [resource-id]
+--rw resource-id inet:uri
+--rw certificate string
- Note: It is not very clear how the certificates and private key should be used. For more information, see the Section [sec:conclusion:cert].
- Implementation:
resource-id: Stored internally.owned-certificate/certificate: Maps indirectly – the stored certificate in the base64-encoded DER format must be translated into the full PEM format and exported into the file used by OVS. The filename is available in thecertificatemember from theovsrec_ssl(Listing [struct:ssl]). Translation is performed simply by adding the-----BEGIN CERTIFICATE-----and-----END CERTIFICATE-----tags.owned-certificate/private-key/: Maps indirectly – the stored private-key information must be translated into the PEM format and stored into the file used by OVS. The filename is available inprivate_keymember from theovsrec_ssl(Listing [struct:ssl]). Translation can be done using libssl functions.- Note: The problem here is that the data model actually does not describe private, but the public key. We had to change the data model to store the private key for the OVS
external-certificate/certificate: Maps indirectly – the stored certificate in the base64-encoded DER format must be translated into the full PEM format and exported into the file used by OVS. The filename is available inca_certfrom theovsrec_ssl(Listing [struct:ssl]). Translation is performed simply by adding the-----BEGIN CERTIFICATE-----and-----END CERTIFICATE-----tags.- Note: It is not clear if the certificate is directly the certificate of the controller or the certificate of the trustworthy CA. Anyway, OVS uses PEM file with the CA certificate.
+--rw capable-switch
+--rw resources
+--rw flow-table* [table-id]
+--rw resource-id inet:uri
+--rw table-id uint8
+--rw name? string
# +--rw metadata-match? hex-binary
# +--rw metadata-write? hex-binary
+--ro max-entries? uint32
# +--rw properties!
# +--rw instructions
# | +--rw type* OFInstructionType
# +--rw instructions-miss
# | +--rw type* OFInstructionType
# +--rw next-tables
# | +--rw table-id* uint8
# +--rw next-tables-miss
# | +--rw table-id* uint8
# +--rw write-actions
# | +--rw type* OFActionType
# +--rw write-actions-miss
# | +--rw type* OFActionType
# +--rw apply-actions
# | +--rw type* OFActionType
# +--rw apply-actions-miss
# | +--rw type* OFActionType
# +--rw matches
# | +--rw type* OFMatchFieldType
# +--rw wildcards
# | +--rw type* OFMatchFieldType
# +--rw write-setfields
# | +--rw type* OFMatchFieldType
# +--rw write-setfields-miss
# | +--rw type* OFMatchFieldType
# +--rw apply-setfields
# | +--rw type* OFMatchFieldType
# +--rw apply-setfields-miss
# | +--rw type* OFMatchFieldType
# +--rw experimenter
# | +--rw experimenter-id* OFExperimenterId
# +--rw experimenter-miss
# +--rw experimenter-id* OFExperimenterId
- Implementation:
resource-id: Stored internally, mapped to UUID.table-id: Maps to the key from the<key, Flow_Table>pair, it is stored in thekey_flow_tablesarray from theovsrec_bridge(Listing [struct:bridge]). An explanation of<key, Table>pairs is presented in Sec. [sec:key-table-pair].name: Maps to thenamemember of theovsrec_flow_table(Listing [struct:flowtable]).max-entries: Maps to theflow_limitarray ofn_flow_limitsize from theovsrec_flow_table(Listing [struct:flowtable]).
+--rw capable-switch
+--rw logical-switches
+--rw switch* [id]
+--rw id OFConfigId
+--rw datapath-id datapath-id-type
+--rw enabled? boolean
# +--rw check-controller-certificate? boolean
+--rw lost-connection-behavior? enumeration
- Implementation:
id: Maps to thenamemember from theovsrec_bridge(Listing [struct:bridge]).datapath-id: Maps todatapath-idin theother_configstring map from theovsrec_bridge(Listing [struct:bridge]).- Note: It uses a different format. OVSDB accepts 16 HEX digits but OF-CONFIG has [0-9a-fA-F]2(:[0-9a-fA-F]2)7 pattern.
enabled: OVSDB does not include enable/disable switch for a bridge. When a bridge is configured, it is set up to work. To allow disabling of the bridge, we have to completely remove the configuration data for it and for everything it links. On the other hand, we have to keep an internal copy of all the structures related to the disabled bridge to be able to return configuration data in case of<get-config>or re-enabling the bridge in the future. The disabled bridge configuration data structures do not need to be stored permanently – in case of a reboot the startup configuration datastore is used anyway, so the running state will not be needed. Therefore, only the in-memory copy of disabled structures will be kept. In case of creating a disabled bridge, we can create shadow data structures directly and do not affect OVSDB via IDL API.lost-connection-behavior: Maps tofail_modefrom theovsrec_bridge(Listing [struct:bridge]), it can contain eitherstandaloneorsecure.
+--rw capable-switch
+--rw logical-switches
+--rw switch* [id]
+--ro capabilities
+--ro max-buffered-packets? uint32
+--ro max-tables? uint8
+--ro max-ports? uint32
+--ro flow-statistics? boolean
+--ro table-statistics? boolean
+--ro port-statistics? boolean
+--ro group-statistics? boolean
+--ro queue-statistics? boolean
+--ro reassemble-ip-fragments? boolean
+--ro block-looping-ports? boolean
+--ro reserved-port-types
| +--ro type* enumeration
+--ro group-types
| +--ro type* enumeration
+--ro group-capabilities
| +--ro capability* enumeration
+--ro action-types
| +--ro type* OFActionType
+--ro instruction-types
+--ro type* OFInstructionType
- Note: The following data are static in case of the OVS software switch. Hardware OVS-based switches can have different values.
- Implementation:
max-buffered-packets: Static, value 256 (defined asPKTBUF_CNTmacro inofproto/pktbuf.c).max-tables: No explicit limit.max-ports: Static, 255 (per bridge).flow-statistics,table-statistics,port-statistics,group-statistics,queue-statistics,reasemble-ip-fragments,block-looping-ports: Static, true (implemented).reserved-port-types: Static, OVS supports all types (all,controller,table,inport,any,normal,flood).group-types: Static, OVS supports all types (all,select,indirect,fast-failover).group-capabilities: Static, OVS supportsselect-weight,select-livenessandchaining. Thechaining-checkis not supported.action-types: Static, OVS supportsoutput,set-mpls-ttl,dec-mpls-ttl,push-vlan,pop-vlan,push-mpls,pop-mpls,set-queue,group,set-nw-ttl,dec-nw-ttlandset-field. Thecopy-ttl-outandcopy-ttl-inactions are not supported.instruction-types: Static, OVS supports all types (apply-actions,clear-actions,write-actions,write-metadata,goto-table).
+--rw capable-switch
+--rw logical-switches
+--rw switch* [id]
+--rw controllers
+--rw controller* [id]
+--rw id OFConfigId
# +--rw role? enumeration
+--rw ip-address inet:ip-address
+--rw port? inet:port-number
+--rw local-ip-address? inet:ip-address
# +--rw local-port? inet:port-number
+--rw protocol? enumeration
+--ro state
+--ro connection-state? OFUpDownStateType
# +--ro current-version? OFOpenFlowVersionType
# +--ro supported-versions* OFOpenFlowVersionType
+--ro local-ip-address-in-use? inet:ip-address
+--ro local-port-in-use? inet:port-number
- Implementation:
id: Stored internally.protocol,ip-address,port: Maps to thetargetfrom theovsrec_controller(Listing [struct:controller]).- Note: Protocol maps to prefix. Note that OVSDB uses
ssl, while OF-CONFIG usestlsname.
- Note: Protocol maps to prefix. Note that OVSDB uses
local-ip-address: Maps tolocal_ipfrom theovsrec_controllerstructure. It is considered only when theconnection_modemember of the same IDL structure is set toin-band.connection-state: Maps tois_connectedfrom theovsrec_controllerstructure.local-ip-address-in-use,local-port-in-use: Can be parsed from the netstat(8) output:# netstat -nt- Note: The values can be obtained by filtering output with remote address values for
ip-address:portas specified in the controller configuration.
- Note: The values can be obtained by filtering output with remote address values for
+--rw capable-switch
+--rw logical-switches
+--rw switch* [id]
+--rw resources
+--rw port* -> /capable-switch/resources/port/resource-id
+--rw queue* -> /capable-switch/resources/queue/resource-id
! +--rw certificate? -> /capable-switch/resources/owned-certificate/resource-id
+--rw flow-table* -> /capable-switch/resources/flow-table/table-id
- Implementation:
port: Port is associated with a Bridge using theportsarray of then_portssize in theovsrec_bridge(Listing [struct:bridge]).queue:QUEUEis related toPORTvia theqospointer in theovsrec_portstructure,QOScontains the array of<key, Queue>pairs. See Section [sec:key-table-pair] for the explanation of<integer, Table>pairs.certificate: OVS uses only a single SSL configuration per OVS daemon process. Therefore, if the value is set by the client, it will be forced to refer to the first instance of theowned-certificate.flow-table:BRIDGEcontains an array of<key, Flow_table>pairs. See Section [sec:key-table-pair] for an explanation of<integer, Table>pairs.
Here we summarize the issues mentioned in the previous sections, whose issues with the configuration data were marked ! character.
As mentioned in Section [sec:ops:locks], OVSDB does not support mandatory locking of the configuration data. The provided locking mechanism is insufficient to meet the OF-CONFIG requirements for locking. It is not possible to avoid data modification performed by another OVSDB client running concurrently.
To solve this problem, some changes in the OVSDB server would be necessary. Therefore, we are going to discuss this issue in OVS development mailing list.
The main issue with the port management is the lack of unique mapping between the configuration data and system interfaces. It can be done using the interface name or ifindex. Currently, the name is state information and ifindex is not used at all. This way, a client is not able to create configuration data that would be mapped to some specific system interface.
The problem would be solved if the OF-CONFIG server automatically detects all system interfaces and prepares configuration data for them. But the natural way of using switch configuration (and OVS does it that way) is different. The switch configuration does not need to contain configuration of all system interfaces. Only the interfaces used in logical switches (bridges in the OVS terminology) must be described. And in this case, the current OF-CONFIG data does not allow to map a port instance to a specific system interface.
Therefore, we propose to make the name element of the port list a key. The second way is to add ifindex (and make it a key) which could be used to identify system interface that is covered by the port instance.
Another port issue is connected to a generic OVS feature – garbage collecting. OVS does garbage collecting and automatically removes any resource which is not used in a bridge (logical-switch). In the first phase, we do not plan to solve this in any way. If the user adds a port configuration which is not used by any logical-switch, the configuration will disappear since the running configuration is going to reflect OVSDB content. Later, we can solve this by managing resources that are not used by any logical-switch somehow differently. It means, that such resources would not be applied to the OVSDB, but they would be kept in separated structures.
In the previous report we have already mentioned that the certificate configuration is confusing and used format is not common nor user friendly. We were investigating it in more detail and we are not sure how the provided information (private key parameters and certificates) should be used.
The DSAKeyValue, under the private-key container does not contain private key (X value is missing), which is confusing due to the name of the container. The referenced W3C document states that the DSAKeyValue as well as the RSAKeyValue are parts of the KeyInfo element. But this element (the key it includes) is used to validate the signature, which means that the key is actually a public key. The private keys are not covered by this document.
And a note about the DSA reference document used in the DSAKeyValueType grouping description – the link is currently broken and it should be updated to http://csrc.nist.gov/publications/fips/archive/fips186-2/fips186-2.pdf .