From b22ba015ef8c42e584876d9ac73df8e2b71b6eaf Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 8 Dec 2017 18:22:26 -0500 Subject: [PATCH] doc: more organizing & updating * Add chapter on BGPD * Add diagram for git workflow * Convert next-hop tracking documents to ReST * Update & organize workflow document * Move ldpd docs back up to the parent directory Signed-off-by: Quentin Young --- doc/developer/bgpd.rst | 8 + doc/developer/conf.py | 6 +- doc/developer/git_branches.png | Bin 0 -> 53216 bytes doc/developer/index.rst | 1 + doc/developer/next-hop-tracking.rst | 352 +++++++++++++++++++ doc/developer/next-hop-tracking.txt | 326 ----------------- doc/developer/workflow.rst | 128 ++++--- doc/{developer => }/ldpd-basic-test-setup.md | 0 8 files changed, 427 insertions(+), 394 deletions(-) create mode 100644 doc/developer/bgpd.rst create mode 100644 doc/developer/git_branches.png create mode 100644 doc/developer/next-hop-tracking.rst delete mode 100644 doc/developer/next-hop-tracking.txt rename doc/{developer => }/ldpd-basic-test-setup.md (100%) diff --git a/doc/developer/bgpd.rst b/doc/developer/bgpd.rst new file mode 100644 index 0000000000..053c0779de --- /dev/null +++ b/doc/developer/bgpd.rst @@ -0,0 +1,8 @@ +BGPD +========================= + +.. toctree:: + :maxdepth: 2 + + next-hop-tracking + diff --git a/doc/developer/conf.py b/doc/developer/conf.py index 6c39c6e26d..233056666d 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -231,7 +231,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'FRR.tex', u'FRR Developer\'s Documentation', + (master_doc, 'FRR.tex', u'FRR Developer\'s Manual', u'FRR', 'manual'), ] @@ -261,7 +261,7 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'frr', u'FRR Developer\'s Documentation', + (master_doc, 'frr', u'FRR Developer\'s Manual', [author], 1) ] @@ -275,7 +275,7 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'FRR', u'FRR Developer\'s Documentation', + (master_doc, 'FRR', u'FRR Developer\'s Manual', author, 'FRR', 'One line description of project.', 'Miscellaneous'), ] diff --git a/doc/developer/git_branches.png b/doc/developer/git_branches.png new file mode 100644 index 0000000000000000000000000000000000000000..21001c30a114a1af04727c5fc3ddb20a3187039b GIT binary patch literal 53216 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 Jjqdo&{{gTM17rXI literal 0 HcmV?d00001 diff --git a/doc/developer/index.rst b/doc/developer/index.rst index 6f0dbebdfd..f1a39d2828 100644 --- a/doc/developer/index.rst +++ b/doc/developer/index.rst @@ -6,5 +6,6 @@ Welcome to FRR's documentation! workflow library + bgpd building diff --git a/doc/developer/next-hop-tracking.rst b/doc/developer/next-hop-tracking.rst new file mode 100644 index 0000000000..1d65956f8c --- /dev/null +++ b/doc/developer/next-hop-tracking.rst @@ -0,0 +1,352 @@ +Next Hop Tracking +================== + +Next hop tracking is an optimization feature that reduces the processing time +involved in the BGP bestpath algorithm by monitoring changes to the routing +table. + +Background +----------- + +Recursive routes are of the form: + +:: + + p/m --> n + [Ex: 1.1.0.0/16 --> 2.2.2.2] + +where 'n' itself is resolved through another route as follows: + +:: + + p2/m --> h, interface + [Ex: 2.2.2.0/24 --> 3.3.3.3, eth0] + +Usually, BGP routes are recursive in nature and BGP nexthops get resolved +through an IGP route. IGP usually adds its routes pointing to an interface +(these are called non-recursive routes). + +When BGP receives a recursive route from a peer, it needs to validate the +nexthop. The path is marked valid or invalid based on the reachability status +of the nexthop. Nexthop validation is also important for BGP decision process +as the metric to reach the nexthop is a parameter to best path selection +process. + +As it goes with routing, this is a dynamic process. Route to the nexthop can +change. The nexthop can become unreachable or reachable. In the current BGP +implementation, the nexthop validation is done periodically in the scanner run. +The default scanner run interval is one minute. Every minute, the scanner task +walks the entire BGP table. It checks the validity of each nexthop with Zebra +(the routing table manager) through a request and response message exchange +between BGP and Zebra process. BGP process is blocked for that duration. The +mechanism has two major drawbacks: + +- The scanner task runs to completion. That can potentially starve the other + tasks for long periods of time, based on the BGP table size and number of + nexthops. + +- Convergence around routing changes that affect the nexthops can be long + (around a minute with the default intervals). The interval can be shortened + to achieve faster reaction time, but it makes the first problem worse, with + the scanner task consuming most of the CPU resources. + +The next-hop tracking feature makes this process event-driven. It eliminates +periodic nexthop validation and introduces an asynchronous communication path +between BGP and Zebra for route change notifications that can then be acted +upon. + +Goal +---- + +Stating the obvious, the main goal is to remove the two limitations we +discussed in the previous section. The goals, in a constructive tone, +are the following: + +- **Fairness**: the scanner run should not consume an unjustly high amount of + CPU time. This should give an overall good performance and response time to + other events (route changes, session events, IO/user interface). + +- **Convergence**: BGP must react to nexthop changes instantly and provide + sub-second convergence. This may involve diverting the routes from one + nexthop to another. + +Overview of changes +------------------------ + +The changes are in both BGP and Zebra modules. The short summary is +the following: + +- Zebra implements a registration mechanism by which clients can + register for next hop notification. Consequently, it maintains a + separate table, per (VRF, AF) pair, of next hops and interested + client-list per next hop. + +- When the main routing table changes in Zebra, it evaluates the next + hop table: for each next hop, it checks if the route table + modifications have changed its state. If so, it notifies the + interested clients. + +- BGP is one such client. It registers the next hops corresponding to + all of its received routes/paths. It also threads the paths against + each nexthop structure. + +- When BGP receives a next hop notification from Zebra, it walks the + corresponding path list. It makes them valid or invalid depending + on the next hop notification. It then re-computes best path for the + corresponding destination. This may result in re-announcing those + destinations to peers. + +Design +------ + +Modules +~~~~~~~ + +The core design introduces an "nht" (next hop tracking) module in BGP +and "rnh" (recursive nexthop) module in Zebra. The "nht" module +provides the following APIs: + ++----------------------------+--------------------------------------------------+ +| Function | Action | ++============================+==================================================+ +| bgp_find_or_add_nexthop() | find or add a nexthop in BGP nexthop table | ++----------------------------+--------------------------------------------------+ +| bgp_find_nexthop() | find a nexthop in BGP nexthop table | ++----------------------------+--------------------------------------------------+ +| bgp_parse_nexthop_update() | parse a nexthop update message coming from zebra | ++----------------------------+--------------------------------------------------+ + +The "rnh" module provides the following APIs: + ++----------------------------+----------------------------------------------------------------------------------------------------------+ +| Function | Action | ++============================+==========================================================================================================+ +| zebra_add_rnh() | add a recursive nexthop | ++----------------------------+----------------------------------------------------------------------------------------------------------+ +| zebra_delete_rnh() | delete a recursive nexthop | ++----------------------------+----------------------------------------------------------------------------------------------------------+ +| zebra_lookup_rnh() | lookup a recursive nexthop | ++----------------------------+----------------------------------------------------------------------------------------------------------+ +| zebra_add_rnh_client() | register a client for nexthop notifications against a recursive nexthop | ++----------------------------+----------------------------------------------------------------------------------------------------------+ +| zebra_remove_rnh_client() | remove the client registration for a recursive nexthop | ++----------------------------+----------------------------------------------------------------------------------------------------------+ +| zebra_evaluate_rnh_table() | (re)evaluate the recursive nexthop table (most probably because the main routing table has changed). | ++----------------------------+----------------------------------------------------------------------------------------------------------+ +| zebra_cleanup_rnh_client() | Cleanup a client from the "rnh" module data structures (most probably because the client is going away). | ++----------------------------+----------------------------------------------------------------------------------------------------------+ + +4.2. Control flow + +The next hop registration control flow is the following: + +:: + + <==== BGP Process ====>|<==== Zebra Process ====> + | + receive module nht module | zserv module rnh module + ---------------------------------------------------------------------- + | | | + bgp_update_ | | | + main() | bgp_find_or_add_ | | + | nexthop() | | + | | | + | | zserv_nexthop_ | + | | register() | + | | | zebra_add_rnh() + | | | + + +The next hop notification control flow is the following: + +:: + + <==== Zebra Process ====>|<==== BGP Process ====> + | + rib module rnh module | zebra module nht module + ---------------------------------------------------------------------- + | | | + meta_queue_ | | | + process() | zebra_evaluate_ | | + | rnh_table() | | + | | | + | | bgp_read_nexthop_ | + | | update() | + | | | bgp_parse_ + | | | nexthop_update() + | | | + + +zclient message format +~~~~~~~~~~~~~~~~~~~~~~ + +ZEBRA_NEXTHOP_REGISTER and ZEBRA_NEXTHOP_UNREGISTER messages are +encoded in the following way: + +:: + + . 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | AF | prefix len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . Nexthop prefix . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | AF | prefix len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . Nexthop prefix . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +``ZEBRA_NEXTHOP_UPDATE`` message is encoded as follows: + +:: + + . 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | AF | prefix len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . Nexthop prefix getting resolved . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | metric | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | #nexthops | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | nexthop type | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . resolving Nexthop details . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | nexthop type | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . resolving Nexthop details . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +BGP data structure +~~~~~~~~~~~~~~~~~~ +Legend: + +:: + + /\ struct bgp_node: a BGP destination/route/prefix + \/ + + [ ] struct bgp_info: a BGP path (e.g. route received from a peer) + + _ + (_) struct bgp_nexthop_cache: a BGP nexthop + + /\ NULL + \/--+ ^ + | : + +--[ ]--[ ]--[ ]--> NULL + /\ : + \/--+ : + | : + +--[ ]--[ ]--> NULL + : + _ : + (_)........... + + +Zebra data structure +~~~~~~~~~~~~~~~~~~~~ + +RNH table:: + + O + / \ + O O + / \ + O O + + struct rnh + { + u_char flags; + struct route_entry *state; + struct list *client_list; + struct route_node *node; + }; + +User interface changes +~~~~~~~~~~~~~~~~~~~~~~ + +:: + + frr# show ip nht + 3.3.3.3 + resolved via kernel + via 11.0.0.6, swp1 + Client list: bgp(fd 12) + 11.0.0.10 + resolved via connected + is directly connected, swp2 + Client list: bgp(fd 12) + 11.0.0.18 + resolved via connected + is directly connected, swp4 + Client list: bgp(fd 12) + 11.11.11.11 + resolved via kernel + via 10.0.1.2, eth0 + Client list: bgp(fd 12) + + frr# show ip bgp nexthop + Current BGP nexthop cache: + 3.3.3.3 valid [IGP metric 0], #paths 3 + Last update: Wed Oct 16 04:43:49 2013 + + 11.0.0.10 valid [IGP metric 1], #paths 1 + Last update: Wed Oct 16 04:43:51 2013 + + 11.0.0.18 valid [IGP metric 1], #paths 2 + Last update: Wed Oct 16 04:43:47 2013 + + 11.11.11.11 valid [IGP metric 0], #paths 1 + Last update: Wed Oct 16 04:43:47 2013 + + frr# show ipv6 nht + frr# show ip bgp nexthop detail + + frr# debug bgp nht + frr# debug zebra nht + + 6. Sample test cases + + r2----r3 + / \ / + r1----r4 + + - Verify that a change in IGP cost triggers NHT + + shutdown the r1-r4 and r2-r4 links + + no shut the r1-r4 and r2-r4 links and wait for OSPF to come back + up + + We should be back to the original nexthop via r4 now + - Verify that a NH becoming unreachable triggers NHT + + Shutdown all links to r4 + - Verify that a NH becoming reachable triggers NHT + + no shut all links to r4 + +Future work +~~~~~~~~~~~ + +- route-policy for next hop validation (e.g. ignore default route) +- damping for rapid next hop changes +- prioritized handling of nexthop changes ((un)reachability vs. metric + changes) +- handling recursion loop, e.g:: + + 11.11.11.11/32 -> 12.12.12.12 + 12.12.12.12/32 -> 11.11.11.11 + 11.0.0.0/8 -> +- better statistics diff --git a/doc/developer/next-hop-tracking.txt b/doc/developer/next-hop-tracking.txt deleted file mode 100644 index 12ed63947b..0000000000 --- a/doc/developer/next-hop-tracking.txt +++ /dev/null @@ -1,326 +0,0 @@ -0. Introduction - -This is the design specification for next hop tracking feature in -Frr. - -1. Background - -Recursive routes are of the form: - - p/m --> n - [Ex: 1.1.0.0/16 --> 2.2.2.2] - -where 'n' itself is resolved through another route as follows: - - p2/m --> h, interface - [Ex: 2.2.2.0/24 --> 3.3.3.3, eth0] - -Usually, BGP routes are recursive in nature and BGP nexthops get -resolved through an IGP route. IGP usually adds its routes pointing to -an interface (these are called non-recursive routes). - -When BGP receives a recursive route from a peer, it needs to validate -the nexthop. The path is marked valid or invalid based on the -reachability status of the nexthop. Nexthop validation is also -important for BGP decision process as the metric to reach the nexthop -is a parameter to best path selection process. - -As it goes with routing, this is a dynamic process. Route to the -nexthop can change. The nexthop can become unreachable or -reachable. In the current BGP implementation, the nexthop validation -is done periodically in the scanner run. The default scanner run -interval is one minute. Every minute, the scanner task walks the -entire BGP table. It checks the validity of each nexthop with Zebra -(the routing table manager) through a request and response message -exchange between BGP and Zebra process. BGP process is blocked for -that duration. The mechanism has two major drawbacks: - -(1) The scanner task runs to completion. That can potentially starve - the other tasks for long periods of time, based on the BGP table - size and number of nexthops. - -(2) Convergence around routing changes that affect the nexthops can be - long (around a minute with the default intervals). The interval - can be shortened to achieve faster reaction time, but it makes the - first problem worse, with the scanner task consuming most of the - CPU resources. - -"Next hop tracking" feature makes this process event-driven. It -eliminates periodic nexthop validation and introduces an asynchronous -communication path between BGP and Zebra for route change notifications -that can then be acted upon. - -2. Goal - -Stating the obvious, the main goal is to remove the two limitations we -discussed in the previous section. The goals, in a constructive tone, -are the following: - -- fairness: the scanner run should not consume an unjustly high amount - of CPU time. This should give an overall good performance and - response time to other events (route changes, session events, - IO/user interface). - -- convergence: BGP must react to nexthop changes instantly and provide - sub-second convergence. This may involve diverting the routes from - one nexthop to another. - -3. Overview of the changes - -The changes are in both BGP and Zebra modules. The short summary is -the following: - -- Zebra implements a registration mechanism by which clients can - register for next hop notification. Consequently, it maintains a - separate table, per (VRF, AF) pair, of next hops and interested - client-list per next hop. - -- When the main routing table changes in Zebra, it evaluates the next - hop table: for each next hop, it checks if the route table - modifications have changed its state. If so, it notifies the - interested clients. - -- BGP is one such client. It registers the next hops corresponding to - all of its received routes/paths. It also threads the paths against - each nexthop structure. - -- When BGP receives a next hop notification from Zebra, it walks the - corresponding path list. It makes them valid or invalid depending - on the next hop notification. It then re-computes best path for the - corresponding destination. This may result in re-announcing those - destinations to peers. - -4. Design - -4.1. Modules - -The core design introduces an "nht" (next hop tracking) module in BGP -and "rnh" (recursive nexthop) module in Zebra. The "nht" module -provides the following APIs: - -bgp_find_or_add_nexthop() : find or add a nexthop in BGP nexthop table -bgp_find_nexthop() : find a nexthop in BGP nexthop table -bgp_parse_nexthop_update() : parse a nexthop update message coming - from zebra - -The "rnh" module provides the following APIs: - -zebra_add_rnh() : add a recursive nexthop -zebra_delete_rnh() : delete a recursive nexthop -zebra_lookup_rnh() : lookup a recursive nexthop - -zebra_add_rnh_client() : register a client for nexthop notifications - against a recursive nexthop - -zebra_remove_rnh_client(): remove the client registration for a - recursive nexthop - -zebra_evaluate_rnh_table(): (re)evaluate the recursive nexthop table - (most probably because the main routing - table has changed). - -zebra_cleanup_rnh_client(): Cleanup a client from the "rnh" module - data structures (most probably because the - client is going away). - -4.2. Control flow - -The next hop registration control flow is the following: - -<==== BGP Process ====>|<==== Zebra Process ====> - | -receive module nht module | zserv module rnh module ----------------------------------------------------------------------- - | | | -bgp_update_ | | | - main() | bgp_find_or_add_ | | - | nexthop() | | - | | | - | | zserv_nexthop_ | - | | register() | - | | | zebra_add_rnh() - | | | - - -The next hop notification control flow is the following: - -<==== Zebra Process ====>|<==== BGP Process ====> - | -rib module rnh module | zebra module nht module ----------------------------------------------------------------------- - | | | -meta_queue_ | | | - process() | zebra_evaluate_ | | - | rnh_table() | | - | | | - | | bgp_read_nexthop_ | - | | update() | - | | | bgp_parse_ - | | | nexthop_update() - | | | - - -4.3. zclient message format - -ZEBRA_NEXTHOP_REGISTER and ZEBRA_NEXTHOP_UNREGISTER messages are -encoded in the following way: - -/* - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | AF | prefix len | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . Nexthop prefix . - * . . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . . - * . . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | AF | prefix len | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . Nexthop prefix . - * . . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -ZEBRA_NEXTHOP_UPDATE message is encoded as follows: - -/* - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | AF | prefix len | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . Nexthop prefix getting resolved . - * . . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | metric | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | #nexthops | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | nexthop type | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . resolving Nexthop details . - * . . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | nexthop type | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . resolving Nexthop details . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -4.4. BGP data structure - -Legend: - -/\ struct bgp_node: a BGP destination/route/prefix -\/ - -[ ] struct bgp_info: a BGP path (e.g. route received from a peer) - - _ -(_) struct bgp_nexthop_cache: a BGP nexthop - - - - /\ NULL - \/--+ ^ - | : - +--[ ]--[ ]--[ ]--> NULL - /\ : - \/--+ : - | : - +--[ ]--[ ]--> NULL - : - _ : - (_)............. - - -4.5. Zebra data structure - -rnh table: - - O - / \ - O O - / \ - O O - - struct rnh - { - u_char flags; - struct route_entry *state; - struct list *client_list; - struct route_node *node; - }; - -5. User interface changes - -frr# show ip nht -3.3.3.3 - resolved via kernel - via 11.0.0.6, swp1 - Client list: bgp(fd 12) -11.0.0.10 - resolved via connected - is directly connected, swp2 - Client list: bgp(fd 12) -11.0.0.18 - resolved via connected - is directly connected, swp4 - Client list: bgp(fd 12) -11.11.11.11 - resolved via kernel - via 10.0.1.2, eth0 - Client list: bgp(fd 12) - -frr# show ip bgp nexthop -Current BGP nexthop cache: - 3.3.3.3 valid [IGP metric 0], #paths 3 - Last update: Wed Oct 16 04:43:49 2013 - - 11.0.0.10 valid [IGP metric 1], #paths 1 - Last update: Wed Oct 16 04:43:51 2013 - - 11.0.0.18 valid [IGP metric 1], #paths 2 - Last update: Wed Oct 16 04:43:47 2013 - - 11.11.11.11 valid [IGP metric 0], #paths 1 - Last update: Wed Oct 16 04:43:47 2013 - -frr# show ipv6 nht -frr# show ip bgp nexthop detail - -frr# debug bgp nht -frr# debug zebra nht - -6. Sample test cases - - r2----r3 - / \ / - r1----r4 - -- Verify that a change in IGP cost triggers NHT - + shutdown the r1-r4 and r2-r4 links - + no shut the r1-r4 and r2-r4 links and wait for OSPF to come back - up - + We should be back to the original nexthop via r4 now -- Verify that a NH becoming unreachable triggers NHT - + Shutdown all links to r4 -- Verify that a NH becoming reachable triggers NHT - + no shut all links to r4 - -7. Future work - -- route-policy for next hop validation (e.g. ignore default route) -- damping for rapid next hop changes -- prioritized handling of nexthop changes ((un)reachability vs. metric - changes) -- handling recursion loop, e.g. - 11.11.11.11/32 -> 12.12.12.12 - 12.12.12.12/32 -> 11.11.11.11 - 11.0.0.0/8 -> -- better statistics diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 38cf0b878d..4ab70ac3c5 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -1,67 +1,52 @@ -Developing for FRRouting +Process & Workflow ======================== -General note on this document ------------------------------ - -This document is "descriptive/post-factual" in that it documents -pratices that are in use; it is not "definitive/pre-factual" in -prescribing practices. +FRR is a large project developed by many different groups. This section +documents standards for code style & quality, commit messages, pull requests +and best practices that all contributors are asked to follow. -This means that when a procedure changes, it is agreed upon, then put -into practice, and then documented here. If this document doesn't match -reality, it's the document that needs to be updated, not reality. +This section is "descriptive/post-factual" in that it documents pratices that +are in use; it is not "definitive/pre-factual" in prescribing practices. This +means that when a procedure changes, it is agreed upon, then put into practice, +and then documented here. If this document doesn't match reality, it's the +document that needs to be updated, not reality. Git Structure ------------- -The master Git for FRRouting resides on Github at -`https://github.com/frrouting/frr `__ - -.. figure:: git_branches.svg - :alt: git branches continually merging to the left from 3 lanes; - float-right - - git branches continually merging to the left from 3 lanes; - float-right +The master Git for FRR resides on `Github +`__. -There is one main branch for development and a release branch for each -major release. +.. figure:: git_branches.png -New contributions are done against the head of the master branch. The CI -systems will pick up the Github Pull Requests or the new patch from -Patchwork, run some basic build and functional tests. - -For each major release (1.0, 1.1 etc) a new release branch is created -based on the master. - -There was an attempt to use a "develop" branch automatically maintained -by the CI system. This is not currently in active use, though the system -is operational. If the "develop" branch is in active use and this -paragraph is still here, this document obviously wasn't updated. +There is one main branch for development, ``master``. For each major release +(2.0, 3.0 etc) a new release branch is created based on the master. Subsequent +point releases based on a major branch are marked by tagging. Programming language, Tools and Libraries ----------------------------------------- -The core of FRRouting is written in C (gcc or clang supported) and makes +The core of FRR is written in C (gcc or clang supported) and makes use of GNU compiler extensions. A few non-essential scripts are -implemented in Perl and Python. FRRouting requires the following tools +implemented in Perl and Python. FRR requires the following tools to build distribution packages: automake, autoconf, texinfo, libtool and gawk and various libraries (i.e. libpam and libjson-c). If your contribution requires a new library or other tool, then please highlight this in your description of the change. Also make sure it’s -supported by all FRRouting platform OSes or provide a way to build +supported by all FRR platform OSes or provide a way to build without the library (potentially without the new feature) on the other platforms. -Documentation should be written in Tex (.texi) or Markdown (.md) format -with a preference for Markdown. +Documentation should be written in reStructuredText. Sphinx extensions may be +utilized but pure ReST is preferred where possible. See `Documentation +<#documentation>`__. Mailing lists ------------- -Italicized lists are private. +The FRR development group maintains multiple mailing lists for use by the +community. Italicized lists are private. +----------------------------------+--------------------------------+ | Topic | List | @@ -80,19 +65,31 @@ Italicized lists are private. Changelog ~~~~~~~~~ -The changelog will be the base for the release notes. A changelog entry -for your changes is usually not required and will be added based on your -commit messages by the maintainers. However, you are free to include an -update to the changelog with some better description. The changelog will -be the base for the release notes. +The changelog will be the base for the release notes. A changelog entry for +your changes is usually not required and will be added based on your commit +messages by the maintainers. However, you are free to include an update to the +changelog with some better description. Submitting Patches and Enhancements ----------------------------------- +FRR accepts patches from two sources: + +- Email (git format-patch) +- Github pull request + +Contributors are highly encouraged to use Github's fork-and-pr workflow. It is +easier for us to review it, test it, try it and discuss it on Github than it is +via email, thus your patch will get more attention more quickly on Github. + +The base branch for new contributions and non-critical bug fixes should be +``master``. Please ensure your pull request is based on this branch when you +submit it. + Pre-submission Checklist ~~~~~~~~~~~~~~~~~~~~~~~~ -- Format code (see `Developer's Guidelines <#developers-guidelines>`__) +- Format code (see `Code Formatting <#developers-guidelines>`__) - Verify and acknowledge license (see `License for contributions <#license-for-contributions>`__) - Ensure you have properly signed off (see `Signing @@ -115,14 +112,14 @@ Pre-submission Checklist License for contributions ~~~~~~~~~~~~~~~~~~~~~~~~~ -FRRouting is under a “GPLv2 or later” license. Any code submitted must +FRR is under a “GPLv2 or later” license. Any code submitted must be released under the same license (preferred) or any license which allows redistribution under this GPLv2 license (eg MIT License). Signing Off ~~~~~~~~~~~ -Code submitted to FRRouting must be signed off. We have the same +Code submitted to FRR must be signed off. We have the same requirements for using the signed-off-by process as the Linux kernel. In short, you must include a signed-off-by tag in every patch. @@ -142,6 +139,8 @@ to be a helpful resource. In short, when you sign off on a commit, you assert your agreement to all of the following: +:: + Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: @@ -171,7 +170,7 @@ What do I submit my changes against? We've documented where we would like to have the different fixes applied at -https://github.com/FRRouting/frr/wiki/Where-Do-I-create-a-Pull-Request-against%3F +https://github.com/FRR/frr/wiki/Where-Do-I-create-a-Pull-Request-against%3F If you are unsure where your submission goes, look at that document or ask a project maintainer. @@ -219,12 +218,9 @@ After submitting your changes - You should automatically receive an email with the test results within less than 2 hrs of the submission. If you don’t get the - email, then check status on the github pull request (if submitted - by pull request) or on Patchwork at - https://patchwork.frrouting.org (if submitted as patch to mailing - list). + email, then check status on the Github pull request. - Please notify the development mailing list if you think something - doesn’t work. + doesn't work. - If the tests failed: @@ -253,8 +249,8 @@ After submitting your changes community members. - Your submission is done once it is merged to the master branch. -Developer's Guidelines ----------------------- +Coding Practices & Style +------------------------ Commit messages ~~~~~~~~~~~~~~~ @@ -392,13 +388,12 @@ BSD coding style applies to: Documentation ~~~~~~~~~~~~~ -FRRouting is a large and complex software project developed by many -different people over a long period of time. Without adequate -documentation, it can be exceedingly difficult to understand code -segments, APIs and other interfaces. In the interest of keeping the -project healthy and maintainable, you should make every effort to -document your code so that other people can understand what it does -without needing to closely read the code itself. +FRR is a large and complex software project developed by many different people +over a long period of time. Without adequate documentation, it can be +exceedingly difficult to understand code segments, APIs and other interfaces. +In the interest of keeping the project healthy and maintainable, you should +make every effort to document your code so that other people can understand +what it does without needing to closely read the code itself. Some specific guidelines that contributors should follow are: @@ -440,10 +435,13 @@ used for. - **For new code in ``lib/``, these guidelines are hard requirements.** If you are contributing code that adds significant user-visible -functionality or introduces a new API, please document it in ``doc/``. -Markdown and LaTeX are acceptable formats, although Markdown is -currently preferred for new documentation. This may change in the near -future. +functionality please document it in ``doc/``. If you make significant changes +to portions of the codebase covered in the Developer's Manual, please +update the relevant sections. If you add a major feature or introduce a new +API, please document the architecture and API to the best of your abilities in +the Developer's Manual. + +Documentation should be in reStructuredText. Finally, if you come across some code that is undocumented and feel like going above and beyond, document it! We absolutely appreciate and accept diff --git a/doc/developer/ldpd-basic-test-setup.md b/doc/ldpd-basic-test-setup.md similarity index 100% rename from doc/developer/ldpd-basic-test-setup.md rename to doc/ldpd-basic-test-setup.md -- 2.39.5