]> git.puffer.fish Git - mirror/frr.git/commitdiff
Zebra: Make RA socket operation on a per-NS basis
authorvivek <vivek@cumulusnetworks.com>
Fri, 19 Feb 2016 22:28:25 +0000 (14:28 -0800)
committervivek <vivek@cumulusnetworks.com>
Fri, 19 Feb 2016 22:55:36 +0000 (14:55 -0800)
This patch reorganizes the RA handling to be per namespace rather than per
VRF. The VRF library by 6wind had done the original change to make the RA
data structures (socket information) per VRF, but this was correct only if
each VRF represented a NS. In our reorganization, we have created a NS
structure (struct zebra_ns) and VRFs don't correspond to namespaces (i.e.,
all VRFs exist in the default namespace). So, the RA handling should be
done under 'struct zebra_ns'.

With the changes, there is a single raw socket per NS (=> 1 for us) on which
we will receive and handle RAs for all interfaces. The interface information
is available through cmsg and the processing will then happen for that interface.

There is a problem with transmitting RAs over a VRF interface. This is
tracked by CM-9398.

Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Ticket: CM-9206
Reviewed By: CCR-4217
Testing Done: Manual testing

zebra/main.c
zebra/rib.h
zebra/rtadv.c
zebra/rtadv.h

index a865170c26f8ce30e923acf19edefa3abd4bad68..3590eed26a943c99884db663a1b8c5d5737a2703 100644 (file)
@@ -124,6 +124,8 @@ char config_default[] = SYSCONFDIR DEFAULT_CONFIG_FILE;
 /* Process ID saved for use by init system */
 const char *pid_file = PATH_ZEBRA_PID;
 
+static int zebra_ns_disable (ns_id_t ns_id, void **info);
+
 /* Help information display. */
 static void
 usage (char *progname, int status)
@@ -185,6 +187,7 @@ sigint (void)
 #endif
 
   zebra_ptm_finish();
+  zebra_ns_disable (0, (void **)&dzns);
   systemd_send_stopping();
   exit (0);
 }
@@ -243,6 +246,10 @@ zebra_ns_enable (ns_id_t ns_id, void **info)
   char nl_name[64];
 #endif
 
+#if defined (HAVE_RTADV)
+  rtadv_init (zns);
+#endif
+
 #ifdef HAVE_NETLINK
   /* Initialize netlink sockets */
   snprintf (nl_name, 64, "netlink-listen (NS %u)", ns_id);
@@ -269,24 +276,22 @@ zebra_vrf_enable (vrf_id_t vrf_id, const char *name, void **info)
 
   assert (zvrf);
 
-#if defined (HAVE_RTADV)
-  rtadv_init (zvrf);
-#endif
-
   return 0;
 }
 
-/*
 static int
 zebra_ns_disable (ns_id_t ns_id, void **info)
 {
   struct zebra_ns *zns = (struct zebra_ns *) (*info);
 
+#if defined (HAVE_RTADV)
+  rtadv_terminate (zns);
+#endif
+
   kernel_terminate (zns);
 
   return 0;
 }
-*/
 
 /* Callback upon disabling a VRF. */
 static int
@@ -309,10 +314,6 @@ zebra_vrf_disable (vrf_id_t vrf_id, const char *name, void **info)
         if_down (ifp);
     }
 
-#if defined (HAVE_RTADV)
-  rtadv_terminate (zvrf);
-#endif
-
   list_delete_all_node (zvrf->rid_all_sorted_list);
   list_delete_all_node (zvrf->rid_lo_sorted_list);
 
index df0e993f751dcccbd595c433a297340024a81ea9..84941a6737485d5ed879af96b39d9c82f9123115 100644 (file)
@@ -302,6 +302,10 @@ struct zebra_ns
 #endif
 
   struct route_table *if_table;
+
+#if defined (HAVE_RTADV)
+  struct rtadv rtadv;
+#endif /* HAVE_RTADV */
 };
 
 /* Routing table instance.  */
@@ -345,10 +349,6 @@ struct zebra_vrf
   struct list *rid_lo_sorted_list;
   struct prefix rid_user_assigned;
 
-#if defined (HAVE_RTADV)
-  struct rtadv rtadv;
-#endif /* HAVE_RTADV */
-
   /*
    * Back pointer to the owning namespace.
    */
index 69bd5664085645a63018f345c9eec9c85d3fbe93..da89ef282add9dc486f1a07bd17a7dc398cbb5af 100644 (file)
@@ -63,7 +63,7 @@ extern struct zebra_t zebrad;
 enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER, 
                  RTADV_TIMER_MSEC, RTADV_READ};
 
-static void rtadv_event (struct zebra_vrf *, enum rtadv_event, int);
+static void rtadv_event (struct zebra_ns *, enum rtadv_event, int);
 
 static int if_join_all_router (int, struct interface *);
 static int if_leave_all_router (int, struct interface *);
@@ -370,43 +370,46 @@ rtadv_send_packet (int sock, struct interface *ifp)
 static int
 rtadv_timer (struct thread *thread)
 {
-  struct zebra_vrf *zvrf = THREAD_ARG (thread);
+  struct zebra_ns *zns = THREAD_ARG (thread);
+  vrf_iter_t iter;
   struct listnode *node, *nnode;
   struct interface *ifp;
   struct zebra_if *zif;
   int period;
 
-  zvrf->rtadv.ra_timer = NULL;
-  if (zvrf->rtadv.adv_msec_if_count == 0)
+  zns->rtadv.ra_timer = NULL;
+  if (zns->rtadv.adv_msec_if_count == 0)
     {
       period = 1000; /* 1 s */
-      rtadv_event (zvrf, RTADV_TIMER, 1 /* 1 s */);
+      rtadv_event (zns, RTADV_TIMER, 1 /* 1 s */);
     } 
   else
     {
       period = 10; /* 10 ms */
-      rtadv_event (zvrf, RTADV_TIMER_MSEC, 10 /* 10 ms */);
+      rtadv_event (zns, RTADV_TIMER_MSEC, 10 /* 10 ms */);
     }
 
-  for (ALL_LIST_ELEMENTS (vrf_iflist (zvrf->vrf_id), node, nnode, ifp))
-    {
-      if (if_is_loopback (ifp) || ! if_is_operative (ifp))
-       continue;
-
-      zif = ifp->info;
+  for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+    for (ALL_LIST_ELEMENTS (vrf_iter2iflist (iter), node, nnode, ifp))
+      {
+        if (if_is_loopback (ifp) || ! if_is_operative (ifp))
+          continue;
+
+        zif = ifp->info;
+
+        if (zif->rtadv.AdvSendAdvertisements)
+          {
+            zif->rtadv.AdvIntervalTimer -= period;
+            if (zif->rtadv.AdvIntervalTimer <= 0)
+              {
+                /* FIXME: using MaxRtrAdvInterval each time isn't what section
+                6.2.4 of RFC4861 tells to do. */
+                zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
+                rtadv_send_packet (zns->rtadv.sock, ifp);
+              }
+          }
+      }
 
-      if (zif->rtadv.AdvSendAdvertisements)
-       { 
-         zif->rtadv.AdvIntervalTimer -= period;
-         if (zif->rtadv.AdvIntervalTimer <= 0)
-           {
-             /* FIXME: using MaxRtrAdvInterval each time isn't what section
-                6.2.4 of RFC4861 tells to do. */
-             zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
-             rtadv_send_packet (zvrf->rtadv.sock, ifp);
-           }
-       }
-    }
   return 0;
 }
 
@@ -414,10 +417,12 @@ static void
 rtadv_process_solicit (struct interface *ifp)
 {
   struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
+  struct zebra_ns *zns = zvrf->zns;
 
   zlog_info ("Router solicitation received on %s vrf %u", ifp->name, zvrf->vrf_id);
 
-  rtadv_send_packet (zvrf->rtadv.sock, ifp);
+  assert (zns);
+  rtadv_send_packet (zns->rtadv.sock, ifp);
 }
 
 static void
@@ -497,17 +502,17 @@ rtadv_process_advert (u_char *msg, unsigned int len, struct interface *ifp,
 
 static void
 rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex, int hoplimit,
-                      struct sockaddr_in6 *from, vrf_id_t vrf_id)
+                      struct sockaddr_in6 *from, struct zebra_ns *zns)
 {
   struct icmp6_hdr *icmph;
   struct interface *ifp;
   struct zebra_if *zif;
 
   /* Interface search. */
-  ifp = if_lookup_by_index_vrf (ifindex, vrf_id);
+  ifp = if_lookup_by_index_per_ns (zns, ifindex);
   if (ifp == NULL)
     {
-      zlog_warn ("Unknown interface index: %d, vrf %u", ifindex, vrf_id);
+      zlog_warn ("Unknown interface index: %d", ifindex);
       return;
     }
 
@@ -562,13 +567,13 @@ rtadv_read (struct thread *thread)
   struct sockaddr_in6 from;
   unsigned int ifindex = 0;
   int hoplimit = -1;
-  struct zebra_vrf *zvrf = THREAD_ARG (thread);
+  struct zebra_ns *zns = THREAD_ARG (thread);
 
   sock = THREAD_FD (thread);
-  zvrf->rtadv.ra_read = NULL;
+  zns->rtadv.ra_read = NULL;
 
   /* Register myself. */
-  rtadv_event (zvrf, RTADV_READ, sock);
+  rtadv_event (zns, RTADV_READ, sock);
 
   len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit);
 
@@ -578,30 +583,28 @@ rtadv_read (struct thread *thread)
       return len;
     }
 
-  rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit, &from, zvrf->vrf_id);
+  rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit, &from, zns);
 
   return 0;
 }
 
 static int
-rtadv_make_socket (vrf_id_t vrf_id)
+rtadv_make_socket (void)
 {
   int sock;
-  int ret;
+  int ret = 0;
   struct icmp6_filter filter;
 
   if ( zserv_privs.change (ZPRIVS_RAISE) )
        zlog_err ("rtadv_make_socket: could not raise privs, %s",
                   safe_strerror (errno) );
                   
-  sock = vrf_socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, vrf_id);
+  sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
 
   if ( zserv_privs.change (ZPRIVS_LOWER) )
        zlog_err ("rtadv_make_socket: could not lower privs, %s",
                                 safe_strerror (errno) );
 
-  /* When we can't make ICMPV6 socket simply back.  Router
-     advertisement feature will not be supported. */
   if (sock < 0)
     return -1;
 
@@ -712,9 +715,11 @@ ipv6_nd_suppress_ra_set (struct interface *ifp, ipv6_nd_suppress_ra_status statu
 {
   struct zebra_if *zif;
   struct zebra_vrf *zvrf;
+  struct zebra_ns *zns;
 
   zif = ifp->info;
   zvrf = vrf_info_lookup (ifp->vrf_id);
+  zns = zvrf->zns;
 
   if (status == RA_SUPPRESS)
     {
@@ -723,12 +728,12 @@ ipv6_nd_suppress_ra_set (struct interface *ifp, ipv6_nd_suppress_ra_status statu
         {
           zif->rtadv.AdvSendAdvertisements = 0;
           zif->rtadv.AdvIntervalTimer = 0;
-          zvrf->rtadv.adv_if_count--;
+          zns->rtadv.adv_if_count--;
 
-          if_leave_all_router (zvrf->rtadv.sock, ifp);
+          if_leave_all_router (zns->rtadv.sock, ifp);
 
-          if (zvrf->rtadv.adv_if_count == 0)
-            rtadv_event (zvrf, RTADV_STOP, 0);
+          if (zns->rtadv.adv_if_count == 0)
+            rtadv_event (zns, RTADV_STOP, 0);
         }
     }
   else
@@ -737,12 +742,12 @@ ipv6_nd_suppress_ra_set (struct interface *ifp, ipv6_nd_suppress_ra_status statu
         {
           zif->rtadv.AdvSendAdvertisements = 1;
           zif->rtadv.AdvIntervalTimer = 0;
-          zvrf->rtadv.adv_if_count++;
+          zns->rtadv.adv_if_count++;
 
-          if_join_all_router (zvrf->rtadv.sock, ifp);
+          if_join_all_router (zns->rtadv.sock, ifp);
 
-          if (zvrf->rtadv.adv_if_count == 1)
-            rtadv_event (zvrf, RTADV_START, zvrf->rtadv.sock);
+          if (zns->rtadv.adv_if_count == 1)
+            rtadv_event (zns, RTADV_START, zns->rtadv.sock);
         }
     }
 }
@@ -802,7 +807,9 @@ DEFUN (ipv6_nd_ra_interval_msec,
   struct interface *ifp = (struct interface *) vty->index;
   struct zebra_if *zif = ifp->info;
   struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
+  struct zebra_ns *zns;
 
+  zns = zvrf->zns;
   VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 70, 1800000);
   if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000))
   {
@@ -811,10 +818,10 @@ DEFUN (ipv6_nd_ra_interval_msec,
   }
 
   if (zif->rtadv.MaxRtrAdvInterval % 1000)
-    zvrf->rtadv.adv_msec_if_count--;
+    zns->rtadv.adv_msec_if_count--;
 
   if (interval % 1000)
-    zvrf->rtadv.adv_msec_if_count++;
+    zns->rtadv.adv_msec_if_count++;
   
   zif->rtadv.MaxRtrAdvInterval = interval;
   zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
@@ -835,7 +842,9 @@ DEFUN (ipv6_nd_ra_interval,
   struct interface *ifp = (struct interface *) vty->index;
   struct zebra_if *zif = ifp->info;
   struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
+  struct zebra_ns *zns;
 
+  zns = zvrf->zns;
   VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 1, 1800);
   if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime))
   {
@@ -844,7 +853,7 @@ DEFUN (ipv6_nd_ra_interval,
   }
 
   if (zif->rtadv.MaxRtrAdvInterval % 1000)
-    zvrf->rtadv.adv_msec_if_count--;
+    zns->rtadv.adv_msec_if_count--;
        
   /* convert to milliseconds */
   interval = interval * 1000; 
@@ -867,13 +876,15 @@ DEFUN (no_ipv6_nd_ra_interval,
   struct interface *ifp;
   struct zebra_if *zif;
   struct zebra_vrf *zvrf;
+  struct zebra_ns *zns;
 
   ifp = (struct interface *) vty->index;
   zif = ifp->info;
   zvrf = vrf_info_lookup (ifp->vrf_id);
+  zns = zvrf->zns;
 
   if (zif->rtadv.MaxRtrAdvInterval % 1000)
-    zvrf->rtadv.adv_msec_if_count--;
+    zns->rtadv.adv_msec_if_count--;
   
   zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
   zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
@@ -1857,18 +1868,18 @@ rtadv_config_write (struct vty *vty, struct interface *ifp)
 
 
 static void
-rtadv_event (struct zebra_vrf *zvrf, enum rtadv_event event, int val)
+rtadv_event (struct zebra_ns *zns, enum rtadv_event event, int val)
 {
-  struct rtadv *rtadv = &zvrf->rtadv;
+  struct rtadv *rtadv = &zns->rtadv;
 
   switch (event)
     {
     case RTADV_START:
       if (! rtadv->ra_read)
-       rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, zvrf, val);
+       rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, zns, val);
       if (! rtadv->ra_timer)
        rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer,
-                                           zvrf, 0);
+                                           zns, 0);
       break;
     case RTADV_STOP:
       if (rtadv->ra_timer)
@@ -1884,17 +1895,17 @@ rtadv_event (struct zebra_vrf *zvrf, enum rtadv_event event, int val)
       break;
     case RTADV_TIMER:
       if (! rtadv->ra_timer)
-       rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, zvrf,
+       rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, zns,
                                            val);
       break;
     case RTADV_TIMER_MSEC:
       if (! rtadv->ra_timer)
        rtadv->ra_timer = thread_add_timer_msec (zebrad.master, rtadv_timer, 
-                                           zvrf, val);
+                                           zns, val);
       break;
     case RTADV_READ:
       if (! rtadv->ra_read)
-       rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, zvrf, val);
+       rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, zns, val);
       break;
     default:
       break;
@@ -1903,24 +1914,23 @@ rtadv_event (struct zebra_vrf *zvrf, enum rtadv_event event, int val)
 }
 
 void
-rtadv_init (struct zebra_vrf *zvrf)
+rtadv_init (struct zebra_ns *zns)
 {
-  zvrf->rtadv.sock = rtadv_make_socket (zvrf->vrf_id);
+  zns->rtadv.sock = rtadv_make_socket ();
 }
 
 void
-rtadv_terminate (struct zebra_vrf *zvrf)
+rtadv_terminate (struct zebra_ns *zns)
 {
-  rtadv_event (zvrf, RTADV_STOP, 0);
-
-  if (zvrf->rtadv.sock >= 0)
+  rtadv_event (zns, RTADV_STOP, 0);
+  if (zns->rtadv.sock >= 0)
     {
-      close (zvrf->rtadv.sock);
-      zvrf->rtadv.sock = -1;
+      close (zns->rtadv.sock);
+      zns->rtadv.sock = -1;
     }
 
-  zvrf->rtadv.adv_if_count = 0;
-  zvrf->rtadv.adv_msec_if_count = 0;
+  zns->rtadv.adv_if_count = 0;
+  zns->rtadv.adv_msec_if_count = 0;
 }
 
 void
@@ -2032,12 +2042,12 @@ if_leave_all_router (int sock, struct interface *ifp)
 
 #else
 void
-rtadv_init (struct zebra_vrf *zvrf)
+rtadv_init (struct zebra_ns *zns)
 {
   /* Empty.*/;
 }
 void
-rtadv_terminate (struct zebra_vrf *zvrf)
+rtadv_terminate (struct zebra_ns *zns)
 {
   /* Empty.*/;
 }
index e955d34d657199813da9bb531f27c2b6a2aa7003..51b8afe8d34effb5ee72680b7a8f3e0bb3f711cc 100644 (file)
@@ -105,8 +105,8 @@ typedef enum {
   RA_SUPPRESS,
 } ipv6_nd_suppress_ra_status;
 
-extern void rtadv_init (struct zebra_vrf *);
-extern void rtadv_terminate (struct zebra_vrf *);
+extern void rtadv_init (struct zebra_ns *);
+extern void rtadv_terminate (struct zebra_ns *);
 extern void rtadv_cmd_init (void);
 extern void ipv6_nd_suppress_ra_set (struct interface *ifp, ipv6_nd_suppress_ra_status status);