diff options
| -rwxr-xr-x | configure.ac | 5 | ||||
| -rw-r--r-- | lib/sockunion.h | 6 | ||||
| -rw-r--r-- | zebra/kernel_socket.c | 22 | ||||
| -rw-r--r-- | zebra/kernel_socket.h | 3 | ||||
| -rw-r--r-- | zebra/rt.h | 1 | ||||
| -rw-r--r-- | zebra/rt_socket.c | 25 | ||||
| -rw-r--r-- | zebra/zebra_mpls.c | 1 | ||||
| -rw-r--r-- | zebra/zebra_mpls_netlink.c | 2 | ||||
| -rw-r--r-- | zebra/zebra_mpls_null.c | 1 | ||||
| -rw-r--r-- | zebra/zebra_mpls_openbsd.c | 206 | 
10 files changed, 270 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac index e15f384c21..ac63eaab81 100755 --- a/configure.ac +++ b/configure.ac @@ -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" diff --git a/lib/sockunion.h b/lib/sockunion.h index 105b11a24c..abad43122e 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -25,12 +25,18 @@  #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 diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 3a232129b6..7952f9e761 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -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; diff --git a/zebra/kernel_socket.h b/zebra/kernel_socket.h index e9558ad6dd..18d69343a4 100644 --- a/zebra/kernel_socket.h +++ b/zebra/kernel_socket.h @@ -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 */ diff --git a/zebra/rt.h b/zebra/rt.h index 1137f880f0..c4a85e6d66 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -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 */ diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 24671829f0..a6a1978065 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -21,6 +21,9 @@   */  #include <zebra.h> +#if defined HAVE_MPLS && defined __OpenBSD__ +#include <netmpls/mpls.h> +#endif  #include "if.h"  #include "prefix.h" @@ -33,13 +36,15 @@  #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); diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 8f18f326d1..6b032707ac 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -1888,5 +1888,6 @@ zebra_mpls_init_tables (struct zebra_vrf *zvrf)  void  zebra_mpls_init (void)  { +  mpls_kernel_init ();    mpls_processq_init (&zebrad);  } diff --git a/zebra/zebra_mpls_netlink.c b/zebra/zebra_mpls_netlink.c index f5678ede31..4011b90eea 100644 --- a/zebra/zebra_mpls_netlink.c +++ b/zebra/zebra_mpls_netlink.c @@ -76,3 +76,5 @@ kernel_del_lsp (zebra_lsp_t *lsp)    return 0;  } + +void mpls_kernel_init (void) {}; diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c index 9022fe30d2..93405b88fd 100644 --- a/zebra/zebra_mpls_null.c +++ b/zebra/zebra_mpls_null.c @@ -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 index 0000000000..43a54adff1 --- /dev/null +++ b/zebra/zebra_mpls_openbsd.c @@ -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; +}  | 
