summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpd/kroute.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bgpd/kroute.c')
-rw-r--r--usr.sbin/bgpd/kroute.c141
1 files changed, 139 insertions, 2 deletions
diff --git a/usr.sbin/bgpd/kroute.c b/usr.sbin/bgpd/kroute.c
index 0bb1c9a2ea4..3403ed29607 100644
--- a/usr.sbin/bgpd/kroute.c
+++ b/usr.sbin/bgpd/kroute.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kroute.c,v 1.227 2018/12/28 22:05:15 denis Exp $ */
+/* $OpenBSD: kroute.c,v 1.228 2018/12/30 13:53:07 denis Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -93,9 +93,11 @@ struct ktable *ktable_get(u_int);
int kr4_change(struct ktable *, struct kroute_full *, u_int8_t);
int kr6_change(struct ktable *, struct kroute_full *, u_int8_t);
int krVPN4_change(struct ktable *, struct kroute_full *, u_int8_t);
+int krVPN6_change(struct ktable *, struct kroute_full *, u_int8_t);
int kr4_delete(struct ktable *, struct kroute_full *, u_int8_t);
int kr6_delete(struct ktable *, struct kroute_full *, u_int8_t);
int krVPN4_delete(struct ktable *, struct kroute_full *, u_int8_t);
+int krVPN6_delete(struct ktable *, struct kroute_full *, u_int8_t);
void kr_net_delete(struct network *);
struct network *kr_net_match(struct ktable *, struct kroute *);
struct network *kr_net_match6(struct ktable *, struct kroute6 *);
@@ -475,6 +477,8 @@ kr_change(u_int rtableid, struct kroute_full *kl, u_int8_t fib_prio)
return (kr6_change(kt, kl, fib_prio));
case AID_VPN_IPv4:
return (krVPN4_change(kt, kl, fib_prio));
+ case AID_VPN_IPv6:
+ return (krVPN6_change(kt, kl, fib_prio));
}
log_warnx("%s: not handled AID", __func__);
return (-1);
@@ -669,6 +673,81 @@ krVPN4_change(struct ktable *kt, struct kroute_full *kl, u_int8_t fib_prio)
}
int
+krVPN6_change(struct ktable *kt, struct kroute_full *kl, u_int8_t fib_prio)
+{
+ struct kroute6_node *kr6;
+ struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT;
+ int action = RTM_ADD;
+ u_int32_t mplslabel = 0;
+ u_int16_t labelid;
+
+ /* nexthop to loopback -> ignore silently */
+ if (IN6_IS_ADDR_LOOPBACK(&kl->nexthop.v6))
+ return (0);
+
+ /* only single MPLS label are supported for now */
+ if (kl->prefix.vpn6.labellen != 3) {
+ log_warnx("%s: %s/%u has not a single label", __func__,
+ log_addr(&kl->prefix), kl->prefixlen);
+ return (0);
+ }
+ mplslabel = (kl->prefix.vpn6.labelstack[0] << 24) |
+ (kl->prefix.vpn6.labelstack[1] << 16) |
+ (kl->prefix.vpn6.labelstack[2] << 8);
+ mplslabel = htonl(mplslabel);
+
+ /* for blackhole and reject routes nexthop needs to be ::1 */
+ if (kl->flags & (F_BLACKHOLE|F_REJECT))
+ bcopy(&lo6, &kl->nexthop.v6, sizeof(kl->nexthop.v6));
+
+ labelid = rtlabel_name2id(kl->label);
+
+ if ((kr6 = kroute6_find(kt, &kl->prefix.vpn6.addr, kl->prefixlen,
+ fib_prio)) != NULL)
+ action = RTM_CHANGE;
+
+ if (action == RTM_ADD) {
+ if ((kr6 = calloc(1, sizeof(struct kroute6_node))) == NULL) {
+ log_warn("%s", __func__);
+ return (-1);
+ }
+ memcpy(&kr6->r.prefix, &kl->prefix.vpn6.addr,
+ sizeof(struct in6_addr));
+ kr6->r.prefixlen = kl->prefixlen;
+ memcpy(&kr6->r.nexthop, &kl->nexthop.v6,
+ sizeof(struct in6_addr));
+ kr6->r.flags = kl->flags | F_BGPD_INSERTED | F_MPLS;
+ kr6->r.priority = fib_prio;
+ kr6->r.labelid = labelid;
+ kr6->r.mplslabel = mplslabel;
+
+ if (kroute6_insert(kt, kr6) == -1) {
+ free(kr6);
+ return (-1);
+ }
+ } else {
+ kr6->r.mplslabel = mplslabel;
+ memcpy(&kr6->r.nexthop, &kl->nexthop.v6,
+ sizeof(struct in6_addr));
+ rtlabel_unref(kr6->r.labelid);
+ kr6->r.labelid = labelid;
+ if (kl->flags & F_BLACKHOLE)
+ kr6->r.flags |= F_BLACKHOLE;
+ else
+ kr6->r.flags &= ~F_BLACKHOLE;
+ if (kl->flags & F_REJECT)
+ kr6->r.flags |= F_REJECT;
+ else
+ kr6->r.flags &= ~F_REJECT;
+ }
+
+ if (send_rt6msg(kr_state.fd, action, kt, &kr6->r, fib_prio) == -1)
+ return (-1);
+
+ return (0);
+}
+
+int
kr_delete(u_int rtableid, struct kroute_full *kl, u_int8_t fib_prio)
{
struct ktable *kt;
@@ -684,6 +763,8 @@ kr_delete(u_int rtableid, struct kroute_full *kl, u_int8_t fib_prio)
return (kr6_delete(kt, kl, fib_prio));
case AID_VPN_IPv4:
return (krVPN4_delete(kt, kl, fib_prio));
+ case AID_VPN_IPv6:
+ return (krVPN6_delete(kt, kl, fib_prio));
}
log_warnx("%s: not handled AID", __func__);
return (-1);
@@ -758,6 +839,29 @@ krVPN4_delete(struct ktable *kt, struct kroute_full *kl, u_int8_t fib_prio)
return (0);
}
+int
+krVPN6_delete(struct ktable *kt, struct kroute_full *kl, u_int8_t fib_prio)
+{
+ struct kroute6_node *kr6;
+
+ if ((kr6 = kroute6_find(kt, &kl->prefix.vpn6.addr, kl->prefixlen,
+ fib_prio)) == NULL)
+ return (0);
+
+ if (!(kr6->r.flags & F_BGPD_INSERTED))
+ return (0);
+
+ if (send_rt6msg(kr_state.fd, RTM_DELETE, kt, &kr6->r, fib_prio) == -1)
+ return (-1);
+
+ rtlabel_unref(kr6->r.labelid);
+
+ if (kroute6_remove(kt, kr6) == -1)
+ return (-1);
+
+ return (0);
+}
+
void
kr_shutdown(u_int8_t fib_prio, u_int rdomain)
{
@@ -2723,13 +2827,18 @@ int
send_rt6msg(int fd, int action, struct ktable *kt, struct kroute6 *kroute,
u_int8_t fib_prio)
{
- struct iovec iov[5];
+ struct iovec iov[7];
struct rt_msghdr hdr;
struct pad {
struct sockaddr_in6 addr;
char pad[sizeof(long)];
} prefix, nexthop, mask;
+ struct {
+ struct sockaddr_dl dl;
+ char pad[sizeof(long)];
+ } ifp;
struct sockaddr_rtlabel label;
+ struct sockaddr_mpls mpls;
int iovcnt = 0;
if (!kt->fib_sync)
@@ -2793,6 +2902,34 @@ send_rt6msg(int fd, int action, struct ktable *kt, struct kroute6 *kroute,
iov[iovcnt].iov_base = &mask;
iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6));
+ if (kt->ifindex) {
+ memset(&ifp, 0, sizeof(ifp));
+ ifp.dl.sdl_len = sizeof(struct sockaddr_dl);
+ ifp.dl.sdl_family = AF_LINK;
+ ifp.dl.sdl_index = kt->ifindex;
+ hdr.rtm_addrs |= RTA_IFP;
+ hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_dl));
+ iov[iovcnt].iov_base = &ifp;
+ iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_dl));
+ }
+
+ if (kroute->flags & F_MPLS) {
+ memset(&mpls, 0, sizeof(mpls));
+ mpls.smpls_len = sizeof(mpls);
+ mpls.smpls_family = AF_MPLS;
+ mpls.smpls_label = kroute->mplslabel;
+ /* adjust header */
+ hdr.rtm_flags |= RTF_MPLS;
+ hdr.rtm_mpls = MPLS_OP_PUSH;
+ hdr.rtm_addrs |= RTA_SRC;
+ hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_mpls));
+ /* clear gateway flag since this is for mpe(4) */
+ hdr.rtm_flags &= ~RTF_GATEWAY;
+ /* adjust iovec */
+ iov[iovcnt].iov_base = &mpls;
+ iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_mpls));
+ }
+
if (kroute->labelid) {
bzero(&label, sizeof(label));
label.sr_len = sizeof(label);