From d42127daf36e5cf0aed132cb55bd5788ea60a353 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 30 Jun 2017 12:18:21 -0300 Subject: [PATCH] zebra: add support to openbsd's mpw(4) for pseudowires Thanks to rzalamena@ for writing mpw(4) :) Signed-off-by: Renato Westphal --- zebra/zebra_mpls_openbsd.c | 90 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c index c3d09aedbd..119cd5b700 100644 --- a/zebra/zebra_mpls_openbsd.c +++ b/zebra/zebra_mpls_openbsd.c @@ -37,6 +37,7 @@ extern struct zebra_privs_t zserv_privs; struct { u_int32_t rtseq; int fd; + int ioctl_fd; } kr_state; static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label, @@ -330,6 +331,85 @@ int kernel_del_lsp(zebra_lsp_t *lsp) return ret; } +static int kmpw_install(struct zebra_pw *pw) +{ + struct ifreq ifr; + struct ifmpwreq imr; + struct sockaddr_storage ss; + struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; + struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; + + memset(&imr, 0, sizeof(imr)); + switch (pw->type) { + case PW_TYPE_ETHERNET: + imr.imr_type = IMR_TYPE_ETHERNET; + break; + case PW_TYPE_ETHERNET_TAGGED: + imr.imr_type = IMR_TYPE_ETHERNET_TAGGED; + break; + default: + zlog_err("%s: unhandled pseudowire type (%#X)", __func__, + pw->type); + return -1; + } + + if (pw->flags & F_PSEUDOWIRE_CWORD) + imr.imr_flags |= IMR_FLAG_CONTROLWORD; + + /* pseudowire nexthop */ + memset(&ss, 0, sizeof(ss)); + switch (pw->af) { + case AF_INET: + sa_in->sin_family = AF_INET; + sa_in->sin_len = sizeof(struct sockaddr_in); + sa_in->sin_addr = pw->nexthop.ipv4; + break; + case AF_INET6: + sa_in6->sin6_family = AF_INET6; + sa_in6->sin6_len = sizeof(struct sockaddr_in6); + sa_in6->sin6_addr = pw->nexthop.ipv6; + break; + default: + zlog_err("%s: unhandled pseudowire address-family (%u)", + __func__, pw->af); + return -1; + } + memcpy(&imr.imr_nexthop, (struct sockaddr *)&ss, + sizeof(imr.imr_nexthop)); + + /* pseudowire local/remote labels */ + imr.imr_lshim.shim_label = pw->local_label; + imr.imr_rshim.shim_label = pw->remote_label; + + /* ioctl */ + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name)); + ifr.ifr_data = (caddr_t)&imr; + if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) { + zlog_err("ioctl SIOCSETMPWCFG: %s", safe_strerror(errno)); + return -1; + } + + return 0; +} + +static int kmpw_uninstall(struct zebra_pw *pw) +{ + struct ifreq ifr; + struct ifmpwreq imr; + + memset(&ifr, 0, sizeof(ifr)); + memset(&imr, 0, sizeof(imr)); + strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name)); + ifr.ifr_data = (caddr_t)&imr; + if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) { + zlog_err("ioctl SIOCSETMPWCFG: %s", safe_strerror(errno)); + return -1; + } + + return 0; +} + #define MAX_RTSOCK_BUF 128 * 1024 int mpls_kernel_init(void) { @@ -341,6 +421,12 @@ int mpls_kernel_init(void) return -1; } + if ((kr_state.ioctl_fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0)) + == -1) { + zlog_warn("%s: ioctl socket", __func__); + return -1; + } + /* grow receive buffer, don't wanna miss messages */ optlen = sizeof(default_rcvbuf); if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF, &default_rcvbuf, @@ -359,6 +445,10 @@ int mpls_kernel_init(void) kr_state.rtseq = 1; + /* register hook to install/uninstall pseudowires */ + hook_register(pw_install, kmpw_install); + hook_register(pw_uninstall, kmpw_uninstall); + return 0; } -- 2.39.5