Reintroduce UpdateRoutesWithRetries in TunDeviceController.

PiperOrigin-RevId: 378927180
diff --git a/quic/qbone/bonnet/tun_device_controller.cc b/quic/qbone/bonnet/tun_device_controller.cc
index c8a6517..4a5c9e7 100644
--- a/quic/qbone/bonnet/tun_device_controller.cc
+++ b/quic/qbone/bonnet/tun_device_controller.cc
@@ -110,6 +110,19 @@
   return true;
 }
 
+bool TunDeviceController::UpdateRoutesWithRetries(
+    const IpRange& desired_range,
+    const std::vector<IpRange>& desired_routes,
+    int retries) {
+  while (retries-- > 0) {
+    if (UpdateRoutes(desired_range, desired_routes)) {
+      return true;
+    }
+    absl::SleepFor(absl::Milliseconds(100));
+  }
+  return false;
+}
+
 bool TunDeviceController::UpdateRules(IpRange desired_range) {
   if (!absl::GetFlag(FLAGS_qbone_tun_device_replace_default_routing_rules)) {
     return true;
diff --git a/quic/qbone/bonnet/tun_device_controller.h b/quic/qbone/bonnet/tun_device_controller.h
index 6854521..89464c3 100644
--- a/quic/qbone/bonnet/tun_device_controller.h
+++ b/quic/qbone/bonnet/tun_device_controller.h
@@ -39,6 +39,17 @@
   virtual bool UpdateRoutes(const IpRange& desired_range,
                             const std::vector<IpRange>& desired_routes);
 
+  // Same as UpdateRoutes, but will wait and retry up to the number of times
+  // given by |retries| before giving up. This is an unpleasant workaround to
+  // deal with older kernels that aren't always able to set a route with a
+  // source address immediately after adding the address to the interface.
+  //
+  // TODO(b/179430548): Remove this once we've root-caused the underlying issue.
+  virtual bool UpdateRoutesWithRetries(
+      const IpRange& desired_range,
+      const std::vector<IpRange>& desired_routes,
+      int retries);
+
   virtual QuicIpAddress current_address();
 
  private: