Once you have a working development environment, the steps to create a
new API are:
</p>
<ol><li>define the public API</li><li>define the internal driver API</li><li>implement the public API</li><li>define the wire protocol format</li><li>implement the RPC client</li><li>implement the server side dispatcher</li><li>implement the driver methods</li><li>add virsh support</li></ol>
<p>
It is, of course, possible to implement the pieces in any order, but
if the development tasks are completed in the order listed, the code
will compile after each step. Given the number of changes required,
verification after each step is highly recommended.
</p>
<p>
Submit new code in the form shown in the example code: one patch
per step. That's not to say submit patches before you have working
functionality--get the whole thing working and make sure you're happy
with it. Then use git or some other version control system that lets
you rewrite your commit history and break patches into pieces so you
don't drop a big blob of code on the mailing list at one go. For
example, I didn't follow my own advice when I originally submitted the
example code to the libvirt list but rather submitted it in several
large chunks. I've used git's ability to rewrite my commit history to
break the code apart into the example patches shown.
</p>
<p>
Don't mix anything else into the patches you submit. The patches
should be the minimal changes required to implement the functionality
you're adding. If you notice a bug in unrelated code (i.e., code you
don't have to touch to implement your API change) during development,
create a patch that just addresses that bug and submit it
separately.
</p>
<p>With that said, let's begin.</p>
<h2>
<aname="publicapi"id="publicapi">Defining the public API</a>
</h2>
<p>The first task is to define the public API and add it to:</p>
<p>
<code>include/libvirt/libvirt.h.in</code>
</p>
<p>
This task is in many ways the most important to get right, since once
the API has been committed to the repository, it's libvirt's policy
never to change it. Mistakes in the implementation are bugs that you
can fix. Make a mistake in the API definition and you're stuck with
it, so think carefully about the interface and don't be afraid to
rework it as you go through the process of implementing it.
</p>
<p>Once you have defined the API, you have to add the symbol names to:</p>
<p>
<code>src/libvirt_public.syms</code>
</p>
<pclass="example">See <ahref="api_extension/0001-Step-1-of-8-Define-the-public-API.patch">0001-Step-1-of-8-Define-the-public-API.patch</a> for example code.</p>
<h2>
<aname="internalapi"id="internalapi">Defining the internal API</a>
</h2>
<p>
Each public API call is associated with a driver, such as a host
virtualization driver, a network virtualization driver, a storage
virtualization driver, a state driver, or a device monitor. Adding
the internal API is ordinarily a matter of adding a new member to the
struct representing one of these drivers.
</p>
<p>
Of course, it's possible that the new API will involve the creation of
an entire new driver type, in which case the changes will include the
creation of a new struct type to represent the new driver type.
</p>
<p>The driver structs are defined in:</p>
<p>
<code>src/driver.h</code>
</p>
<p>
To define the internal API, first typedef the driver function
prototype and then add a new field for it to the relevant driver
Once these changes are in place, it's necessary to run 'make rpcgen'
in the qemud directory to create the .c and .h files required by the
remote protocol code. This must be done on a Linux host using the
GLibC rpcgen program. Other rpcgen versions may generate code which
results in bogus compile time warnings
</p>
<h2>
<aname="rpcclient"id="rpcclient">Implement the RPC client</a>
</h2>
<p>
Implementing the RPC client is also relatively mechanical, so refer to
the exising code and example patch for guidance. The RPC client uses
the rpcgen generated .h files. The remote method calls go in:
</p>
<p>
<code>src/remote_internal.c</code>
</p>
<p>Each remote method invocation does the following:</p>
<olclass="ordinarylist"><li>locks the remote driver;</li><li>sets up the method arguments;</li><li>invokes the remote function;</li><li>checks the return value, if necessary;</li><li>extracts any returned data;</li><li>frees any returned data;</li><li>unlocks the remote driver.</li></ol>
<p>
Once you have created the remote method calls, you have to add fields
for them to the driver structs for the appropriate remote driver.