Hi Jon,

(apologies for repeating some of what you already know, but from the top…)

A VRF is virtualisation of a router’s *IP* routing and forwarding. VRFs are 
typically identified by a name (and again typically named to refer to the VPN 
customer they represent). IP packets in VRF RED must be separate from IP 
packets in VRF BLUE. By ‘IP’ in this context we mean IPv4 and IPv6 and unicast 
and multicast (known as sub-address families or SAFIs). To provide this 
separation we therefore need 4 ‘tables’ per-VRF, one for each SAFI. A ‘table’ 
in this context is the well known longest-prefix matching DB. Tables are known 
by a unique per-AFI ID (note per-AFI not per-SAFI, so IPv4 unicast and 
multicast share the same table-id). It is the client’s responsibility to 
associate unique table IDs to tables within all of its VRFs. The client is free 
to choose the table-ID from the full u32 range. So, bottom line, in the context 
of IP forwarding a table (and its associated ID) refer to an instance of a LPM 
DB.

Despite code comments and variable naming, VPP does not maintain the concept of 
a VRF, i.e. it does not maintain a grouping of ‘tables’. At the client 
interface VPP deals only with table IDs – i.e. an identifier that the client 
provided for a given LPM DB. All APIs that claim to accept a VRF index should 
be renamed to accept an IP table ID.
As with all things VPP the allocation of the data-structure that represents the 
LPM-DB comes from a memory pool. This data-structure thus has an associated 
pool index – this is the FIB index. So, there is a one to one mapping between 
the externally visible and client assigned ‘table ID’ and the internal use only 
‘FIB index’. Both are a u32, neither are strictly typed…

With regards to the creation of tables, I’m currently working on the API you 
discovered – ip_table_add_del. With this API the client instructs VPP to 
add/delete a ‘table ID’ (as discussed above). The VPP FIB has the concept of 
ownership or ‘sourcing’ of its resources. Sources can be external (i.e. the CLI 
or the API) or internal (e.g. LISP and DHCP). FIB resources are only completely 
free’d was there are no more sources that are referencing it.
My intention with the table add/delete API is that the client can add the table 
then insert routes and bind interfaces. If the client then deletes the table 
its routes will be purged. The table will then be deleted iff it held the last 
reference. With the introduction of this API VPP will insist that it has been 
called to create the table before any routes or interfaces refer to it.
The current behaviour is that tables can be created either by setting an 
interface into that table, or by setting the ‘create_vrf_if_needed’ flag in a 
route add. There is no means to delete it, hence my new API work.

Hth,
neale


-----Original Message-----
From: <vpp-dev-boun...@lists.fd.io> on behalf of Jon Loeliger <j...@netgate.com>
Date: Monday, 28 August 2017 at 01:36
To: vpp-dev <vpp-dev@lists.fd.io>
Subject: [vpp-dev] Static Route Data API Data Structures

    VPP-ites,
    
    I am delving into the world of static routes.  I am clearly missing
    some basic information and would like some help understanding
    how static routes work.
    
    For starters, I'm a little unclear on what exactly these items are,
    or what they represent or hold, and their relationship to each other:
    
        - VRF index / VRF id
        - Table id
        - FIB index  / FIB id
    
    The only place I can find that even defines "VRF" is on this wiki page:
    
        https://wiki.fd.io/view/VPP/What_is_VPP%3F
    
    (Yeah, the final %3F is needed.)
    
    And even that is in passing:
    
        Some of the functionality that a routing application can create 
includes:
    
           o Virtual Routing and Forwarding (VRF) tables (in the thousands)
    
    
    How is a VRF created/deleted/managed?  I don't see an obvious API call
    that looks like it would create/delete one:
    
    $ git grep -i vrf | grep add_del
    src/plugins/nat/nat64.c:nat64_add_del_pool_addr (ip4_address_t * addr,
    u32 vrf_id, u8 is_add)
    src/plugins/nat/nat64.c:nat64_add_del_prefix (ip6_address_t * prefix,
    u8 plen, u32 vrf_id, u8 is_add)
    src/plugins/nat/nat64.h:int nat64_add_del_pool_addr (ip4_address_t *
    addr, u32 vrf_id, u8 is_add);
    src/plugins/nat/nat64.h:int nat64_add_del_prefix (ip6_address_t *
    prefix, u8 plen, u32 vrf_id,
    src/plugins/nat/nat64_cli.c:      rv = nat64_add_del_pool_addr
    (&this_addr, vrf_id, is_add);
    src/plugins/nat/nat64_cli.c:  rv = nat64_add_del_prefix (&prefix, (u8)
    plen, vrf_id, is_add);
    src/plugins/nat/nat_api.c:      if ((rv = nat64_add_del_pool_addr
    (&this_addr, vrf_id, mp->is_add)))
    src/plugins/nat/nat_api.c:  s = format (0, "SCRIPT:
    nat64_add_del_prefix %U/%u vrf_id %u %s\n",
    src/vat/api_format.c:_(oam_add_del, "src <ip4-address> dst
    <ip4-address> [vrf <n>] [del]")   \
    src/vat/api_format.c:_(one_eid_table_add_del_map, "[del] vni <vni> vrf
    <vrf>")               \
    src/vat/api_format.c:_(lisp_eid_table_add_del_map, "[del] vni <vni>
    vrf <vrf>")              \
    test/test_nat.py:
    self.vapi.nat64_add_del_pool_addr_range(self.vrf1_nat_addr_n,
    test/test_nat.py:
    self.vapi.nat64_add_del_pool_addr_range(self.vrf1_nat_addr_n,
    test/test_nat.py:        self.vapi.nat64_add_del_prefix(vrf1_pref64_n,
    test/vpp_papi_provider.py:    def nat64_add_del_prefix(self, prefix,
    plen, vrf_id=0, is_add=1):
    
    
    Tables, on the other hand, can be created/deleted:
    
        src/vnet/ip/ip.api:autoreply define ip_table_add_del
        src/vnet/ip/ip_api.c:_(IP_TABLE_ADD_DEL, ip_table_add_del)
                              \
        src/vnet/ip/ip_api.c:vl_api_ip_table_add_del_t_handler
    (vl_api_ip_table_add_del_t * mp)
    
    Is this the right "table"?
    
    What is the lifetime management of a table?  When is it OK to delete one?
    Does it have to come into existence before any thing references the Table 
Id?
    Or is it OK to have a dangling Table Id pointer for a while?
    What happens if you use the API to delete it and there are lingering 
referrers?
    
    But let's face it "table" is very generic.  What kind of table is
    that?  And there
    is no better name for it than "table"?   Wait.  Don't answer yet.
    Let's check at
    the API definition first:
    
        /** \brief Add / del table request
                   A table can be added multiple times, but need be
    deleted only once.
            @param client_index - opaque cookie to identify the sender
            @param context - sender context, to match reply w/ request
            @param is_ipv6 - V4 or V6 table
            @param table_id - table ID associated with the route
                             This table ID will apply to both the unicast
                              and mlticast FIBs.
        */
        autoreply define ip_table_add_del
        {
          u32 client_index;
          u32 context;
          u32 table_id;
          u8 is_ipv6;
          u8 is_add;
        };
    
    But still, no clue what the table is, what it manages, what it holds,
    what abstraction
    it provides.  Nothing.
    
    Is it really an arbitrary "Table" of anything you want?  Are these
    used for several (?)
    unrelated items and a generic "Table" is really appropriate?
    
    It appears that a "table id" can sometimes be a FIB table id:
    
        /** \brief IP FIB table response
            @param table_id - IP fib table id
    
    
    But clearly they are not the same:
    
        src/vnet/dhcp/dhcp_proxy.h:     * @brief The FIB index (not the
    external Table-ID) in which the server
        src/vnet/dhcp/dhcp_proxy.h:     * @brief The FIB index (not the
    external Table-ID) in which the client
    
    OK.  Let's turn to some commands for help or insight.
    
    NAT wants VRF ids:
    
        VLIB_CLI_COMMAND (add_address_command, static) = {
          .path = "nat44 add address",
          .short_help = "nat44 add addresses <ip4-range-start> [- 
<ip4-range-end>] "
                    "[tenant-vrf <vrf-id>] [del]",
    
        VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
          .path = "nat44 add static mapping",
          .function = add_static_mapping_command_fn,
          .short_help =
            "nat44 add static mapping local tcp|udp|icmp <addr> [<port>]
    external <addr> [<port>] [vrf <table-id>] [del]",
        };
    
    Ooo!  Look at that penultimate bit:  [vrf <table-id>]
    So.  Is a "table id" the same thing as a "VRF id"?
    
    I find no discussion or description of any of this in any of the wiki,
    nor in the online docs.fd.io,
    nor in the VPP source repo itself.  What am I missing?
    
    Any help?
    
    Thanks,
    jdl
    _______________________________________________
    vpp-dev mailing list
    vpp-dev@lists.fd.io
    https://lists.fd.io/mailman/listinfo/vpp-dev
    

_______________________________________________
vpp-dev mailing list
vpp-dev@lists.fd.io
https://lists.fd.io/mailman/listinfo/vpp-dev

Reply via email to