API Usage ========= In this section, we give some simple examples of using both the netlink raw API, and the higher-level SDN API. An obvious cautionary note: you are modifying your network stack (possibly remotely), so don't drop your any configuration that would disconnect you (e.g., your control interface, its subnet route(s), and its default route)! These examples use the ``curl`` command-line tool, but you could also use ``wget`` or ``fetch``. ``nlsdn`` is effectively a netlink wrapper, and the implementation is based on the ``pyroute2`` Netlink Python library. Thus, much of the input data to individual API calls is best defined by the documentation for those APIs. You can find a detailed netlink reference at http://man7.org/linux/man-pages/man7/rtnetlink.7.html ; the ``pyroute2`` documentation is at https://docs.pyroute2.org/iproute.html . Often, it is unnecessary to specify full Netlink attribute names; ``pyroute2`` does a great job expanding unprefixed attribute names to the appropriate prefixed names, given the calling context (e.g., link, address, route, etc.). All ``POST``/``DELETE`` data is JSON-encoded, and you should specify a ``Content-type: text/json`` header in your request. ``GET`` calls only accept URL parameters. Successful ``POST`` requests return HTTP 2xx and no content. Unsuccessful requests return an HTTP error code (e.g., 404, 500), and a simple JSON dictionary with a ``error`` member that describes the problem. The ``curl``-based examples in the following sections assume an SSL/TLS-enabled ``nlsdn`` server running on ``localhost:56789``, that is configured to accept the ``admin``/``admin`` username and password credentials. We replace the common part of the URL frontmatter for the netlink API endpoint with the ``$NLSERVER`` shell variable (and similarly for the ``$SDNSERVER`` variable), so make sure to export those variables (and modify as necessary to your config) prior to running the examples: .. code-block:: shell export NLSERVER=https://localhost:56789/service/nl/v1 export SDNSERVER=https://localhost:56789/service/nlsdn/v1 ``nl`` API Endpoint ------------------- This subsection defines the raw ``netlink`` API. It exposes most of the traditional ``netlink`` resources and operations, but not all. ``GET`` requests return lists of dictionaries, each describing a resource (link, address, route, etc). These are defined in the netlink man page (http://man7.org/linux/man-pages/man7/rtnetlink.7.html), but they all follow a common format, containing several top-level keys, and a very detailed, resource-specific list of attributes (in the ``attrs``) key. All ``GET`` requests accept several common parameters that allow you to filter the output data, both by the high-level key names, and the lower-level attribute names. * ``_filter``: if set to ``0``, exclude any of the supplied ``_keys`` and ``_attrs``. If set to ``1``, include only the supplied ``_keys`` and ``_attrs``. * ``_keys``: include or exclude the given keys. * ``_attrs``: include or exclude the given attributes. Note that these may be short attribute names (e.g. ``ifname`` instead of ``IFLA_IFNAME``), just as for input data to ``POST`` or ``DELETE`` requests. ``nl/links`` ~~~~~~~~~~~~ ``GET``: Returns a list of dictionaries, each corresponding to a ``struct ifinfomsg`` returned by a ``RTM_GETLINK`` netlink request. You may specify URL parameters that correspond to ``struct ifinfomsg`` (or to its ``pyroute2`` short names and short attribute names), such as ``family``, ``ifindex``, ``ifname``, etc. Instead of searching for a specific device by ``ifindex``, you could also simply using the ``nl/links/`` URL; or the ``nl/links/`` URL instead of ``ifname``. To return all information about all links: .. code-block:: shell curl -k -u admin:admin "${NLSERVER}/links" To only return some of the information about the ``lo`` device: .. code-block:: shell curl -k -u admin:admin \ "${NLSERVER}/links?ifname=lo&_filter=1&_keys=family,attrs&_attrs=ifname" ``POST``: Creates a new link according to the JSON dictionary specified as the input data (e.g., the ``RTM_NEWLINK`` netlink message). For instance, to create a link named ``dummy1`` using the ``dummy`` driver: .. code-block:: shell curl -k -u admin:admin -H 'content-type: text/json' -X POST \ -d '{"ifname":"dummy1","kind":"dummy"}' \ "${NLSERVER}/links" ``DELETE``: Deletes one or more links according to the JSON dictionary specified as the input data (e.g., the ``RTM_DELLINK`` netlink message). For instance, to delete the ``dummy1`` link we previously created: .. code-block:: shell curl -k -u admin:admin -H 'content-type: text/json' -X DELETE \ -d '{"ifname":"dummy1","kind":"dummy"}' \ "${NLSERVER}/links" ``nlsdn`` API Endpoint ---------------------- This subsection covers the higher-level SDN API. The API is currently quite simple: it supports :py:class:`nlsdn.server.sdn.Match` rules that, when match a given flow, perform an :py:class:`nlsdn.server.sdn.Action`. Each of these types of objects are created separately, so you must first create an :py:class:`nlsdn.server.sdn.Action`, then create a :py:class:`nlsdn.server.sdn.Match` that references the :py:class:`nlsdn.server.sdn.Action`. Both objects are identified by an alphanumeric ID, returned after creation. We currently support :py:class:`nlsdn.server.sdn.RuleMatch` match objects, which are implemented by ``ip rule``; and :py:class:`nlsdn.server.sdn.RouteAction` and :py:class:`nlsdn.server.sdn.Seg6Action` actions, both implemented by ``ip route`` statements in per-instance routing tables. A matching rule points to a route table containing an action. ``nlsdn/match`` ~~~~~~~~~~~~~~~ ``GET``: Returns a dictionary of :py:class:`nlsdn.server.sdn.Match` objects, indexed by number. Each number key points to a dictionary containing the Match keys. For instance, to show all ``Match`` objects, .. code-block:: shell curl -k -u admin:admin "${NLSDNSERVER}/match" or to show a specific match .. code-block:: shell curl -k -u admin:admin "${NLSDNSERVER}/match/500" ``POST``: Creates a ``Match`` object. The type of ``Match`` object created is determined based on the value of the ``type`` key. For instance, to create a RuleMatch, you would provide a dictionary containing a subset of these keys (:py:obj:`nlsdn.server.sdn.RuleMatch.NL_KEYS`), like so: .. code-block:: shell curl -k -u admin:admin -H 'content-type: text/json' -X POST \ -d '{"type":"rule","priority":500,"src":"127.0.0.1","src_len":32, \ "sport_range":[56789,56789],"dst":"8.8.8.8","dst_len":32,"oifname":"wlp3s0", \ "action_id":500}' \ "${NLSDNSERVER}/match" (Note that the use of the ``sport_range`` attribute currently requires our forked version of ``pyroute2``, available at https://gitlab.flux.utah.edu/safeedge/pyroute2 .) This would create a ``rule`` (:py:class:`nlsdn.server.sdn.RuleMatch`) ``Match`` object that matches traffic from ``127.0.0.1:56789`` heading to ``8.8.8.8`` via ``wlp3s0``, and direct it to the ``Action`` with ID ``500``. ``DELETE``: You can delete a ``Match`` object by its ID. Note that you must delete ``Match`` objects prior to deleting the ``Actions`` they reference. For instance, to delete the ``RuleMatch`` object created above, you would .. code-block:: shell curl -k -u admin:admin -H 'content-type: text/json' -X DELETE \ "${NLSDNSERVER}/match/500" ; echo ``nlsdn/action`` ~~~~~~~~~~~~~~~~ ``GET``: Returns a dictionary of :py:class:`nlsdn.server.sdn.Action` objects, indexed by number. Each number key points to a dictionary containing the Action keys. For instance, to show all ``Action`` objects, .. code-block:: shell curl -k -u admin:admin "${NLSDNSERVER}/action" or to show a specific action .. code-block:: shell curl -k -u admin:admin "${NLSDNSERVER}/action/500" ``POST``: .. code-block:: shell curl -k -u admin:admin -H 'content-type: text/json' -X POST \ -d '{"type":"route","number":500,"dst":"8.8.8.8","dst_len":32, \ "oif":68}' \ "${NLSDNSERVER}/action" ``DELETE``: You can delete an ``Action`` object by its ID. Note that you must delete ``Match`` objects prior to deleting the ``Actions`` they reference. For instance, to delete the ``RouteAction`` object created above, you would .. code-block:: shell curl -k -u admin:admin -H 'content-type: text/json' -X DELETE \ "${NLSDNSERVER}/action/500" ; echo