]> git.proxmox.com Git - mirror_frr.git/commitdiff
mpls: add support to the OpenBSD kernel
authorRenato Westphal <renato@opensourcerouting.org>
Thu, 2 Jun 2016 11:28:15 +0000 (08:28 -0300)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Fri, 23 Sep 2016 13:31:15 +0000 (09:31 -0400)
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
configure.ac
lib/sockunion.h
zebra/kernel_socket.c
zebra/kernel_socket.h
zebra/rt.h
zebra/rt_socket.c
zebra/zebra_mpls.c
zebra/zebra_mpls_netlink.c
zebra/zebra_mpls_null.c
zebra/zebra_mpls_openbsd.c [new file with mode: 0644]

index e15f384c218bbcc6fc7385b886da31b5bd777f4b..ac63eaab8198f23e784db71dbb0355e523574a85 100755 (executable)
@@ -374,6 +374,11 @@ if test "x${enable_mpls}" = "xyes"; then
         MPLS_METHOD="zebra_mpls_netlink.o"
         AC_MSG_RESULT(Linux MPLS)
     ;;
+    *-openbsd*)
+        AC_DEFINE(HAVE_MPLS,,Enable MPLS)
+        MPLS_METHOD="zebra_mpls_openbsd.o"
+        AC_MSG_RESULT(OpenBSD MPLS)
+    ;;
     *)
         AC_MSG_RESULT(Unsupported kernel)
         MPLS_METHOD="zebra_mpls_null.o"
index 105b11a24c5afc03da6905cfdbcdc17b8632f91c..abad43122ea5a729a2a1e75516525cf31a8f38dc 100644 (file)
 
 #include "privs.h"
 #include "if.h"
+#if defined HAVE_MPLS && defined __OpenBSD__
+#include <netmpls/mpls.h>
+#endif
 
 union sockunion 
 {
   struct sockaddr sa;
   struct sockaddr_in sin;
   struct sockaddr_in6 sin6;
+#if defined HAVE_MPLS && defined __OpenBSD__
+  struct sockaddr_mpls smpls;
+#endif
 };
 
 enum connect_result
index 3a232129b664780e0bc2ce4e7b0ee69c488a216f..7952f9e76175b030ecdcbc7497e64482531589b5 100644 (file)
@@ -21,6 +21,9 @@
 
 #include <zebra.h>
 #include <net/if_types.h>
+#if defined HAVE_MPLS && defined __OpenBSD__
+#include <netmpls/mpls.h>
+#endif
 
 #include "if.h"
 #include "prefix.h"
@@ -1068,6 +1071,7 @@ rtm_write (int message,
           union sockunion *dest,
           union sockunion *mask,
           union sockunion *gate,
+          union sockunion *mpls,
           unsigned int index,
           int zebra_flags,
           int metric)
@@ -1097,6 +1101,10 @@ rtm_write (int message,
   msg.rtm.rtm_addrs = RTA_DST;
   msg.rtm.rtm_addrs |= RTA_GATEWAY;
   msg.rtm.rtm_flags = RTF_UP;
+#if defined HAVE_MPLS && defined __OpenBSD__
+  msg.rtm.rtm_flags |= RTF_MPATH;
+  msg.rtm.rtm_fmask = RTF_MPLS;
+#endif
   msg.rtm.rtm_index = index;
 
   if (metric != 0)
@@ -1142,6 +1150,17 @@ rtm_write (int message,
   else if (message == RTM_ADD) 
     msg.rtm.rtm_flags |= RTF_HOST;
 
+#if defined HAVE_MPLS && defined __OpenBSD__
+  if (mpls)
+    {
+      msg.rtm.rtm_addrs |= RTA_SRC;
+      msg.rtm.rtm_flags |= RTF_MPLS;
+
+      if (mpls->smpls.smpls_label != htonl (MPLS_IMP_NULL_LABEL << MPLS_LABEL_OFFSET))
+       msg.rtm.rtm_mpls = MPLS_OP_PUSH;
+    }
+#endif
+
   /* Tagging route with flags */
   msg.rtm.rtm_flags |= (RTF_PROTO1);
 
@@ -1166,6 +1185,9 @@ rtm_write (int message,
   SOCKADDRSET (dest, RTA_DST);
   SOCKADDRSET (gate, RTA_GATEWAY);
   SOCKADDRSET (mask, RTA_NETMASK);
+#if defined HAVE_MPLS && defined __OpenBSD__
+  SOCKADDRSET (mpls, RTA_SRC);
+#endif
 
   msg.rtm.rtm_msglen = pnt - (caddr_t) &msg;
 
index e9558ad6dd708c5e80064b3896af28ab9100e108..18d69343a4bb8cc47c7faaeb62f7589d7945507c 100644 (file)
@@ -27,7 +27,8 @@ extern void rtm_read (struct rt_msghdr *);
 extern int ifam_read (struct ifa_msghdr *);
 extern int ifm_read (struct if_msghdr *);
 extern int rtm_write (int, union sockunion *, union sockunion *,
-                      union sockunion *, unsigned int, int, int);
+                      union sockunion *, union sockunion *,
+                      unsigned int, int, int);
 extern const struct message rtm_type_str[];
 
 #endif /* __ZEBRA_KERNEL_SOCKET_H */
index 1137f880f0992d7847dd6411347d4846d39c9645..c4a85e6d66cbc8019495e1661c842f6c4be16ace 100644 (file)
@@ -44,5 +44,6 @@ extern int kernel_delete_ipv6 (struct prefix *, struct rib *);
 extern int kernel_add_lsp (zebra_lsp_t *);
 extern int kernel_upd_lsp (zebra_lsp_t *);
 extern int kernel_del_lsp (zebra_lsp_t *);
+extern void mpls_kernel_init (void);
 
 #endif /* _ZEBRA_RT_H */
index 24671829f03871303fc3bf49535d97fdaf387964..a6a1978065137074075f28e67eff338510f5899e 100644 (file)
@@ -21,6 +21,9 @@
  */
 
 #include <zebra.h>
+#if defined HAVE_MPLS && defined __OpenBSD__
+#include <netmpls/mpls.h>
+#endif
 
 #include "if.h"
 #include "prefix.h"
 #include "zebra/rib.h"
 #include "zebra/rt.h"
 #include "zebra/kernel_socket.h"
+#include "zebra/zebra_mpls.h"
 
 extern struct zebra_privs_t zserv_privs;
 
 /* kernel socket export */
 extern int rtm_write (int message, union sockunion *dest,
                       union sockunion *mask, union sockunion *gate,
-                      unsigned int index, int zebra_flags, int metric);
+                      union sockunion *mpls, unsigned int index,
+                      int zebra_flags, int metric);
 
 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
 /* Adjust netmask socket length. Return value is a adjusted sin_len
@@ -73,6 +78,10 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family)
 {
   struct sockaddr_in *mask = NULL;
   struct sockaddr_in sin_dest, sin_mask, sin_gate;
+#if defined HAVE_MPLS && defined __OpenBSD__
+  struct sockaddr_mpls smpls;
+#endif
+  union sockunion *smplsp = NULL;
   struct nexthop *nexthop, *tnexthop;
   int recursing;
   int nexthop_num = 0;
@@ -147,10 +156,23 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family)
              mask = &sin_mask;
            }
 
+#if defined HAVE_MPLS && defined __OpenBSD__
+         if (nexthop->nh_label)
+           {
+             memset (&smpls, 0, sizeof (smpls));
+             smpls.smpls_len = sizeof (smpls);
+             smpls.smpls_family = AF_MPLS;
+             smpls.smpls_label =
+               htonl (nexthop->nh_label->label[0] << MPLS_LABEL_OFFSET);
+             smplsp = (union sockunion *)&smpls;
+           }
+#endif
+
          error = rtm_write (cmd,
                             (union sockunion *)&sin_dest, 
                             (union sockunion *)mask, 
                             gate ? (union sockunion *)&sin_gate : NULL,
+                            smplsp,
                             ifindex,
                             rib->flags,
                             rib->metric);
@@ -365,6 +387,7 @@ kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib,
                        (union sockunion *) &sin_dest,
                        (union sockunion *) mask,
                        gate ? (union sockunion *)&sin_gate : NULL,
+                       NULL,
                        ifindex,
                        rib->flags,
                        rib->metric);
index 8f18f326d1282b0aeda04b695f473b506fc182dd..6b032707ac4c071ecd1b48d9b3d8af6c0eef2e64 100644 (file)
@@ -1888,5 +1888,6 @@ zebra_mpls_init_tables (struct zebra_vrf *zvrf)
 void
 zebra_mpls_init (void)
 {
+  mpls_kernel_init ();
   mpls_processq_init (&zebrad);
 }
index f5678ede31da954aab782b54e13c14fafc47a68d..4011b90eeae8f17c5ffbbd85901beb6ac59614c5 100644 (file)
@@ -76,3 +76,5 @@ kernel_del_lsp (zebra_lsp_t *lsp)
 
   return 0;
 }
+
+void mpls_kernel_init (void) {};
index 9022fe30d27b3071504116da5d026315c9d80897..93405b88fda813557bd8f060a6939d337807d695 100644 (file)
@@ -5,3 +5,4 @@
 int kernel_add_lsp (zebra_lsp_t *lsp) { return 0; }
 int kernel_upd_lsp (zebra_lsp_t *lsp) { return 0; }
 int kernel_del_lsp (zebra_lsp_t *lsp) { return 0; }
+void mpls_kernel_init (void) {};
diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c
new file mode 100644 (file)
index 0000000..43a54ad
--- /dev/null
@@ -0,0 +1,206 @@
+#include <zebra.h>
+#include <netmpls/mpls.h>
+#include "zebra/rt.h"
+#include "zebra/zebra_mpls.h"
+#include "zebra/debug.h"
+
+#include "privs.h"
+#include "prefix.h"
+#include "interface.h"
+#include "log.h"
+
+extern struct zebra_privs_t zserv_privs;
+
+struct {
+  u_int32_t rtseq;
+  int fd;
+} kr_state;
+
+static int
+kernel_send_rtmsg (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 sockaddr_in nexthop;
+  int iovcnt = 0;
+  int ret;
+
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    zlog_debug ("kernel_send_rtmsg: 0x%x, label=%u", action, in_label);
+
+  /* initialize header */
+  bzero(&hdr, 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 */
+  bzero(&sa_label_in, 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 */
+  bzero(&nexthop, sizeof (nexthop));
+  nexthop.sin_len = sizeof (nexthop);
+  nexthop.sin_family = AF_INET;
+  nexthop.sin_addr = nhlfe->nexthop->gate.ipv4;
+  /* adjust header */
+  hdr.rtm_flags |= RTF_GATEWAY;
+  hdr.rtm_addrs |= RTA_GATEWAY;
+  hdr.rtm_msglen += sizeof (nexthop);
+  /* adjust iovec */
+  iov[iovcnt].iov_base = &nexthop;
+  iov[iovcnt++].iov_len = sizeof (nexthop);
+
+  /* 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));
+      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 ("kernel_send_rtmsg: %s", safe_strerror (errno));
+
+  return ret;
+}
+
+static int
+kernel_lsp_cmd (int action, zebra_lsp_t *lsp)
+{
+  zebra_nhlfe_t *nhlfe;
+  struct nexthop *nexthop = NULL;
+  int nexthop_num = 0;
+
+  for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
+    {
+      nexthop = nhlfe->nexthop;
+      if (!nexthop)
+        continue;
+
+      if (MULTIPATH_NUM != 0 && 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))) ||
+          (action == RTM_DELETE &&
+           (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED) &&
+            CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))))
+        {
+          nexthop_num++;
+
+         kernel_send_rtmsg (action, lsp->ile.in_label, nhlfe);
+          if (action == RTM_ADD || action == RTM_CHANGE)
+            {
+              SET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED);
+              SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+            }
+          else
+            {
+              UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED);
+              UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+            }
+        }
+    }
+
+  return (0);
+}
+
+int
+kernel_add_lsp (zebra_lsp_t *lsp)
+{
+  if (!lsp || !lsp->best_nhlfe) // unexpected
+    return -1;
+
+  return kernel_lsp_cmd (RTM_ADD, lsp);
+}
+
+int
+kernel_upd_lsp (zebra_lsp_t *lsp)
+{
+  if (!lsp || !lsp->best_nhlfe) // unexpected
+    return -1;
+
+  return kernel_lsp_cmd (RTM_CHANGE, lsp);
+}
+
+int
+kernel_del_lsp (zebra_lsp_t *lsp)
+{
+  if (!lsp) // unexpected
+    return -1;
+
+  return kernel_lsp_cmd (RTM_DELETE, lsp);
+}
+
+#define MAX_RTSOCK_BUF 128 * 1024
+void
+mpls_kernel_init (void)
+{
+  int          rcvbuf, default_rcvbuf;
+  socklen_t    optlen;
+
+  if ((kr_state.fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
+      zlog_warn("kr_init: socket");
+      return;
+  }
+
+  /* grow receive buffer, don't wanna miss messages */
+  optlen = sizeof (default_rcvbuf);
+  if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF,
+                &default_rcvbuf, &optlen) == -1)
+    zlog_warn("kr_init getsockopt SOL_SOCKET SO_RCVBUF");
+  else
+    for (rcvbuf = MAX_RTSOCK_BUF;
+        rcvbuf > default_rcvbuf &&
+        setsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF,
+                   &rcvbuf, sizeof (rcvbuf)) == -1 && errno == ENOBUFS;
+        rcvbuf /= 2)
+      ;        /* nothing */
+
+  kr_state.rtseq = 1;
+}