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