Skip to content
/ libupsf Public

Library implementing the BBF WT-474 Subscriber Session Steering gRPC protocol for C/C++ applications

License

Notifications You must be signed in to change notification settings

bisdn/libupsf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

libupsf

libupsf is a C/C++ client implementation of the Broadband Forum's (BBF) Subscriber Session Steering (SSS) protocol defined by the Access and Transport Architecture (ATA) group in WT-474.

Homepage: https://github.com/bisdn/libupsf

It is used for communication to the User Plane Selection Function (UPSF) in a distributed Broadband Network Gateway (BNG) environment. See the associated BBF documents for details.

Getting started: building and installing

The library's build system is based on cmake and makes use of pkg-config. The list of dependencies includes:

Name Project page
gRPC framework https://grpc.io
Protocol buffers https://protobuf.dev
Google logging library https://github.com/google/glog
Google gflags library https://github.com/gflags/gflags

On Ubuntu 22.04 LTS install the gRPC framework and the associated protobuf compiler:

sh# sudo apt install libgrpc++-dev protobuf-compiler-grpc libgflags-dev

libupsf needs version 0.7.0 or better of Google's logging library. For a manual installation clone the associated repository for building and installing the library:

sh# git clone https://github.com/google/glog
sh# mkdir -p glog/build && cd glog/build
sh# cmake -DCMAKE_INSTALL_PREFIX=<path> -DCMAKE_BUILD_TYPE=Release ..
sh# make && make install

Adjust the PKG_CONFIG_PATH environment variable according to the chosen installation path, e.g.:

sh# export PKG_CONFIG_PATH=<path>/lib/pkgconfig:${PKG_CONFIG_PATH}

Enter libupsf's build directory and run cmake for configuring the project. Start the build process and install the resulting library:

sh# cd libupsf/build
sh# cmake -DCMAKE_INSTALL_PREFIX=<path> ..
sh# make && make install

sh# pkg-config --cflags upsf++
-I<path>/include

sh# pkg-config --libs upsf++
-L<path>/lib -lupsf++

For developers: using libupsf within your project

libupsf provides a C++ and C interface. The latter is a thin wrapper for using the library in a C environment, but linking libupsf to your project still requires a C++ linker. Here a list of source files:

File Description
upsf.h C header file
upsf.hpp C++ header file
upsf_c_wrapper.cpp UPSF C wrapper functions
upsf_c_mapping.hpp functions for bidirectional mapping C to C++ representation
upsf_c_mapping.cpp functions for bidirectional mapping C to C++ representation
upsf_stream.hpp helper output operators for C++ upsf classes
upsf++.pc.in pkg-config template for libupsf

A C based example

Please see file upsf_c_example.c as a starting point for your own project.

The library is thread-aware, i.e., a separate gRPC connection will be used per execution thread. You must call function upsf_open() once in each thread explicitly for specifying UPSF host and port to connect to, though. Changing the associated UPSF host/port requires calling function upsf_close() first before reestablishing the connection. A helper function named upsf_exists() is providing a simple check to verify existence of an active gRPC connection in the calling thread context.

Class UpsfSlot serves as container for all thread local variables including an instance of class UpsfClient (see the C++ related section below).

SSS gRPC item representation

All items are represented by an associated C structure as shown below:

C structure SSS gRPC item
upsf_service_gateway_t Service gateway
upsf_service_gateway_user_plane_t Service gateway user plane
upsf_traffic_steering_function_t Traffic steering function
upsf_shard_t Subscriber group (shard)
upsf_session_context_t Session context
upsf_network_connection_t Network connection

Various C sub-structures exist for the various SSS protobuf definitions, see upsf.h for details.

Arrays are limited to a maximum size of 16 elements: adjust the constants defined in upsf.h to suit your needs in case these limitations do not meet your project's requirements.

Strings defined in the SSS gRPC protobufs are stored in upsf_string_t providing maximum space of 64 bytes for the string and an associated length field indicating the string's actual length.

Create a service gateway user plane

Here an example for creating an SGUP item in the UPSF.

    /* SGUP C structure */
    upsf_service_gateway_user_plane_t item;
    memset(&item, 0, sizeof(item));

    /* populate mandatory fields */
    snprintf(item.name.str, sizeof(item.name.str), "my-up");
    snprintf(item.service_gateway_name.str, UPSF_MAX_STRING_SIZE, "my-sg");
    item.spec.max_session_count = 1024;
    item.spec.max_shards = 128;

    /* create service gateway user plane */
    if (upsf_create_service_gateway_user_plane(&item) == NULL) {
        return -1;
    }
    /* item contains updated SGUP received from UPSF */
    ...

Update a service gateway user plane

Here an example for updating an SGUP item in the UPSF.

    /* SGUP C structure */
    upsf_service_gateway_user_plane_t item;
    memset(&item, 0, sizeof(item));

    /* populate mandatory fields */
    snprintf(item.name.str, sizeof(item.name.str), "my-up");
    snprintf(item.service_gateway_name.str, UPSF_MAX_STRING_SIZE, "my-sg");
    item.spec.max_session_count = 1024;
    item.spec.max_shards = 128;
    item.status.allocated_session_count = 7;
    item.status.allocated_shards = 1;

    /* specify SGUP default endpoint */
    item.spec.default_endpoint.ep_type = UPSF_EP_TYPE_VTEP;
    snprintf(item.spec.default_endpoint.endpoint_name.str, UPSF_MAX_STRING_SIZE, "my-up-ep1");
    snprintf(item.spec.default_endpoint.ep_spec.vtep.ip_address.str, UPSF_MAX_STRING_SIZE, "1.2.3.4");
    item.spec.default_endpoint.ep_spec.vtep.udp_port = 4789;
    item.spec.default_endpoint.ep_spec.vtep.vni = 1234;

    /* create service gateway user plane */
    if (upsf_create_service_gateway_user_plane(&item) == NULL) {
        return -1;
    }
    /* item contains updated SGUP received from UPSF */
    ...

Read a service gateway user plane

Here an example for reading an SGUP item from the UPSF.

    /* SGUP C structure */
    upsf_service_gateway_user_plane_t item;
    memset(&item, 0, sizeof(item));

    /* populate mandatory fields */
    snprintf(item.name.str, sizeof(item.name.str), "my-up");

    /* read service gateway user plane */
    if (upsf_get_service_gateway_user_plane(&item) < 0) {
        return -1;
    }
    /* item contains updated SGUP received from UPSF */
    ...

Delete a service gateway user plane

Here an example for deleting an SGUP item from UPSF.

    /* SGUP C structure */
    upsf_service_gateway_user_plane_t item;
    memset(&item, 0, sizeof(item));

    /* populate mandatory fields */
    snprintf(item.name.str, sizeof(item.name.str), "my-up");

    /* delete service gateway user plane */
    if (upsf_delete_service_gateway_user_plane(&item) < 0) {
        return -1;
    }

A C++ based example

Please see file upsf_cpp_example.cpp as a starting point for your own project.

Class UpsfClient serves as container for all thread local variables including the gRPC channel and associated protocol stub. Please find below a simple example for wrapping UpsfClient in another class:

    #include <upsf.hpp>

    class UpsfExample {
        private:
            upsf::UpsfClient client;


        public:
            UpsfExample(const std::string &srv_addr = std::string("127.0.0.1:50051")) :
                client(
                    grpc::CreateChannel(
                        srv_addr,
                        grpc::InsecureChannelCredentials()
                    )
                )
            { ... };
    }

Create a service gateway user plane

Here an example for creating an SGUP item in the UPSF.

    std::string srv_addr("127.0.0.1:50051");

    upsf::UpsfClient client(
        grpc::CreateChannel(
            srv_addr, 
            grpc::InsecureChannelCredentials()
        )
    );

    wt474_messages::v1::ServiceGatewayUserPlane request;
    wt474_messages::v1::ServiceGatewayUserPlane reply;

    /* populate mandatory fields */
    request.set_name(std::string("my-up"));
    request.set_service_gateway_name(std::string("my-sg"));
    request.mutable_spec()->set_max_session_count(1024);
    request.mutable_spec()->set_max_shards(128);

    /* create service gateway user plane, returns 0 in case of failure */
    if (!client.CreateV1(request, reply)) {
        // handle error
        return;
    }
    // reply contains SGUP received from UPSF

Update a service gateway user plane

Here an example for updating an SGUP item in the UPSF.

    std::string srv_addr("127.0.0.1:50051");

    upsf::UpsfClient client(
        grpc::CreateChannel(
            srv_addr, 
            grpc::InsecureChannelCredentials()
        )
    );

    wt474_messages::v1::ServiceGatewayUserPlane request;
    wt474_messages::v1::ServiceGatewayUserPlane reply;
    wt474_upsf_service::v1::UpdateReq::UpdateOptions options;

    /* populate mandatory fields */
    request.set_name(std::string("my-up"));
    request.set_service_gateway_name(std::string("my-sg"));
    request.mutable_spec()->add_supported_service_group("ssg-1");
    request.mutable_spec()->add_supported_service_group("ssg-2");
    request.mutable_spec()->mutable_default_endpoint()->set_endpoint_name("my-up-ep1");
    request.mutable_spec()->mutable_default_endpoint()->mutable_vtep()->set_ip_address("1.2.3.4");
    request.mutable_spec()->mutable_default_endpoint()->mutable_vtep()->set_udp_port(4789);
    request.mutable_spec()->mutable_default_endpoint()->mutable_vtep()->set_vni(12345);
    request.mutable_status()->set_allocated_session_count(7);
    request.mutable_status()->set_allocated_shards(1);

    /* update service gateway user plane, returns 0 in case of failure */
    if (!client.UpdateV1(request, reply, options)) {
        // handle error
        return;
    }
    // reply contains SGUP received from UPSF

Read a service gateway user plane

Here an example for reading a single SGUP item from the UPSF.

    std::string srv_addr("127.0.0.1:50051");

    upsf::UpsfClient client(
        grpc::CreateChannel(
            srv_addr, 
            grpc::InsecureChannelCredentials()
        )
    );

    wt474_messages::v1::ServiceGatewayUserPlane reply;

    /* read service gateway user plane, returns 0 in case of failure */
    if (!client.ReadV1(std::string("my-up"), reply)) {
        // handle error
        return;
    }
    // reply contains SGUP received from UPSF

And for reading the entire list of SGUP instances stored in UPSF:

    std::string srv_addr("127.0.0.1:50051");

    upsf::UpsfClient client(
        grpc::CreateChannel(
            srv_addr, 
            grpc::InsecureChannelCredentials()
        )
    );

    std::vector<wt474_messages::v1::ServiceGatewayUserPlane> items;

    /* read service gateway user plane, returns 0 in case of failure */
    if (!client.ReadV1(items)) {
        // handle error
        return;
    }
    // items contains all SGUP instances received from UPSF

Delete a service gateway user plane

Here an example for deleting an SGUP item from UPSF.

    std::string srv_addr("127.0.0.1:50051");

    upsf::UpsfClient client(
        grpc::CreateChannel(
            srv_addr, 
            grpc::InsecureChannelCredentials()
        )
    );

    std::string reply;

    /* delete service gateway user plane, returns 0 in case of failure */
    if (!client.DeleteV1(std::string("my-up"), reply)) {
        // handle error
        return;
    }
    // reply contains status message received from UPSF

Subscribing to UPSF emitted notifications

The SSS gRPC protobuf definition includes a mechanism for receiving a continuous stream of events for certain types of items stored in the UPSF database. The following sub-sections cover this subscription process for both C and C++ based applications.

C subscriber example

Main entry point for subscribing to UPSF emitted notifications is function upsf_subscribe(). This function blocks and never returns upon reception of notifications so it is best run within its own background thread. It accepts a set of parameters including:

Parameter Example value Description
upsf_host 127.0.0.1 UPSF server host to connect to
upsf_port 50051 UPSF server port to connect to
userdata ... An opaque void pointer to arbitrary user data used by callbacks and ignored by libupsf

In addition a set of callbacks must be specified for those items one is interested in (set the associcated callback to nullptr for skipping certain item types).

See next table for their prototype definitions:

SSS item type Callback prototype
Service gateway typedef int (*upsf_service_gateway_cb_t)(upsf_service_gateway_t* service_gateway, void* userdata);
Service gateway user plane typedef int (*upsf_service_gateway_user_plane_cb_t)(upsf_service_gateway_user_plane_t* service_gateway_user_plane, void* userdata);
Traffic steering function typedef int (*upsf_traffic_steering_function_cb_t)(upsf_traffic_steering_function_t* traffic_steering_function, void* userdata);
Subscriber group (shard) typedef int (*upsf_shard_cb_t)(upsf_shard_t* shard, void* userdata);
Session context typedef int (*upsf_session_context_cb_t)(upsf_session_context_t* session_context, void* userdata);
Network connection typedef int (*upsf_network_connection_cb_t)(upsf_network_connection_t* network_connection, void* userdata);

Here an example for a UPSF notification service:

    int service_gateway_cb(upsf_service_gateway_t* data, void* userdata)
    {
        /* use data */
        return 1; /* continue subscribe */
    }
    
    int service_gateway_user_plane_cb(upsf_service_gateway_user_plane_t* data, void* userdata)
    {
        /* use data */
        return 1; /* continue subscribe */
    }
    
    int shard_cb(upsf_shard_t* data, void* userdata)
    {
        /* use data */
        return 1; /* continue subscribe */
    }
    
    int session_context_cb(upsf_session_context_t* data, void* userdata)
    {
        /* use data */
        return 1; /* continue subscribe */
    }
    
    int network_connection_cb(upsf_network_connection_t* data, void* userdata)
    {
        /* use data */
        return 1; /* continue subscribe */
    }
    
    int traffic_steering_function_cb(upsf_traffic_steering_function_t* data, void* userdata)
    {
        /* use data */
        return 1; /* continue subscribe */
    }
    
    int subscribe()
    {
        /* opaque pointer to arbitrary user data */
        void* userdata = NULL;
    
        /* never returns */
        if (upsf_subscribe("127.0.0.1", 50051, userdata,
            &shard_cb,
            &session_context_cb,
            &network_connection_cb,
            &service_gateway_user_plane_cb,
            &traffic_steering_function_cb,
            &service_gateway_cb) < 0) 
        {
            return -1;
        }
    
        return 0;
    }

C++ subscriber example

For subscribing to UPSF emitted notifications main entry point is class UpsfSubscriber. It contains the following parameters:

Parameter Type Description
watch bool Boolean value for continuous reception
item_types std::vector<wt474_messages::v1::ItemType>& Vector of SSS item types
derived_states std::vector<wt474_messages::v1::DerivedState>& Vector of SSS derived states
parents std::vector<std::string>> Vector of item parents to watch
names std::vector<std::string>> Vector of item names to watch

Set watch to true to receive continuous notifications, its default is false!

Overwrite the associated notification methods defined in class UpsfSubscriber to receive notifications for a specific item type:

class UpsfExample : public upsf::UpsfSubscriber
{
public:
    virtual void notify(
        const wt474_messages::v1::Shard& shard);

    virtual void notify(
        const wt474_messages::v1::SessionContext& session_context);

    virtual void notify(
        const wt474_messages::v1::NetworkConnection& network_connection);

    virtual void notify(
        const wt474_messages::v1::ServiceGatewayUserPlane& service_gateway_user_plane);

    virtual void notify(
        const wt474_messages::v1::TrafficSteeringFunction& traffic_steering_function);

    virtual void notify(
        const wt474_messages::v1::ServiceGateway& service_gateway);
}

About

Library implementing the BBF WT-474 Subscriber Session Steering gRPC protocol for C/C++ applications

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published