|
| 1 | + |
| 2 | + zebra: Add kernel level graceful restart |
| 3 | + |
| 4 | + <Initial Code from Praveen Chaudhary> |
| 5 | + |
| 6 | + Add the a `--graceful_restart X` flag to zebra start that |
| 7 | + now creates a timer that pops in X seconds and will go |
| 8 | + through and remove all routes that are older than startup. |
| 9 | + |
| 10 | + If graceful_restart is not specified then we will just pop |
| 11 | + a timer that cleans everything up immediately. |
| 12 | + |
| 13 | + Signed-off-by: Praveen Chaudhary < [email protected]> |
| 14 | + Signed-off-by: Donald Sharp < [email protected]> |
| 15 | + |
| 16 | +diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst |
| 17 | +index f38db9d24..40d894929 100644 |
| 18 | +--- a/doc/user/zebra.rst |
| 19 | ++++ b/doc/user/zebra.rst |
| 20 | +@@ -23,9 +23,12 @@ Besides the common invocation options (:ref:`common-invocation-options`), the |
| 21 | + Runs in batch mode. *zebra* parses configuration file and terminates |
| 22 | + immediately. |
| 23 | + |
| 24 | +-.. option:: -k, --keep_kernel |
| 25 | ++.. option:: -K TIME, --graceful_restart TIME |
| 26 | + |
| 27 | +- When zebra starts up, don't delete old self inserted routes. |
| 28 | ++ If this option is specified, the graceful restart time is TIME seconds. |
| 29 | ++ Zebra, when started, will read in routes. Those routes that Zebra |
| 30 | ++ identifies that it was the originator of will be swept in TIME seconds. |
| 31 | ++ If no time is specified then we will sweep those routes immediately. |
| 32 | + |
| 33 | + .. option:: -r, --retain |
| 34 | + |
| 35 | +diff --git a/zebra/main.c b/zebra/main.c |
| 36 | +index 184e798bd..3d1d156ad 100644 |
| 37 | +--- a/zebra/main.c |
| 38 | ++++ b/zebra/main.c |
| 39 | +@@ -74,8 +74,7 @@ int retain_mode = 0; |
| 40 | + /* Allow non-quagga entities to delete quagga routes */ |
| 41 | + int allow_delete = 0; |
| 42 | + |
| 43 | +-/* Don't delete kernel route. */ |
| 44 | +-int keep_kernel_mode = 0; |
| 45 | ++int graceful_restart; |
| 46 | + |
| 47 | + bool v6_rr_semantics = false; |
| 48 | + |
| 49 | +@@ -89,12 +88,12 @@ uint32_t nl_rcvbufsize = 4194304; |
| 50 | + struct option longopts[] = { |
| 51 | + {"batch", no_argument, NULL, 'b'}, |
| 52 | + {"allow_delete", no_argument, NULL, 'a'}, |
| 53 | +- {"keep_kernel", no_argument, NULL, 'k'}, |
| 54 | + {"socket", required_argument, NULL, 'z'}, |
| 55 | + {"ecmp", required_argument, NULL, 'e'}, |
| 56 | + {"label_socket", no_argument, NULL, 'l'}, |
| 57 | + {"retain", no_argument, NULL, 'r'}, |
| 58 | + {"vrfdefaultname", required_argument, NULL, 'o'}, |
| 59 | ++ {"graceful_restart", required_argument, NULL, 'K'}, |
| 60 | + #ifdef HAVE_NETLINK |
| 61 | + {"vrfwnetns", no_argument, NULL, 'n'}, |
| 62 | + {"nl-bufsize", required_argument, NULL, 's'}, |
| 63 | +@@ -264,13 +263,14 @@ int main(int argc, char **argv) |
| 64 | + char *netlink_fuzzing = NULL; |
| 65 | + #endif /* HANDLE_NETLINK_FUZZING */ |
| 66 | + |
| 67 | ++ graceful_restart = 0; |
| 68 | + vrf_configure_backend(VRF_BACKEND_VRF_LITE); |
| 69 | + logicalrouter_configure_backend(LOGICALROUTER_BACKEND_NETNS); |
| 70 | + |
| 71 | + frr_preinit(&zebra_di, argc, argv); |
| 72 | + |
| 73 | + frr_opt_add( |
| 74 | +- "bakz:e:l:o:r" |
| 75 | ++ "baz:e:l:o:rK:" |
| 76 | + #ifdef HAVE_NETLINK |
| 77 | + "s:n" |
| 78 | + #endif |
| 79 | +@@ -282,24 +282,24 @@ int main(int argc, char **argv) |
| 80 | + #endif /* HANDLE_NETLINK_FUZZING */ |
| 81 | + , |
| 82 | + longopts, |
| 83 | +- " -b, --batch Runs in batch mode\n" |
| 84 | +- " -a, --allow_delete Allow other processes to delete zebra routes\n" |
| 85 | +- " -z, --socket Set path of zebra socket\n" |
| 86 | +- " -e, --ecmp Specify ECMP to use.\n" |
| 87 | +- " -l, --label_socket Socket to external label manager\n" |
| 88 | +- " -k, --keep_kernel Don't delete old routes which were installed by zebra.\n" |
| 89 | +- " -r, --retain When program terminates, retain added route by zebra.\n" |
| 90 | +- " -o, --vrfdefaultname Set default VRF name.\n" |
| 91 | ++ " -b, --batch Runs in batch mode\n" |
| 92 | ++ " -a, --allow_delete Allow other processes to delete zebra routes\n" |
| 93 | ++ " -z, --socket Set path of zebra socket\n" |
| 94 | ++ " -e, --ecmp Specify ECMP to use.\n" |
| 95 | ++ " -l, --label_socket Socket to external label manager\n" |
| 96 | ++ " -r, --retain When program terminates, retain added route by zebra.\n" |
| 97 | ++ " -o, --vrfdefaultname Set default VRF name.\n" |
| 98 | ++ " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" |
| 99 | + #ifdef HAVE_NETLINK |
| 100 | +- " -n, --vrfwnetns Use NetNS as VRF backend\n" |
| 101 | +- " -s, --nl-bufsize Set netlink receive buffer size\n" |
| 102 | +- " --v6-rr-semantics Use v6 RR semantics\n" |
| 103 | ++ " -n, --vrfwnetns Use NetNS as VRF backend\n" |
| 104 | ++ " -s, --nl-bufsize Set netlink receive buffer size\n" |
| 105 | ++ " --v6-rr-semantics Use v6 RR semantics\n" |
| 106 | + #endif /* HAVE_NETLINK */ |
| 107 | + #if defined(HANDLE_ZAPI_FUZZING) |
| 108 | +- " -c <file> Bypass normal startup and use this file for testing of zapi\n" |
| 109 | ++ " -c <file> Bypass normal startup and use this file for testing of zapi\n" |
| 110 | + #endif /* HANDLE_ZAPI_FUZZING */ |
| 111 | + #if defined(HANDLE_NETLINK_FUZZING) |
| 112 | +- " -w <file> Bypass normal startup and use this file for testing of netlink input\n" |
| 113 | ++ " -w <file> Bypass normal startup and use this file for testing of netlink input\n" |
| 114 | + #endif /* HANDLE_NETLINK_FUZZING */ |
| 115 | + ); |
| 116 | + |
| 117 | +@@ -318,9 +318,6 @@ int main(int argc, char **argv) |
| 118 | + case 'a': |
| 119 | + allow_delete = 1; |
| 120 | + break; |
| 121 | +- case 'k': |
| 122 | +- keep_kernel_mode = 1; |
| 123 | +- break; |
| 124 | + case 'e': |
| 125 | + multipath_num = atoi(optarg); |
| 126 | + if (multipath_num > MULTIPATH_NUM |
| 127 | +@@ -350,6 +347,9 @@ int main(int argc, char **argv) |
| 128 | + case 'r': |
| 129 | + retain_mode = 1; |
| 130 | + break; |
| 131 | ++ case 'K': |
| 132 | ++ graceful_restart = atoi(optarg); |
| 133 | ++ break; |
| 134 | + #ifdef HAVE_NETLINK |
| 135 | + case 's': |
| 136 | + nl_rcvbufsize = atoi(optarg); |
| 137 | +@@ -437,9 +437,9 @@ int main(int argc, char **argv) |
| 138 | + * will be equal to the current getpid(). To know about such routes, |
| 139 | + * we have to have route_read() called before. |
| 140 | + */ |
| 141 | +- if (!keep_kernel_mode) |
| 142 | +- rib_sweep_route(); |
| 143 | +- |
| 144 | ++ zrouter.startup_time = monotime(NULL); |
| 145 | ++ thread_add_timer(zrouter.master, rib_sweep_route, |
| 146 | ++ NULL, graceful_restart, NULL); |
| 147 | + /* Needed for BSD routing socket. */ |
| 148 | + pid = getpid(); |
| 149 | + |
| 150 | +diff --git a/zebra/rib.h b/zebra/rib.h |
| 151 | +index 9fe42aef3..69850f3a0 100644 |
| 152 | +--- a/zebra/rib.h |
| 153 | ++++ b/zebra/rib.h |
| 154 | +@@ -351,7 +351,7 @@ extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, |
| 155 | + extern void rib_update(vrf_id_t vrf_id, rib_update_event_t event); |
| 156 | + extern void rib_update_table(struct route_table *table, |
| 157 | + rib_update_event_t event); |
| 158 | +-extern void rib_sweep_route(void); |
| 159 | ++extern int rib_sweep_route(struct thread *t); |
| 160 | + extern void rib_sweep_table(struct route_table *table); |
| 161 | + extern void rib_close_table(struct route_table *table); |
| 162 | + extern void rib_init(void); |
| 163 | +diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c |
| 164 | +index 555127b09..b6afcdc8c 100644 |
| 165 | +--- a/zebra/zebra_rib.c |
| 166 | ++++ b/zebra/zebra_rib.c |
| 167 | +@@ -3145,6 +3145,7 @@ void rib_sweep_table(struct route_table *table) |
| 168 | + |
| 169 | + for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) { |
| 170 | + RNODE_FOREACH_RE_SAFE (rn, re, next) { |
| 171 | ++ |
| 172 | + if (IS_ZEBRA_DEBUG_RIB) |
| 173 | + route_entry_dump(&rn->p, NULL, re); |
| 174 | + |
| 175 | +@@ -3154,6 +3155,14 @@ void rib_sweep_table(struct route_table *table) |
| 176 | + if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELFROUTE)) |
| 177 | + continue; |
| 178 | + |
| 179 | ++ /* |
| 180 | ++ * If routes are older than startup_time then |
| 181 | ++ * we know we read them in from the kernel. |
| 182 | ++ * As such we can safely remove them. |
| 183 | ++ */ |
| 184 | ++ if (zrouter.startup_time < re->uptime) |
| 185 | ++ continue; |
| 186 | ++ |
| 187 | + /* |
| 188 | + * So we are starting up and have received |
| 189 | + * routes from the kernel that we have installed |
| 190 | +@@ -3183,7 +3192,7 @@ void rib_sweep_table(struct route_table *table) |
| 191 | + } |
| 192 | + |
| 193 | + /* Sweep all RIB tables. */ |
| 194 | +-void rib_sweep_route(void) |
| 195 | ++int rib_sweep_route(struct thread *t) |
| 196 | + { |
| 197 | + struct vrf *vrf; |
| 198 | + struct zebra_vrf *zvrf; |
| 199 | +@@ -3197,6 +3206,8 @@ void rib_sweep_route(void) |
| 200 | + } |
| 201 | + |
| 202 | + zebra_router_sweep_route(); |
| 203 | ++ |
| 204 | ++ return 0; |
| 205 | + } |
| 206 | + |
| 207 | + /* Remove specific by protocol routes from 'table'. */ |
| 208 | +diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h |
| 209 | +index b316b91d0..b2e92bad0 100644 |
| 210 | +--- a/zebra/zebra_router.h |
| 211 | ++++ b/zebra/zebra_router.h |
| 212 | +@@ -110,8 +110,15 @@ struct zebra_router { |
| 213 | + * The EVPN instance, if any |
| 214 | + */ |
| 215 | + struct zebra_vrf *evpn_vrf; |
| 216 | ++ |
| 217 | ++ /* |
| 218 | ++ * Time for when we sweep the rib from old routes |
| 219 | ++ */ |
| 220 | ++ time_t startup_time; |
| 221 | + }; |
| 222 | + |
| 223 | ++#define GRACEFUL_RESTART_TIME 60 |
| 224 | ++ |
| 225 | + extern struct zebra_router zrouter; |
| 226 | + |
| 227 | + extern void zebra_router_init(void); |
0 commit comments