]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/zebra_mpls_openbsd.c
*: make consistent & update GPLv2 file headers
[mirror_frr.git] / zebra / zebra_mpls_openbsd.c
index bae1de66bfdb70a99f543d236b005ea6dc48954d..bca73898c5fac1a4d328862ee2c656eb994df834 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * Copyright (C) 2016 by Open Source Routing.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
 #include <zebra.h>
 #include <netmpls/mpls.h>
 #include "zebra/rt.h"
@@ -17,7 +37,7 @@ struct {
 } kr_state;
 
 static int
-kernel_send_rtmsg (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
+kernel_send_rtmsg_v4 (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
 {
   struct iovec iov[5];
   struct rt_msghdr hdr;
@@ -27,10 +47,10 @@ kernel_send_rtmsg (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
   int ret;
 
   if (IS_ZEBRA_DEBUG_KERNEL)
-    zlog_debug ("kernel_send_rtmsg: 0x%x, label=%u", action, in_label);
+    zlog_debug ("%s: 0x%x, label=%u", __func__, action, in_label);
 
   /* initialize header */
-  bzero(&hdr, sizeof (hdr));
+  memset (&hdr, 0, sizeof (hdr));
   hdr.rtm_version = RTM_VERSION;
 
   hdr.rtm_type = action;
@@ -45,7 +65,7 @@ kernel_send_rtmsg (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
   iov[iovcnt++].iov_len = sizeof (hdr);
 
   /* in label */
-  bzero(&sa_label_in, sizeof (sa_label_in));
+  memset (&sa_label_in, 0, sizeof (sa_label_in));
   sa_label_in.smpls_len = sizeof (sa_label_in);
   sa_label_in.smpls_family = AF_MPLS;
   sa_label_in.smpls_label = htonl(in_label << MPLS_LABEL_OFFSET);
@@ -58,7 +78,7 @@ kernel_send_rtmsg (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
   iov[iovcnt++].iov_len = sizeof (sa_label_in);
 
   /* nexthop */
-  bzero(&nexthop, sizeof (nexthop));
+  memset (&nexthop, 0, sizeof (nexthop));
   nexthop.sin_len = sizeof (nexthop);
   nexthop.sin_family = AF_INET;
   nexthop.sin_addr = nhlfe->nexthop->gate.ipv4;
@@ -73,7 +93,7 @@ kernel_send_rtmsg (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
   /* If action is RTM_DELETE we have to get rid of MPLS infos */
   if (action != RTM_DELETE)
     {
-      bzero(&sa_label_out, sizeof (sa_label_out));
+      memset (&sa_label_out, 0, sizeof (sa_label_out));
       sa_label_out.smpls_len = sizeof (sa_label_out);
       sa_label_out.smpls_family = AF_MPLS;
       sa_label_out.smpls_label =
@@ -99,7 +119,116 @@ kernel_send_rtmsg (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
     zlog_err ("Can't lower privileges");
 
   if (ret == -1)
-    zlog_err ("kernel_send_rtmsg: %s", safe_strerror (errno));
+    zlog_err ("%s: %s", __func__, safe_strerror (errno));
+
+  return ret;
+}
+
+#if !defined(ROUNDUP)
+#define        ROUNDUP(a)      \
+    (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a))
+#endif
+
+static int
+kernel_send_rtmsg_v6 (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
+{
+  struct iovec iov[5];
+  struct rt_msghdr hdr;
+  struct sockaddr_mpls sa_label_in, sa_label_out;
+  struct pad {
+      struct sockaddr_in6      addr;
+      char                     pad[sizeof(long)]; /* thank you IPv6 */
+  } nexthop;
+  int iovcnt = 0;
+  int ret;
+
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    zlog_debug ("%s: 0x%x, label=%u", __func__, action, in_label);
+
+  /* initialize header */
+  memset (&hdr, 0, sizeof (hdr));
+  hdr.rtm_version = RTM_VERSION;
+
+  hdr.rtm_type = action;
+  hdr.rtm_flags = RTF_UP;
+  hdr.rtm_fmask = RTF_MPLS;
+  hdr.rtm_seq = kr_state.rtseq++;      /* overflow doesn't matter */
+  hdr.rtm_msglen = sizeof (hdr);
+  hdr.rtm_hdrlen = sizeof (struct rt_msghdr);
+  hdr.rtm_priority = 0;
+  /* adjust iovec */
+  iov[iovcnt].iov_base = &hdr;
+  iov[iovcnt++].iov_len = sizeof (hdr);
+
+  /* in label */
+  memset (&sa_label_in, 0, sizeof (sa_label_in));
+  sa_label_in.smpls_len = sizeof (sa_label_in);
+  sa_label_in.smpls_family = AF_MPLS;
+  sa_label_in.smpls_label = htonl(in_label << MPLS_LABEL_OFFSET);
+  /* adjust header */
+  hdr.rtm_flags |= RTF_MPLS | RTF_MPATH;
+  hdr.rtm_addrs |= RTA_DST;
+  hdr.rtm_msglen += sizeof (sa_label_in);
+  /* adjust iovec */
+  iov[iovcnt].iov_base = &sa_label_in;
+  iov[iovcnt++].iov_len = sizeof (sa_label_in);
+
+  /* nexthop */
+  memset (&nexthop, 0, sizeof (nexthop));
+  nexthop.addr.sin6_len = sizeof (struct sockaddr_in6);
+  nexthop.addr.sin6_family = AF_INET6;
+  nexthop.addr.sin6_addr = nhlfe->nexthop->gate.ipv6;
+  if (IN6_IS_ADDR_LINKLOCAL (&nexthop.addr.sin6_addr))
+    {
+      uint16_t                  tmp16;
+      struct sockaddr_in6      *sin6 = &nexthop.addr;
+
+      nexthop.addr.sin6_scope_id = nhlfe->nexthop->ifindex;
+
+      memcpy (&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof (tmp16));
+      tmp16 = htons (sin6->sin6_scope_id);
+      memcpy (&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof (tmp16));
+      sin6->sin6_scope_id = 0;
+    }
+
+  /* adjust header */
+  hdr.rtm_flags |= RTF_GATEWAY;
+  hdr.rtm_addrs |= RTA_GATEWAY;
+  hdr.rtm_msglen += ROUNDUP (sizeof (struct sockaddr_in6));
+  /* adjust iovec */
+  iov[iovcnt].iov_base = &nexthop;
+  iov[iovcnt++].iov_len = ROUNDUP (sizeof (struct sockaddr_in6));
+
+  /* If action is RTM_DELETE we have to get rid of MPLS infos */
+  if (action != RTM_DELETE)
+    {
+      memset (&sa_label_out, 0, sizeof (sa_label_out));
+      sa_label_out.smpls_len = sizeof (sa_label_out);
+      sa_label_out.smpls_family = AF_MPLS;
+      sa_label_out.smpls_label =
+       htonl(nhlfe->nexthop->nh_label->label[0] << MPLS_LABEL_OFFSET);
+      /* adjust header */
+      hdr.rtm_addrs |= RTA_SRC;
+      hdr.rtm_flags |= RTF_MPLS;
+      hdr.rtm_msglen += sizeof (sa_label_out);
+      /* adjust iovec */
+      iov[iovcnt].iov_base = &sa_label_out;
+      iov[iovcnt++].iov_len = sizeof (sa_label_out);
+
+      if (nhlfe->nexthop->nh_label->label[0] == MPLS_LABEL_IMPLNULL)
+       hdr.rtm_mpls = MPLS_OP_POP;
+      else
+       hdr.rtm_mpls = MPLS_OP_SWAP;
+    }
+
+  if (zserv_privs.change(ZPRIVS_RAISE))
+    zlog_err ("Can't raise privileges");
+  ret = writev (kr_state.fd, iov, iovcnt);
+  if (zserv_privs.change(ZPRIVS_LOWER))
+    zlog_err ("Can't lower privileges");
+
+  if (ret == -1)
+    zlog_err ("%s: %s", __func__, safe_strerror (errno));
 
   return ret;
 }
@@ -117,13 +246,9 @@ kernel_lsp_cmd (int action, zebra_lsp_t *lsp)
       if (!nexthop)
         continue;
 
-      if (MULTIPATH_NUM != 0 && nexthop_num >= MULTIPATH_NUM)
+      if (nexthop_num >= multipath_num)
         break;
 
-      /* XXX */
-      if (NHLFE_FAMILY(nhlfe) == AF_INET6)
-       continue;
-
       if (((action == RTM_ADD || action == RTM_CHANGE) &&
            (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_SELECTED) &&
             CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))) ||
@@ -133,7 +258,17 @@ kernel_lsp_cmd (int action, zebra_lsp_t *lsp)
         {
           nexthop_num++;
 
-         kernel_send_rtmsg (action, lsp->ile.in_label, nhlfe);
+         switch (NHLFE_FAMILY(nhlfe))
+           {
+           case AF_INET:
+             kernel_send_rtmsg_v4 (action, lsp->ile.in_label, nhlfe);
+             break;
+           case AF_INET6:
+             kernel_send_rtmsg_v6 (action, lsp->ile.in_label, nhlfe);
+             break;
+           default:
+             break;
+           }
           if (action == RTM_ADD || action == RTM_CHANGE)
             {
               SET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED);