ConnMan network manager
 help / color / mirror / Atom feed
From: Grant Erickson <gerickson@nuovations.com>
To: connman@lists.linux.dev
Cc: "Böszörményi Zoltán" <zboszor@gmail.com>,
	"Christian Hewitt" <christianshewitt@gmail.com>
Subject: RFC: There Are No Routes for Non-default Services
Date: Wed, 6 Dec 2023 14:19:05 -0800	[thread overview]
Message-ID: <4C194197-1C1D-4FB4-A526-4284D6545A37@nuovations.com> (raw)

There will be a patch series posted following this email; however, for anyone interesting in evaluating and testing this pre-upstreaming, a branch has been posted at:

    https://github.com/Nuovations/connman/tree/user/gerickson/github-issue-5-wip

Hopefully, someone from the list can assist with VPN testing. I’ve made every effort to not break it intentionally; however, there was some overloading of the “active” flag (which I’ve now formalized as one of four states in a lifetime finite state machine) and I’ve “un-overloaded” it such that it behaves as it seems it was originally designed to at the outset of the project. If you are testing VPNs, please note the “Regression caused by 'Don't add route for invalid dst and gateway address combinations'” list thread and commit 9eb1772d31b6 (“Don't add route for invalid dst and gateway address combinations”).

From the ‘@file’ comment in src/connection.c:

This (src/connection.c) implements non-client-facing functionality
for managing network service gateways and routes. It also serves
as a Linux Routing Netlink (rtnl) listener for routing table
additions and deletions in the Linux kernel.

Gateway lifecycle is generally top-down, from user space to
kernel. That is, Connection Manager manages and adds/sets or
gateway routes and then uses notifications from the kernel
Routing Netlink (rtnl) to confirm and "activate" those
routes. Likewise, Connection Manager removes/clears/deletes
gateway routes an then uses notifications from the kernel
Routing Netlink (rtnl) to confirm and "inactivate" those
routes. The following is the state machine for that lifecycle:

                          .----------.    SIOCADDRT /
                          |          |    RTM_NEWROUTE
       .------------------| Inactive |--------------------.
       |                  |          |                    |
       |                  '----------'                    |
       | connman_rtnl                                     |
       | .delgateway                                      |
       |                                                  V
  .---------.         SIOCADDRT / RTM_NEWROUTE        .-------.
  |         |---------------------------------------->|       |
  | Removed |                                         | Added |
  |         |<----------------------------------------|       |
  '---------'         SIOCDELRT / RTM_DELROUTE        '-------'
       ^                                                  |
       | SIOCDELRT /                                      |
       | RTM_DELROUTE                                     |
       |                   .--------.     connman_rtnl    |
       |                   |        |     .newgateway     |
       '-------------------| Active |<--------------------'
                           |        |
                           '--------'

Gateways, and their associated routes, are generally of two types:

  1. High-priority (that is, metric 0) default route.

     This is used by the default service and its underlying
     network interface.

  2. Low-priority (that is, metric > 0) default route.

     This is used by non-default services and their underlying
     network interface.

     For IPv6, these are handled and managed automatically by
     the kernel as part of Router Discovery (RD) Router
     Advertisements (RAs) and because link-local addresses and
     multi-homing are a natural part of IPv6, nothing needs to
     be done here. These routes show up in 'ip -6 route show'
     as:

         default via fe80::f29f:c2ff:fe10:271e dev eth0
             proto ra metric 1024 expires 1622sec hoplimit 64
             pref medium
         default via fe80::f29f:c2ff:fe10:271e dev wlan0
             proto ra metric 1024 expires 1354sec hoplimit 64
             pref medium

     For IPv4, largely invented before the advent of link-local
     addresses and multi-homing hosts, these need to be
     fully-managed here and, with such management, should up in
     'ip -4 route show' as low-priority (that is, high metric
     value) default routes:

         default via 192.168.2.1 dev wlan0 metric 4294967295

     The other alternative to low-priority routes would be to
     use "def1" default routes commonly used by VPNs that have a
     prefix length of 1 (hence the "def1" name). These would
     should up as:

         0.0.0.0/1 via 192.168.2.1 dev wlan0
         128.0.0.0/1 via 192.168.2.1 dev wlan0

     However, since these require twice the number of routing
     table entries and seem no more effective than the
     low-priority route approach, this alternative is not used
     here at present.

VPNs and point-to-point (P2P) links get special treatment but
otherwise utilize the same states and types as described above.

Operationally, down calls from outside this module generally
come from the following three functions:

  1. __connman_connection_gateway_add
  2. __connman_connection_gateway_remove
  3. __connman_connection_update_gateway

and up calls generally come from the following two functions:

  1. connection_newgateway
  2. connection_delgateway

From these five functions above, we are then either attempting
to do the following for a gateway associated with a network
service and its underlying network interface:

  1. Set, or add, the high- or low-priority default route(s).
  2. Unset, or remove, the high- or low-priority default route(s).
  3. Promote the default route from low- to high-priority.
  4. Demote the default route from high- to low-priority.

The call trees for these operations amount to:

  set_default_gateway (1)
    |
    '-mutate_default_gateway
        |
        |-set_ipv4_high_priority_default_gateway
        |   |
        |   '-set_default_gateway_route_common
        |       |
        |       '-set_ipv4_high_priority_default_gateway_route_cb
        |
        '-set_ipv6_high_priority_default_gateway
            |
            '-set_default_gateway_route_common
                |
                '-set_ipv6_high_priority_default_gateway_route_cb

  set_low_priority_default_gateway (1)
    |
    '-mutate_default_gateway
        |
        '-set_ipv4_low_priority_default_gateway
            |
            '-set_default_gateway_route_common
                |
                '-set_ipv4_low_priority_default_gateway_route_cb
                    |
                    '-compute_low_priority_metric

  unset_default_gateway (2)
    |
    '-mutate_default_gateway
        |
        |-unset_ipv4_high_priority_default_gateway
        |   |
        |   '-unset_default_gateway_route_common
        |       |
        |       '-unset_ipv4_high_priority_default_gateway_route_cb
        |
        '-unset_ipv6_high_priority_default_gateway
            |
            '-unset_default_gateway_route_common
                |
                '-unset_ipv6_high_priority_default_gateway_route_cb

  unset_low_priority_default_gateway (2)
    |
    '-mutate_default_gateway
        |
        '-unset_ipv4_low_priority_default_gateway
            |
            '-unset_default_gateway_route_common
                |
                '-unset_ipv4_low_priority_default_gateway_route_cb
                    |
                    '-compute_low_priority_metric

  promote_default_gateway (3)
    |
    |-unset_low_priority_default_gateway (2)
    |
    '-set_default_gateway (1)

  demote_default_gateway (4)
    |
    |-unset_default_gateway (2)
    |
    '-set_low_priority_default_gateway (1)

where:

  * 'mutate_default_gateway' and
    '{un,}set_default_gateway_route_common' are abstract,
    generalized handlers that manage the broad error conditions
    and gateway data and configuration lifecycle management.

  * '*_route_cb' callbacks handle the actual routing table
    manipulation as appropriate for the IP configuration and
    gateway type, largely through the use of gateway
    configuration "ops" to help neutralized differences between
    IPv4 and IPv6.

    In the fullness of time, the use of the gateway
    configuration "ops" should allow further collapsing the IPv4
    and IPv6 cases and simplifying the IP type-specific branches
    of the above call trees.

    The low-priority metric is determined on a per-network
    interface basis and is computed by
    'compute_low_priority_metric'.

Historically, this file started life as "connection.c". However,
today it might be better named "route.c" or, perhaps more
precisely, "gateway.c" since its primary focus is gateway routes
and gateway route management.

Best,

Grant

-- 
Principal
Nuovations

gerickson@nuovations.com
http://www.nuovations.com/


             reply	other threads:[~2023-12-06 22:19 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-06 22:19 Grant Erickson [this message]
2023-12-15  4:51 ` RFC: There Are No Routes for Non-default Services Christian Hewitt
2023-12-15  6:12   ` Grant Erickson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4C194197-1C1D-4FB4-A526-4284D6545A37@nuovations.com \
    --to=gerickson@nuovations.com \
    --cc=christianshewitt@gmail.com \
    --cc=connman@lists.linux.dev \
    --cc=zboszor@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).