The ovsdb/spec file defines the table specification of ovsdb. When creating a DB, you must prepare a schema file in advance. The file is a JSON string and defines the DB name, contains all tables; each table contains a JSON dict of columns, through this schema file (e.g. vswitchd/vswitch. ovsschema) to create a DB file. Therefore, ovsdb is actually a file database (why not use SQLite directly, but write it yourself ).
When the ovsdb-server is started, a json rpc interface is opened to the client for rpc. this RPC is generally performed through Unix domain socket. Ovsdb-client is a client program used to access ovsdb. It is useful to use ovsdb-client dump to view ovsdb content. ovsdb-client transact is used to execute a SQL-like statement.
Ovsdb_jsonrpc_server is used to process RPC requests of ovsdb. ovsdb_server is its interface.
/* Abstract representation of an ovsdb server not tied to any participant
* Network protocol. protocol implementations (e.g. jsonrpc-server.c) embed
* This in a larger data structure .*/
Struct ovsdb_server {
Struct Shash dBs;/* maps from a DB name to a "struct ovsdb *".*/
Struct hmap locks;/* contains "struct ovsdb_lock" s indexed by name .*/
};
Ovsdb_server is an abstract interface, which has different implementations based on different network accesses. e.g. ovsdb_jsonrpc_server. The DBS member is a hash table, the key is dB name, the value is struct ovsdb, And the locks is also the name <-> struct ovsdb_lock hash table.
For the connection of each client <-> ovsdb, it is expressed by an abstract interface struct ovsdb_session. Each ovsdb_session will request some locks (ovsdb_lock ), these locks are stored in an hmap called waiters and use ovsdb_lock-> name as the hash key.
/* Abstract representation of an ovsdb client connection, not tied to any
* Particle network protocol. protocol implementations
* (E.g. jsonrpc-server.c) embed this in a larger data structure .*/
Struct ovsdb_session {
Struct ovsdb_server * server;
Struct list completions;/* completed triggers .*/
Struct hmap waiters;/* "ovsdb_lock_waiter *" s by lock name .*/
};
Ovsdb_lock is a mutex lock. In ovsdb_server, there is an hmap dedicated to managing these ovsdb_locks. The ovsdb_lock_waiter waiting on an ovsdb_lock will form a list
/* A database lock.
*
* A lock always has one or more "lock waiters" kept on a list. The waiter
* The head of the list owns the lock .*/
Struct ovsdb_lock {
Struct hmap_node;/* In ovsdb_server's "locks" hmap .*/
Struct ovsdb_server * server;/* The containing server .*/
Char * Name;/* unique name .*/
Struct list waiters;/* contains "struct ovsdb_lock_waiter" S .*/
};
Waiters is the session table waiting for the lock and is encapsulated into a struct ovsdb_lock_waiter structure. The first node in the list is the current owner of ovsdb_lock.
/* A session's request for a database lock .*/
Struct ovsdb_lock_waiter {
Struct hmap_node session_node;/* In-> session-> locks hmap .*/
Struct ovsdb_lock * lock;/* the lock being waited .*/
Enum ovsdb_lock_mode mode;
Char * lock_name;
Struct ovsdb_session * session;
Struct list lock_node;/* In-> lock-> waiters's list .*/
};
Session_node is the hmap_node of the hmap structure of ovsdb_session-> waiters, lock_node is the list node of ovsdb_lock-> waiters, and session is the ovsdb_session waiting for the ovsdb_lock, name/mode is the name and access method of the ovsdb_lock, and lock is the ovsdb_lock to be obtained by the ovsdb_lock_waiter.
Ovsdb_server_create_lock __, create an ovsdb_lock and add it to the hmap of the ovsdb_server lock.
/* Attempts to acquire the lock named 'lock _ name' for 'session'
* 'Server'. returns the new lock waiter.
*
* If 'Mode' is ovsdb_lock_steal, then the new lock waiter is always the owner
* Of the lock. '* victime' beyond es the Session of the previous owner or null
* If the lock was previusly unowned. (if the victim itself originally
* Obtained the lock through a "steal" operation, then this function also
* Removes the victim from the lock's waiting list .)
*
* If 'Mode' is ovsdb_lock_wait, then the new lock waiter is the owner of
* Lock only if this lock had no existing owner. '* vicdq' is set to null .*/
Struct ovsdb_lock_waiter *
Ovsdb_server_lock (struct ovsdb_server * server,
Struct ovsdb_session * session,
Const char * lock_name,
Enum ovsdb_lock_mode mode,
Struct ovsdb_session ** vicibd)
{
Uint32_t hash = hash_string (lock_name, 0 );
Struct ovsdb_lock_waiter * waiter, * victim;
Struct ovsdb_lock * lock;
Lock = ovsdb_server_create_lock _ (server, lock_name, hash );
Victim = (mode = ovsdb_lock_steal &&! List_is_empty (& lock-> waiters)
? Ovsdb_lock_get_owner (LOCK)
: NULL );
If the lock access mode is ovsdb_lock_steal, the owner of the current lock will become victim; otherwise, the victim is empty.
Waiter = xmalloc (sizeof * waiter );
Waiter-> mode = mode;
Waiter-> lock_name = xstrdup (lock_name );
Waiter-> lock = lock;
If (mode = ovsdb_lock_steal ){
List_push_front (& lock-> waiters, & waiter-> lock_node); // ovsdb_lock_steal can get the lock immediately
} Else {
List_push_back (& lock-> waiters, & waiter-> lock_node); // otherwise, enter lock-> waiters to wait.
}
Waiter-> session = session;
Hmap_insert (& waiter-> session-> waiters, & waiter-> session_node, hash );
If (victim & victim-> mode = ovsdb_lock_steal ){
Ovsdb_lock_waiter_remove (victim); // remove the victime from the lock-> waiters list
}
* Vicibd = victim? Victim-> session: NULL;
Return waiter;
}
Ovsdb_jsonrpc_server is an implementation of ovsdb_server. network communication is implemented through jsonrpc.
Struct ovsdb_jsonrpc_server {
Struct ovsdb_server up;
Unsigned int n_sessions, max_sessions;
Struct Shash remotes;/* contains "struct ovsdb_jsonrpc_remote *" S .*/
};
Struct ovsdb_jsonrpc_remote indicates an active or passive connection pool. If the active connection pool and listener are empty, all external connections are saved in the sessions linked list. If the connection pool is passive, listener indicates receiving connections, and all subsequent accept connections are saved in the sessions linked list.
/* A configured Remote. This is either a passive stream listener plus a list
* Of the currently connected sessions, or a list of exactly one active
* Session .*/
Struct ovsdb_jsonrpc_remote {
Struct ovsdb_jsonrpc_server * server;
Struct pstream * listener;/* listener, if passive .*/
Struct list sessions;/* List of "struct ovsdb_jsonrpc_session" S .*/
Uint8_t dscp;
};
Ovsdb_jsonrpc_session represents a connection in the jsonrpc mode of the client <-> ovsdb.
Struct ovsdb_jsonrpc_session {
Struct list node;/* element in remote's sessions list .*/
Struct ovsdb_session up;
Struct ovsdb_jsonrpc_remote * remote;
/* Triggers .*/
Struct hmap triggers;/* hmap of "struct ovsdb_jsonrpc_trigger" S .*/
/* Monitors .*/
Struct hmap monitors;/* hmap of "struct ovsdb_jsonrpc_monitor" S .*/
/* Network connectivity .*/
Struct jsonrpc_session * js;/* JSON-RPC session .*/
Unsigned int js_seqno;/* Last jsonrpc_session_get_seqno () value .*/
};
Struct ovsdb {
Struct ovsdb_schema * Schema;
Struct list replicas;/* contains "struct ovsdb_replica" S .*/
Struct Shash tables;/* contains "struct ovsdb_table *" S .*/
/* Triggers .*/
Struct list triggers;/* contains "struct ovsdb_trigger" S .*/
Bool run_triggers;
};
Ovs databases are stored in ovsdb_server through struct ovsdb. ovsdb_schema is mainly a key-value table with name <-> ovsdb_table_schema. Each ovsdb_table_schema represents a table schema structure, the code for ovs dB table is in ovsdb/table. h ovsdb/table. c. I will not elaborate on it here.
Static struct ovsdb_jsonrpc_remote *
Ovsdb_jsonrpc_server_add_remote (struct ovsdb_jsonrpc_server * SVR,
Const char * Name,
Const struct ovsdb_jsonrpc_options * options)
{
Struct ovsdb_jsonrpc_remote * remote;
Struct pstream * listener;
Int error;
Error = jsonrpc_pstream_open (name, & listener, options-> dscp );
If (error & error! = Eafnosupport ){
Vlog_err_rl (& RL, "% s: Listen failed: % s", name, strerror (error ));
Return NULL;
}
Added pstream in listen status. If listen fails, an error is returned.
Remote = xmalloc (sizeof * remote );
Remote-> Server = SVR;
Remote-> listener = listener;
List_init (& remote-> sessions );
Remote-> dscp = options-> dscp;
Shash_add (& SVR-> remotes, name, remote );
Here, remote actually receives the data structure of the remote connection. After this step, add the new ovsdb_jsonrpc_remote structure to the ovsdb_jsonrpc_server.
If (! Listener ){
Ovsdb_jsonrpc_session_create (remote, jsonrpc_session_open (name ));
}
Return remote;
}
Static void
Ovsdb_jsonrpc_server_del_remote (struct shash_node * node)
{
Struct ovsdb_jsonrpc_remote * remote = node-> data;
Ovsdb_jsonrpc_session_close_all (remote); used to close connections in the remote> sessions
Pstream_close (Remote-> listener); close remote-> listener connection here
Shash_delete (& remote-> server-> remotes, node); Delete remote from the remotes hash table of ovsdb_jsonrpc_server
Free (remote );
}
Ovsdb_jsonrpc_server_reconnect, which calls struct (struct ovsdb_jsonrpc_remote) for all ovsdb_jsonrpc_remote of ovsdb_jsonrpc_jsonrpc_remote * remote)
Static void
Ovsdb_jsonrpc_session_reconnect_all (struct ovsdb_jsonrpc_remote * remote)
{
Struct ovsdb_jsonrpc_session * s, * next;
List_for_each_safe (S, next, node, & remote-> sessions ){
Jsonrpc_session_force_reconnect (S-> JS );
If (! Jsonrpc_session_is_alive (S-> JS )){
Ovsdb_jsonrpc_session_close (s );
}
}
}
Jsonrpc_session_force_reconnect calls reconnect_force_reconnect, changes its status to s_reconnect, and CALLS ovsdb_jsonrpc_session_close for all active sessions.
Void ovsdb_jsonrpc_server_run (struct ovsdb_jsonrpc_server * SVR)
{
Struct shash_node * node;
Shash_for_each (node, & SVR-> remotes ){
Struct ovsdb_jsonrpc_remote * remote = node-> data;
If (Remote-> listener & SVR-> n_sessions <SVR-> max_sessions ){
Struct stream * stream;
Int error;
Error = pstream_accept (Remote-> listener, & stream); if it is passive remote, try to access the new connection
If (! Error ){
Struct jsonrpc_session * js;
JS = jsonrpc_session_open_unreliably (jsonrpc_open (Stream ),
Remote-> dscp); Create a jsonrpc_session
Ovsdb_jsonrpc_session_create (remote, JS); add jsonrpc_session to ovsdb_jsonrpc_remote
} Else if (error! = Eagain ){
Vlog_warn_rl (& RL, "% s: accept failed: % s ",
Pstream_get_name (Remote-> listener ),
Strerror (error ));
}
}
Ovsdb_jsonrpc_session_run_all (remote); ovsdb_jsonrpc_session_run is called for all sessions in remote. If an error is reported, ovsdb_jsonrpc_session_close closes the session.
}
}
Ovsdb_jsonrpc_session_run calls jsonrpc_session_run to process pending connection/request. If jsonrpc_session does not have a request, call jsonrpc_session_recv to try to receive and process the request.
------------------------------ Analyze the main program of ovsdb-server -----------------------------------
Call ovsdb_file_open to generate the database structure of struct DB from the database file,
Struct dB {
/* Initialized in main ().*/
Char * filename;
Struct ovsdb_file * file;
Struct ovsdb * dB;
/* Only used by update_remote_status ().*/
Struct ovsdb_txn * txn;
};
Call ovsdb_jsonrpc_server_create to create the struct ovsdb_jsonrpc_server structure, and then call ovsdb_jsonrpc_server_add_db to add struct ovsdb * to the hash table structure of the ovsdb_server database.
The following describes how to configure struct ovsdb_jsonrpc_server * jsonrpc based on the database content. This is done through reconfigure_from_db, which mainly configures remote connection and SSL.
Enter the main loop below,
While (! Exiting ){
Int I;
....
Reconfigure_from_db (jsonrpc, DBS, n_dbs, & remotes );
Ovsdb_jsonrpc_server_run (jsonrpc );
Unixctl_server_run (unixctl );
The core here is ovsdb_jsonrpc_server_run, which mainly performs two tasks: a) Call accept to receive all pending connection requests B) Call ovsdb_jsonrpc_session to all existing jsonrpc_session_run, process the request/policy that already has a connection. For a request, call ovsdb_jsonrpc_session_got_request for processing. This function is processed based on different methods of the request. 'transact 'is the most commonly used method.
....
For (I = 0; I <n_dbs; I ++ ){
Ovsdb_trigger_run (DBS [I]. DB, time_msec ());
}
If (run_process & process_exited (run_process )){
Exiting = true;
}
.....
Finally, there are a series of blocking calls, waiting for a new connection or request to come in. All FD are blocked by a poll function in poll_block.
Ovsdb_jsonrpc_server_wait (jsonrpc );
Unixctl_server_wait (unixctl );
For (I = 0; I <n_dbs; I ++ ){
Ovsdb_trigger_wait (DBS [I]. DB, time_msec ());
}
If (run_process ){
Process_wait (run_process );
}
If (exiting ){
Poll_immediate_wake ();
}
Poll_timer_wait_until (status_timer );
Poll_block ();
}