summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xconfigure.ac5
-rw-r--r--lib/sockunion.h6
-rw-r--r--zebra/kernel_socket.c22
-rw-r--r--zebra/kernel_socket.h3
-rw-r--r--zebra/rt.h1
-rw-r--r--zebra/rt_socket.c25
-rw-r--r--zebra/zebra_mpls.c1
-rw-r--r--zebra/zebra_mpls_netlink.c2
-rw-r--r--zebra/zebra_mpls_null.c1
-rw-r--r--zebra/zebra_mpls_openbsd.c206
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;
+}