Regarding local-source IP address and DSCP configuration

23 views
Skip to first unread message

Koti Gaddam

unread,
Mar 3, 2026, 3:28:23 AM (2 days ago) Mar 3
to grpc.io
Hi,

We are planning to use gRPC as the transport protocol in our products for telemetry applications.

As part of the requirement - We are supposed to use the local-source ip address as the source ip address of the packt and dscp configuration while sending the packets out to the collector.

 subscription sub1
  local-source-address context local 100.1.1.1 1025
  originated-qos-marking 10

Based on my analysis - I don't find exactly the direct gRPC APIs to call and update the local-source ip address while creating the channel, rather I believe we should use some kind of mutator approach with custome code as below to update the local-source ip address after socket is created internally by the gRPC during the channel creation.

Below are my questions  -
        -  Is it the right approach(production level) to have a mutator with some custome code integrated in to the gRPC core and then call the mutator to update the local-source ip address...?. 
        - Are other vendors following the similar approach for gRPC for local-source ip address configuration..?
       - It would be really appreciated if you could provide any reference code in gRPC for updating the local-source ip address as well as for dscp configuration.

----- code snippet -----

#include <grpcpp/grpcpp.h>

#include <grpc/impl/codegen/grpc_types.h>

#include <arpa/inet.h>

#include <sys/socket.h>

 

// 1. The Mutator: Focused ONLY on local IP binding

class LocalBindMutator : public grpc_socket_mutator {

public:

    LocalBindMutator(const std::string& ip) : ip_(ip) {

        // Initialize the base C-style vtable

        grpc_socket_mutator_init(this, &vtable_);

    }

 

    static bool Mutate(int fd, grpc_socket_mutator* mutator) {

        auto* self = static_cast<LocalBindMutator*>(mutator);

       

        sockaddr_in addr{};

        addr.sin_family = AF_INET;

        addr.sin_port = 0; // Let OS pick the source port

        inet_pton(AF_INET, self->ip_.c_str(), &addr.sin_addr);

 

        // Bind the socket to the specific local IP

        return bind(fd, (reinterpret_cast<const sockaddr*>(&addr)), sizeof(addr)) == 0;

    }

 

    static int Compare(grpc_socket_mutator* a, grpc_socket_mutator* b) {

        return (a < b) ? -1 : ((a > b) ? 1 : 0);

    }

 

    static void Destroy(grpc_socket_mutator* mutator) {

        delete static_cast<LocalBindMutator*>(mutator);

    }

 

private:

    std::string ip_;

    static constexpr grpc_socket_mutator_vtable vtable_ = { Mutate, Compare, Destroy };

};

 

// Define the static vtable outside the class

constexpr grpc_socket_mutator_vtable LocalBindMutator::vtable_;

 

// 2. The Wrapper API

std::shared_ptr<grpc::Channel> CreateVendorChannel(

    const std::string& target,

    const std::string& local_ip,

    int dscp_value)

{

    grpc::ChannelArguments args;

 

    // A. Handle DSCP via Native gRPC Argument

    if (dscp_value >= 0) {

        args.SetInt(GRPC_ARG_DSCP, dscp_value);

    }

 

    // B. Handle Local IP Binding via Mutator

    if (!local_ip.empty()) {

        auto* mutator = new LocalBindMutator(local_ip);

        args.SetPointer(GRPC_ARG_SOCKET_MUTATOR, mutator);

    }

 

    return grpc::CreateCustomChannel(target,

                                     grpc::InsecureChannelCredentials(),

                                     args);

}


Reply all
Reply to author
Forward
0 new messages