Data Accelerator Offload Logo
  • Introduction
  • Getting started Guide
  • Programmer’s Guide
    • 1. Common Libraries
    • 2. DMA Library
    • 3. Ethernet Transport Library
    • 4. Flow Library
    • 5. Liquid Crypto Library
    • 6. Netlink Library
      • 6.1. Introduction
      • 6.2. Native netlink registration
        • 6.2.1. Netlink protocols
        • 6.2.2. Native parse callbacks
        • 6.2.3. Netlink multicast groups
        • 6.2.4. Notifier Object
      • 6.3. High level netlink registration
        • 6.3.1. NETLINK_ROUTE
        • 6.3.2. NETLINK_XFRM
      • 6.4. Programming model
        • 6.4.1. Initialization
        • 6.4.2. Periodic Netlink polling
        • 6.4.3. Netlink Cleanup
    • 7. PEM Library
    • 8. Port Group Library
    • 9. Port Queue Group Library
    • 10. VFIO Library
    • 11. VirtIO Library
    • 12. VirtIO Net Library
  • Application User Guide
  • HowTo Guides
  • Contributor’s Guidelines
  • Release Notes
  • DAO Community Lab
  • FAQ
Data Accelerator Offload
  • Programmer’s Guide
  • 6. Netlink Library
  • View page source

6. Netlink Library

6.1. Introduction

Netlink library provides an abstraction on top of open source libnl library using which application gets notified for a received netlink message from LINUX. Applications are notified via function callback for the netlink protocols they have registered.

6.2. Native netlink registration

Registering for a netlink protocol via dao_netlink_register() is named as Native netlink registration. dao_netlink_register() is a lowest level abstraction API to get notifications for any netlink message that corresponds to netlink protocol provided as an argument to it. dao_netlink_register() has following declaration:

int dao_netlink_register(int protocol, dao_netlink_parse_cb_t parse_cb,
                         void *app_ops, void *app_cookie, ...);

where,
protocol eg: NETLINK_ROUTE, NETLINK_XFRM etc.
parse_cb   : See documentation for more details
app_ops    : Application specific function pointers
app_cookie : Application cookie to identify received notification
...        : comma-separated netlink multicast groups. See documentation for more details

This registration is native in a sense that application is expected to parse received netlink object (struct nl_object *) by itself, perhaps via native libnl APIs, which is passed as an argument to parse_cb

Applications which does not wish to parse netlink object (struct nl_object *) or rather work with any libnl APIs, please refer to high level netlink registration section

6.2.1. Netlink protocols

dao_netlink_register() takes netlink protocol or netlink family as a first argument. Examples of netlink protocols are: NETLINK_ROUTE, NETLINK_XFRM, NETLINK_GENERIC

6.2.1.1. Netlink Object

On successful return, dao_netlink_register() internally opens a netlink socket for provided netlink protocol. It also internally creates a netlink object for registered protocol. For a given netlink protocol, exactly one netlink object is created which holds netlink socket and file descriptor associated with it.

Application can perform following actions on a netlink object

6.2.1.1.1. Registered netlink object lookup

Get netlink object corresponding registered netlink protocol

void *notifier = dao_netlink_lookup(NETLINK_ROUTE);
6.2.1.1.2. Get netlink file descriptor
int fd = dao_netlink_fd_get(netlink);
6.2.1.1.3. Netlink object cleanup

Close netlink socket and free any associated memory including all notifier objects

dao_netlink_close(netlink);

6.2.2. Native parse callbacks

Function callbacks of type dao_netlink_parse_cb_t are called as native parse callbacks which has following function declaration

typedef void (*dao_netlink_parse_cb_t) (struct nl_object *nl_obj, void *notifier);

Applications are expected to parse struct nl_object * by itself using libnl core APIs.``notifier`` is a notifier object

6.2.3. Netlink multicast groups

Each netlink family or protocol has set of defined multicast groups. Application should be able to provide specific multicast group it would like to get notification for within a given protocol. Examples for multicast groups are

Protocol               Multicast Groups
--------               ----------------
NETLINK_ROUTE          RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV4_ROUTE,
                       RTNLGRP_IPV4_RULE, RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV6_ROUTE,
                       RTNLGRP_IPV6_RULE, RTNLGRP_NOTIFY, RTNLGRP_NEIGH etc..

NETLINK_XFRM           XFRMGRP_SA, XFRMGRP_POLICY, XFRMGRP_EXPIRE

Multicast groups for a netlink protocol are provided as comma-separated arguments to dao_netlink_register(). For eg:

dao_netlink_register(NETLINK_ROUTE, route_parse_cb, NULL, NULL,
                     RTNLGRP_IPV4_ROUTE, RTNLGRP_LINK, RTNL_GRP_IPV4_IFADDR);

dao_netlink_register(NETLINK_XFRM, xfrm_parse_cb, NULL, NULL,
                     XFRMGRP_SA, XFRMGRP_POLICY, XFRMGRP_EXPIRE);

It is possible to provide separate parse_cb() for each multicast group like following

dao_netlink_register(NETLINK_ROUTE, parse_cb1, ops1, aux1, RTNLGRP_IPV4_ROUTE);
dao_netlink_register(NETLINK_ROUTE, parse_cb2, ops2, aux2,, RTNLGRP_LINK);

In above case, parse_cb1() will be called once RTNLGRP_IPV4_ROUTE netlink messages are received while parse_cb2() will be called if netlink messages corresponding to RTNLGRP_LINK are received.

Warning

Providing different parse callbacks for same multicast group is not supported

6.2.4. Notifier Object

As described above, dao_netlink_register() can be called multiple times for each combination of [protocol, multicast group]. For each multicast group, different specific cookies can be provided. For eg:

dao_netlink_register(NETLINK_ROUTE, parse_cb1, app_ops1, app_cookie1, RTNLGRP_IPV4_ROUTE);
dao_netlink_register(NETLINK_ROUTE, parse_cb2, app_ops2, app_cookie2, RTNLGRP_LINK);

For each dao_netlink_register() successful registration, library internally creates a notifier object which keep hold of all provided multicast groups, application specific app_ops and app_cookie.

Notifier object is passed as an argument to parse_cb(struct nl_object *obj, void *netlink). Application specific cookies can be retrieved in parse_cb()

6.2.4.1. Application specific ops

void *app_ops = dao_netlink_notifier_callback_ops_get(notifier);

6.2.4.2. Application specific cookie

void *app_cookie = dao_netlink_notifier_app_cookie_get(notifier);

6.2.4.3. Get notifier object for a given parse_cb

void *notifier = dao_netlink_notifier_lookup_by_parse_cb(netlink, parse_cb);

6.3. High level netlink registration

High level netlink registrations are wrappers on top of native netlink registration where application does not deal with libnl APIs or structures, instead this library defines function callbacks for each of the netlink protocol supported for high level registration.

Following protocols are supported for high level netlink registration.

6.3.1. NETLINK_ROUTE

dao_netlink_route_notifier_register(dao_netlink_route_callback_ops_t *ops,
                                    const char *filter_prefix);

Refer to dao_netlink_route_callback_ops_t for getting route netlink message notifications

6.3.2. NETLINK_XFRM

dao_netlink_xfrm_notifier_register(dao_netlink_xfrm_callback_ops_t *ops, void *app_cookie);

Refer to dao_netlink_xfrm_callback_ops_t for getting XFRM netlink message notifications

6.4. Programming model

6.4.1. Initialization

Either use native or high level registration mechanism for getting netlink message notifications

6.4.2. Periodic Netlink polling

A control core is supposed to poll all netlink objects for any new netlink message arrival and hence recvmsg() like function must be invoked on all opened netlink sockets.

For netlink polling, applications are required to call following APIs periodically for getting any new netlink notifications

6.4.2.1. dao_netlink_poll()

Periodically calls recvmsg() on all created netlink sockets and call application specific function callback for any new netlink message

6.4.2.2. dao_netlink_poll_complete()

Once a notification is sent to application for a netlink message via dao_netlink_poll(), library disables further polling on that specific netlink socket until application does not call dao_netlink_poll_complete(). This API enables polling on all netlink sockets which are disabled temporarily after new message notification

dao_netlink_poll_complete() is useful in use-case where dao_netlink_poll() is running in another thread context, perhaps in continuous loop, and current thread wants to control its polling using dao_netlink_poll_complete()

6.4.2.3. Pseudo-code

Following example shows how to receive route updates for LINUX tap interfaces: dtap0 and dtap1

/* Get application specific identifier or cookie for each interface name
 * which is passed in remaining function callbacks
 */
int rops_app_interface_cookie (char *interface_name, int interface_name,
                               uint32_t *cookie)
{
    if(strstr(interface_name, "dtap0") {
        /* Return 0th index for tap0 interface */
        *cookie = 0;
        return 0;
    } else if (strstr (interface_name, "dptap1") {
        /* Return 1st index for tap1 interface */
        *cookie = 0;
        return 0;
    } else {
        /* interested only on dtap0 and dtap1 interface only */
        return -1;
    }
}

/* Set Local IP to interface */
int rops_app_ip_local_addr_add_del(dao_netlink_route_ip_addr_t *addr, int is_add)
{
    int interface_cookie = addr->app_if_cookie; /*< Set in get_app_interface_cookie() */

    if(interface_cookie == 0){
        /* Apply IP address to interface dtap0 */
    } else
        /* Apply IP address to interface dtap1 */
}

/* Update mac address */
int rops_app_link_addr_add_del(dao_netlink_route_link_t *link, int is_add)
{
    int interface_cookie = link->app_if_cookie; /*< Set in get_app_interface_cookie() */

    if(interface_cookie == 0){
        /* Update link "dtap0" */
    } else
        /* Update link "dtap1" *//
}


dao_netlink_route_callback_ops_t rops {
    .get_app_interface_cookie = rops_app_interface_cookie,
    .ip_local_addr_add_del = rops_app_ip_local_addr_add_del,
    .ip_route_add_del = rops_app_ip_route_add_del,
    .link_add_del = rops_app_link_add_del,
    .ip_neigh_add_del = rops_app_ip_neigh_add_del,
};

 int __poll_function(void *obj, const int is_main)
 {
     rte_graph_t *graph = (rte_graph_t *)obj

     /* Get this worker core handle for graph */
     graph = graph + rte_lcore_id();

     while (1) {
        if (is_main) {

           dao_netlink_poll();

            ...
            ... Do other stuff
            ...

           dao_netlink_poll_complete();

         } else {
             rte_graph_walk(graph);
         }
     }
 }

 void poll_function(void *obj)
 {
     if (rte_lcore_id() == rte_get_main_lcore()) {
             __poll_function(obj, 1);
     } else {
             __poll_function(obj, 0);
     }
 }

 int main ()
 {
    rte_graph_t graph[RTE_LCORE_MAX];

    /* Use high level netlink registration method */
    if (dao_netlink_route_notifier_register(&rops, "dtap" /* prefix string for dtap0 and dtap1 */) < 0)
        return -1;

     /* Create rte_graph object for every lcore_id */
     ...
     ...
     ...

    rte_eal_remote_launch(poll_function, graph,  CALL_MAIN);
 }

6.4.3. Netlink Cleanup

Call dao_netlink_cleanup() to close all netlink sockets and notifier object including any associated memory

Previous Next

© Copyright 2024, Marvell.

Built with Sphinx using a theme provided by Read the Docs.