diff options
author | Renato Westphal <renato@cvs.openbsd.org> | 2015-07-21 04:52:30 +0000 |
---|---|---|
committer | Renato Westphal <renato@cvs.openbsd.org> | 2015-07-21 04:52:30 +0000 |
commit | a2ae921ed55c91e98ece8ee7f0b365851fb30633 (patch) | |
tree | 40369cff7366d5b45e4df63f807681b223eb63f8 /usr.sbin/ldpd/kroute.c | |
parent | 6e1f964c76fe64a2e4d55765a578dbb338c18266 (diff) |
VPLS signaling support.
This patch introduces full support for pseudowire signaling in ldpd(8),
including Control Word and Status TLV negotiation.
As of now it's not possible to configure a VPWS, but the signaling is
the same. In the future, when VPWS support is available in the kernel,
ldpd(8) can be extended to support VPWS with only a few modifications.
Limitations:
* No support for FEC 129, only FEC 128 (more widely deployed);
* No support for group withdraws (not widely deployed);
* No support for MAC withdraws (not widely deployed).
Related RFCs:
* RFC 3916: Requirements for Pseudo-Wire Emulation Edge-to-Edge (PWE3)
* RFC 3985: Pseudo Wire Emulation Edge-to-Edge (PWE3) Architecture
* RFC 4385: Pseudowire Emulation Edge-to-Edge (PWE3) Control Word for
Use over an MPLS PSN
* RFC 4446: IANA Allocations for Pseudowire Edge to Edge Emulation (PWE3)
* RFC 4447: Pseudowire Setup and Maintenance Using the Label Distribution
Protocol (LDP)
* RFC 4448: Encapsulation Methods for Transport of Ethernet over MPLS
Networks
* RFC 4905: Encapsulation Methods for Transport of Layer 2 Frames over
MPLS Networks
* RFC 4906: Transport of Layer 2 Frames Over MPLS
ok claudio@
Diffstat (limited to 'usr.sbin/ldpd/kroute.c')
-rw-r--r-- | usr.sbin/ldpd/kroute.c | 115 |
1 files changed, 114 insertions, 1 deletions
diff --git a/usr.sbin/ldpd/kroute.c b/usr.sbin/ldpd/kroute.c index d29500611dc..2f94690fb97 100644 --- a/usr.sbin/ldpd/kroute.c +++ b/usr.sbin/ldpd/kroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kroute.c,v 1.45 2015/07/21 04:43:28 renato Exp $ */ +/* $OpenBSD: kroute.c,v 1.46 2015/07/21 04:52:29 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -20,6 +20,7 @@ #include <sys/types.h> #include <sys/socket.h> +#include <sys/ioctl.h> #include <sys/sysctl.h> #include <sys/tree.h> #include <sys/uio.h> @@ -47,6 +48,7 @@ struct { pid_t pid; int fib_sync; int fd; + int ioctl_fd; struct event ev; } kr_state; @@ -79,6 +81,7 @@ struct kif_node { RB_ENTRY(kif_node) entry; TAILQ_HEAD(, kif_addr) addrs; struct kif k; + struct kpw *kpw; }; void kr_redist_remove(struct kroute *); @@ -208,6 +211,12 @@ kr_init(int fs) kr_dispatch_msg, NULL); event_add(&kr_state.ev, NULL); + if ((kr_state.ioctl_fd = socket(AF_INET, + SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1) { + log_warn("kr_init: ioctl socket"); + return (-1); + } + return (0); } @@ -294,6 +303,7 @@ kr_fib_couple(void) struct kroute_prefix *kp; struct kroute_priority *kprio; struct kroute_node *kn; + struct kif_node *kif; if (kr_state.fib_sync == 1) /* already coupled */ return; @@ -319,6 +329,10 @@ kr_fib_couple(void) } } + RB_FOREACH(kif, kif_tree, &kit) + if (kif->kpw) + kmpw_install(kif->k.ifname, kif->kpw); + log_info("kernel routing table coupled"); } @@ -329,6 +343,7 @@ kr_fib_decouple(void) struct kroute_priority *kprio; struct kroute_node *kn; u_int32_t rl; + struct kif_node *kif; if (kr_state.fib_sync == 0) /* already decoupled */ return; @@ -356,6 +371,10 @@ kr_fib_decouple(void) } } + RB_FOREACH(kif, kif_tree, &kit) + if (kif->kpw) + kmpw_uninstall(kif->k.ifname, kif->kpw); + kr_state.fib_sync = 0; log_info("kernel routing table decoupled"); } @@ -1427,3 +1446,97 @@ rtmsg_process(char *buf, size_t len) return (offset); } + +void +kmpw_set(struct kpw *kpw) +{ + struct kif_node *kif; + + kif = kif_find(kpw->ifindex); + if (kif == NULL) { + log_warn("kmpw_set: failed to find mpw by index (%u)", + kpw->ifindex); + return; + } + + if (kif->kpw == NULL) + kif->kpw = malloc(sizeof(*kif->kpw)); + memcpy(kif->kpw, kpw, sizeof(*kif->kpw)); + + kmpw_install(kif->k.ifname, kpw); +} + +void +kmpw_unset(struct kpw *kpw) +{ + struct kif_node *kif; + + kif = kif_find(kpw->ifindex); + if (kif == NULL) { + log_warn("kmpw_unset: failed to find mpw by index (%u)", + kpw->ifindex); + return; + } + + if (kif->kpw == NULL) { + log_warn("kmpw_unset: %s is not set", kif->k.ifname); + return; + } + + free(kif->kpw); + kif->kpw = NULL; + kmpw_uninstall(kif->k.ifname, kpw); +} + +void +kmpw_install(const char *ifname, struct kpw *kpw) +{ + struct sockaddr_in *sin; + struct ifreq ifr; + struct ifmpwreq imr; + + memset(&imr, 0, sizeof(imr)); + switch (kpw->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: + log_warn("kmpw_install: unhandled pseudowire type (%#X)", + kpw->pw_type); + } + + if (kpw->flags & F_PW_CONTROLWORD) + imr.imr_flags |= IMR_FLAG_CONTROLWORD; + + sin = (struct sockaddr_in *) &imr.imr_nexthop; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = kpw->nexthop.s_addr; + sin->sin_len = sizeof(struct sockaddr_in); + + imr.imr_lshim.shim_label = kpw->local_label; + imr.imr_rshim.shim_label = kpw->remote_label; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + ifr.ifr_data = (caddr_t) &imr; + if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr)) + log_warn("ioctl SETMPWCFG"); +} + +void +kmpw_uninstall(const char *ifname, struct kpw *kpw) +{ + struct ifreq ifr; + struct ifmpwreq imr; + + memset(&imr, 0, sizeof(imr)); + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + ifr.ifr_data = (caddr_t) &imr; + if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr)) + log_warn("ioctl SETMPWCFG"); +} |