summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/bgpd/bgpd.815
-rw-r--r--usr.sbin/bgpd/bgpd.c143
-rw-r--r--usr.sbin/bgpd/bgpd.conf.5124
-rw-r--r--usr.sbin/bgpd/bgpd.h52
-rw-r--r--usr.sbin/bgpd/config.c30
-rw-r--r--usr.sbin/bgpd/kroute.c427
-rw-r--r--usr.sbin/bgpd/parse.y248
-rw-r--r--usr.sbin/bgpd/printconf.c101
-rw-r--r--usr.sbin/bgpd/rde.c221
-rw-r--r--usr.sbin/bgpd/session.h8
10 files changed, 1052 insertions, 317 deletions
diff --git a/usr.sbin/bgpd/bgpd.8 b/usr.sbin/bgpd/bgpd.8
index 9597aa1f118..868e5524531 100644
--- a/usr.sbin/bgpd/bgpd.8
+++ b/usr.sbin/bgpd/bgpd.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: bgpd.8,v 1.34 2010/02/23 21:30:40 schwarze Exp $
+.\" $OpenBSD: bgpd.8,v 1.35 2010/05/17 15:49:29 claudio Exp $
.\"
.\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: February 23 2010 $
+.Dd $Mdocdate: May 17 2010 $
.Dt BGPD 8
.Os
.Sh NAME
@@ -42,7 +42,7 @@ concerning
with other BGP systems.
.Nm
uses the Border Gateway Protocol, Version 4,
-as described in RFC 1771.
+as described in RFC 4271/1771.
Please refer to that document for more information about BGP.
.Pp
.Nm
@@ -150,9 +150,9 @@ control socket
.Xr bgplg 8 ,
.Xr bgplgsh 8
.Rs
-.%R RFC 1771
+.%R RFC 4271
.%T "A Border Gateway Protocol 4 (BGP-4)"
-.%D March 1995
+.%D January 2006
.Re
.Rs
.%R RFC 1997
@@ -195,6 +195,11 @@ control socket
.%D February 2006
.Re
.Rs
+.%R RFC 4364
+.%T "BGP/MPLS IP Virtual Private Networks (VPNs)"
+.%D February 2006
+.Re
+.Rs
.%R RFC 4486
.%T "BGP Cease Notification Message Subcodes"
.%D April 2006
diff --git a/usr.sbin/bgpd/bgpd.c b/usr.sbin/bgpd/bgpd.c
index 2d34db752be..0c3c610a172 100644
--- a/usr.sbin/bgpd/bgpd.c
+++ b/usr.sbin/bgpd/bgpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.c,v 1.161 2010/05/03 13:09:38 claudio Exp $ */
+/* $OpenBSD: bgpd.c,v 1.162 2010/05/17 15:49:29 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -46,16 +46,12 @@ int reconfigure(char *, struct bgpd_config *, struct mrt_head *,
int dispatch_imsg(struct imsgbuf *, int);
int rfd = -1;
-int cflags = 0;
-struct filter_set_head *connectset;
-struct filter_set_head *connectset6;
-struct filter_set_head *staticset;
-struct filter_set_head *staticset6;
-volatile sig_atomic_t mrtdump = 0;
-volatile sig_atomic_t quit = 0;
-volatile sig_atomic_t sigchld = 0;
-volatile sig_atomic_t reconfig = 0;
-pid_t reconfpid = 0;
+int cflags;
+volatile sig_atomic_t mrtdump;
+volatile sig_atomic_t quit;
+volatile sig_atomic_t sigchld;
+volatile sig_atomic_t reconfig;
+pid_t reconfpid;
struct imsgbuf *ibuf_se;
struct imsgbuf *ibuf_rde;
struct rib_names ribnames = SIMPLEQ_HEAD_INITIALIZER(ribnames);
@@ -169,24 +165,20 @@ main(int argc, char *argv[])
if (conf.opts & BGPD_OPT_NOACTION) {
struct network_head net_l;
+ struct rdomain_head rdom_l;
struct filter_head rules_l;
if (parse_config(conffile, &conf, &mrt_l, &peer_l, &net_l,
- &rules_l))
+ &rules_l, &rdom_l))
exit(1);
if (conf.opts & BGPD_OPT_VERBOSE)
print_config(&conf, &ribnames, &net_l, peer_l, &rules_l,
- &mrt_l);
+ &mrt_l, &rdom_l);
else
fprintf(stderr, "configuration OK\n");
exit(0);
}
- cflags = conf.flags;
- connectset = &conf.connectset;
- staticset = &conf.staticset;
- connectset6 = &conf.connectset6;
- staticset6 = &conf.staticset6;
if (geteuid())
errx(1, "need root privileges");
@@ -423,25 +415,22 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l,
struct peer **peer_l)
{
struct network_head net_l;
+ struct rdomain_head rdom_l;
struct filter_head rules_l;
- struct network *n;
struct peer *p;
struct filter_rule *r;
struct listen_addr *la;
struct rde_rib *rr;
+ struct rdomain *rd;
- if (parse_config(conffile, conf, mrt_l, peer_l, &net_l, &rules_l)) {
+ if (parse_config(conffile, conf, mrt_l, peer_l, &net_l, &rules_l,
+ &rdom_l)) {
log_warnx("config file %s has errors, not reloading",
conffile);
return (1);
}
cflags = conf->flags;
- connectset = &conf->connectset;
- staticset = &conf->staticset;
- connectset6 = &conf->connectset6;
- staticset6 = &conf->staticset6;
-
prepare_listeners(conf);
/* start reconfiguration */
@@ -472,7 +461,8 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l,
/* RIBs for the RDE */
while ((rr = SIMPLEQ_FIRST(&ribnames))) {
SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
- if (ktable_update(rr) == -1) {
+ if (ktable_update(rr->rtableid, rr->name, NULL,
+ rr->flags) == -1) {
log_warnx("failed to load rdomain %d",
rr->rtableid);
return (-1);
@@ -483,33 +473,61 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l,
free(rr);
}
- /* networks for the RDE */
- while ((n = TAILQ_FIRST(&net_l)) != NULL) {
- if (imsg_compose(ibuf_rde, IMSG_NETWORK_ADD, 0, 0, -1,
- &n->net, sizeof(struct network_config)) == -1)
- return (-1);
- if (send_filterset(ibuf_rde, &n->net.attrset) == -1)
- return (-1);
- if (imsg_compose(ibuf_rde, IMSG_NETWORK_DONE, 0, 0, -1,
- NULL, 0) == -1)
- return (-1);
- TAILQ_REMOVE(&net_l, n, entry);
- filterset_free(&n->net.attrset);
- free(n);
- }
+ /* networks go via kroute to the RDE */
+ if (kr_net_reload(0, &net_l))
+ return (-1);
/* filters for the RDE */
while ((r = TAILQ_FIRST(&rules_l)) != NULL) {
+ TAILQ_REMOVE(&rules_l, r, entry);
if (imsg_compose(ibuf_rde, IMSG_RECONF_FILTER, 0, 0, -1,
r, sizeof(struct filter_rule)) == -1)
return (-1);
if (send_filterset(ibuf_rde, &r->set) == -1)
return (-1);
- TAILQ_REMOVE(&rules_l, r, entry);
filterset_free(&r->set);
free(r);
}
+ while ((rd = SIMPLEQ_FIRST(&rdom_l)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&rdom_l, entry);
+ if (ktable_update(rd->rtableid, rd->descr, rd->ifmpe,
+ rd->flags) == -1) {
+ log_warnx("failed to load rdomain %d",
+ rd->rtableid);
+ return (-1);
+ }
+ /* networks go via kroute to the RDE */
+ if (kr_net_reload(rd->rtableid, &rd->net_l))
+ return (-1);
+
+ if (imsg_compose(ibuf_rde, IMSG_RECONF_RDOMAIN, 0, 0, -1,
+ rd, sizeof(*rd)) == -1)
+ return (-1);
+
+ /* export targets */
+ if (imsg_compose(ibuf_rde, IMSG_RECONF_RDOMAIN_EXPORT, 0, 0,
+ -1, NULL, 0) == -1)
+ return (-1);
+ if (send_filterset(ibuf_rde, &rd->export) == -1)
+ return (-1);
+ filterset_free(&rd->export);
+
+ /* import targets */
+ if (imsg_compose(ibuf_rde, IMSG_RECONF_RDOMAIN_IMPORT, 0, 0,
+ -1, NULL, 0) == -1)
+ return (-1);
+ if (send_filterset(ibuf_rde, &rd->import) == -1)
+ return (-1);
+ filterset_free(&rd->import);
+
+ if (imsg_compose(ibuf_rde, IMSG_RECONF_RDOMAIN_DONE, 0, 0,
+ -1, NULL, 0) == -1)
+ return (-1);
+
+ free(rd);
+ }
+
/* signal both childs to replace their config */
if (imsg_compose(ibuf_se, IMSG_RECONF_DONE, 0, 0, -1, NULL, 0) == -1 ||
imsg_compose(ibuf_rde, IMSG_RECONF_DONE, 0, 0, -1, NULL, 0) == -1)
@@ -713,55 +731,20 @@ send_imsg_session(int type, pid_t pid, void *data, u_int16_t datalen)
}
int
-bgpd_redistribute(int type, struct kroute *kr, struct kroute6 *kr6)
+send_network(int type, struct network_config *net, struct filter_set_head *h)
{
- struct network_config net;
- struct filter_set_head *h;
-
- if ((cflags & BGPD_FLAG_REDIST_CONNECTED) && kr &&
- (kr->flags & F_CONNECTED))
- h = connectset;
- else if ((cflags & BGPD_FLAG_REDIST_STATIC) && kr &&
- (kr->flags & F_STATIC))
- h = staticset;
- else if ((cflags & BGPD_FLAG_REDIST6_CONNECTED) && kr6 &&
- (kr6->flags & F_CONNECTED))
- h = connectset6;
- else if ((cflags & BGPD_FLAG_REDIST6_STATIC) && kr6 &&
- (kr6->flags & F_STATIC))
- h = staticset6;
- else
- return (0);
-
- bzero(&net, sizeof(net));
- if (kr && kr6)
- fatalx("bgpd_redistribute: unable to redistribute v4 and v6"
- "together");
- if (kr != NULL) {
- net.prefix.aid = AID_INET;
- net.prefix.v4.s_addr = kr->prefix.s_addr;
- net.prefixlen = kr->prefixlen;
- }
- if (kr6 != NULL) {
- net.prefix.aid = AID_INET6;
- memcpy(&net.prefix.v6, &kr6->prefix, sizeof(struct in6_addr));
- net.prefixlen = kr6->prefixlen;
- }
-
- if (imsg_compose(ibuf_rde, type, 0, 0, -1, &net,
+ if (imsg_compose(ibuf_rde, type, 0, 0, -1, net,
sizeof(struct network_config)) == -1)
return (-1);
-
/* networks that get deleted don't need to send the filter set */
if (type == IMSG_NETWORK_REMOVE)
- return (1);
-
+ return (0);
if (send_filterset(ibuf_rde, h) == -1)
return (-1);
if (imsg_compose(ibuf_rde, IMSG_NETWORK_DONE, 0, 0, -1, NULL, 0) == -1)
return (-1);
- return (1);
+ return (0);
}
int
diff --git a/usr.sbin/bgpd/bgpd.conf.5 b/usr.sbin/bgpd/bgpd.conf.5
index b4d8738e1c7..5ae88b70442 100644
--- a/usr.sbin/bgpd/bgpd.conf.5
+++ b/usr.sbin/bgpd/bgpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: bgpd.conf.5,v 1.106 2010/05/04 07:37:56 claudio Exp $
+.\" $OpenBSD: bgpd.conf.5,v 1.107 2010/05/17 15:49:29 claudio Exp $
.\"
.\" Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
.\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: May 4 2010 $
+.Dd $Mdocdate: May 17 2010 $
.Dt BGPD.CONF 5
.Os
.Sh NAME
@@ -26,7 +26,7 @@
The
.Xr bgpd 8
daemon implements the Border Gateway Protocol version 4 as described
-in RFC 1771.
+in RFC 4271.
.Sh SECTIONS
The
.Nm
@@ -38,6 +38,8 @@ configuration file.
.It Sy Global Configuration
Global settings for
.Xr bgpd 8 .
+.It Sy Routing Domain Configuration
+The definition and properties for BGP MPLS VPNs are set in this section.
.It Sy Neighbors and Groups
.Xr bgpd 8
establishes sessions with
@@ -390,6 +392,111 @@ to EBGP neighbors are not prepended with their own AS.
The default is
.Ic no .
.El
+.Sh ROUTING DOMAIN CONFIGURATION
+.Xr bgpd 8
+supports the setup and distribution of Virtual Private Networks.
+It is possible to import and export prefixes between routing domains.
+Each routing domain is specified by a
+.Ic rdomain
+section, which allows properties to be set specifically for that rdomain:
+.Bd -literal -offset indent
+rdomain 1 {
+ descr "a rdomain"
+ rd 65002:1
+ import-target rt 65002:42
+ export-target rt 65002:42
+ network 192.168.1/24
+ depend on mpe0
+}
+.Ed
+.Pp
+There are several routing domain properties:
+.Pp
+.Bl -tag -width Ds -compact
+.It Ic depend on Ar interface
+Routes added to the rdomain will use this this interface as outgoing interface.
+Normaly this will be a MPLS Provider Edge,
+.Xr mpe 4 ,
+interface that is part of the rdomain.
+Local networks will be announced with the MPLS label specified on the interface.
+.Pp
+.It Ic descr Ar description
+Add a description.
+The description is used when logging but has no further meaning to
+.Xr bgpd 8 .
+.Pp
+.It Ic export-target Ar subtype Ar as-number Ns Li : Ns Ar local
+.It Ic export-target Ar subtype Ar IP Ns Li : Ns Ar local
+Specify an extended community which will be attached to announced networks.
+More than one
+.Ic export-target
+can be specified.
+See also the
+.Sx ATTRIBUTE SET
+section for further information about the encoding.
+The
+.Ar subtype
+should be set to
+.Ar rt
+for best compatibility with other implementations.
+.Pp
+.It Xo
+.Ic fib-update
+.Pq Ic yes Ns \&| Ns Ic no
+.Xc
+If set to
+.Ic no ,
+do not update the Forwarding Information Base, a.k.a. the kernel
+routing table.
+The default is
+.Ic yes .
+.Pp
+.It Ic import-target Ar subtype Ar as-number Ns Li : Ns Ar local
+.It Ic import-target Ar subtype Ar IP Ns Li : Ns Ar local
+Only prefixes matching one of the specified
+.Ic import-targets
+will be imported into the rdomain.
+More than one
+.Ic import-target
+can be specified.
+See also the
+.Sx ATTRIBUTE SET
+section for further information about the encoding of extended communities.
+The
+.Ar subtype
+should be set to
+.Ar rt
+for best compatibility with other implementations.
+.Pp
+.It Ic network Ar arguments ...
+Define which networks should be exported into this VPN.
+See also the
+.Ic nexthop
+section in
+.Sx GLOBAL CONFIGURATION
+for further information about the arguments.
+.Pp
+.It Ic rd Ar as-number Ns Li : Ns Ar local
+.It Ic rd Ar IP Ns Li : Ns Ar local
+The Route Distinguishers uniquely identifies a set of VPN prefixes.
+Only prefixes matching the
+.Ic rd
+will be imported into the routing domain.
+The purpose of the
+.Ic rd
+is solely to allow one to create distinct routes to a common address prefix.
+The
+.Ar as-number
+or
+.Ar IP
+of a
+.Ic rd
+should be set to a number or IP that was assigned by an appropriate authority.
+Whereas
+.Ar local
+can be chosen by the local operator.
+.Pp
+.El
.Sh NEIGHBORS AND GROUPS
.Xr bgpd 8
establishes TCP connections to other BGP speakers called
@@ -485,14 +592,17 @@ The default for IBGP peers is
.It Xo
.Ic announce
.Pq Ic IPv4 Ns \&| Ns Ic IPv6
-.Pq Ic none Ns \&| Ns Ic unicast
+.Pq Ic none Ns \&| Ns Ic unicast Ns \&| Ns Ic vpn
.Xc
For the given address family, control which subsequent address families
(at the moment, only
.Em none ,
-which disables the announcement of that address family, and
-.Em unicast
-are supported) are announced during the capabilities negotiation.
+which disables the announcement of that address family,
+.Em unicast ,
+and
+.Em vpn ,
+which allows the distribution of BGP MPLS VPNs, are supported) are announced
+during the capabilities negotiation.
Only routes for that address family and subsequent address family will be
announced and processed.
.Pp
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h
index 9511e96d2f0..1fb519acfef 100644
--- a/usr.sbin/bgpd/bgpd.h
+++ b/usr.sbin/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.258 2010/05/03 13:09:38 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.259 2010/05/17 15:49:29 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -55,10 +55,6 @@
#define BGPD_FLAG_NO_EVALUATE 0x0002
#define BGPD_FLAG_REFLECTOR 0x0004
-#define BGPD_FLAG_REDIST_STATIC 0x0008
-#define BGPD_FLAG_REDIST_CONNECTED 0x0010
-#define BGPD_FLAG_REDIST6_STATIC 0x0020
-#define BGPD_FLAG_REDIST6_CONNECTED 0x0040
#define BGPD_FLAG_NEXTHOP_BGP 0x0080
#define BGPD_FLAG_NEXTHOP_DEFAULT 0x1000
#define BGPD_FLAG_DECISION_MASK 0x0f00
@@ -80,6 +76,8 @@
#define F_REJECT 0x0080
#define F_BLACKHOLE 0x0100
#define F_LONGER 0x0200
+#define F_MPLS 0x0400
+#define F_REDISTRIBUTED 0x0800
#define F_CTL_DETAIL 0x1000 /* only used by bgpctl */
#define F_CTL_ADJ_IN 0x2000
#define F_CTL_ADJ_OUT 0x4000
@@ -194,17 +192,12 @@ TAILQ_HEAD(listen_addrs, listen_addr);
TAILQ_HEAD(filter_set_head, filter_set);
struct bgpd_config {
- struct filter_set_head connectset;
- struct filter_set_head connectset6;
- struct filter_set_head staticset;
- struct filter_set_head staticset6;
struct listen_addrs *listen_addrs;
char *csock;
char *rcsock;
int opts;
int flags;
int log;
- u_int rtableid;
u_int32_t bgpid;
u_int32_t clusterid;
u_int32_t as;
@@ -304,17 +297,26 @@ struct peer_config {
#define PEERFLAG_TRANS_AS 0x01
+enum network_type {
+ NETWORK_DEFAULT,
+ NETWORK_STATIC,
+ NETWORK_CONNECTED
+};
+
struct network_config {
struct bgpd_addr prefix;
struct filter_set_head attrset;
+ u_int rtableid;
+ enum network_type type;
u_int8_t prefixlen;
+ u_int8_t old; /* used for reloading */
};
TAILQ_HEAD(network_head, network);
struct network {
- struct network_config net;
- TAILQ_ENTRY(network) entry;
+ struct network_config net;
+ TAILQ_ENTRY(network) entry;
};
enum imsg_type {
@@ -354,6 +356,10 @@ enum imsg_type {
IMSG_RECONF_PEER,
IMSG_RECONF_FILTER,
IMSG_RECONF_LISTENER,
+ IMSG_RECONF_RDOMAIN,
+ IMSG_RECONF_RDOMAIN_EXPORT,
+ IMSG_RECONF_RDOMAIN_IMPORT,
+ IMSG_RECONF_RDOMAIN_DONE,
IMSG_RECONF_DONE,
IMSG_UPDATE,
IMSG_UPDATE_ERR,
@@ -432,7 +438,6 @@ enum suberr_cease {
struct kroute_node;
struct kroute6_node;
struct knexthop_node;
-struct redist_node;
RB_HEAD(kroute_tree, kroute_node);
RB_HEAD(kroute6_tree, kroute6_node);
RB_HEAD(knexthop_tree, knexthop_node);
@@ -444,7 +449,6 @@ struct ktable {
struct kroute6_tree krt6;
struct knexthop_tree knt;
struct network_head krn;
- LIST_HEAD(, redist_node) redistlist;
u_int rtableid;
u_int nhtableid; /* rdomain id for nexthop lookup */
u_int ifindex; /* ifindex of ifmpe */
@@ -467,6 +471,7 @@ struct kroute_full {
struct kroute {
struct in_addr prefix;
struct in_addr nexthop;
+ u_int32_t mplslabel;
u_int16_t flags;
u_int16_t labelid;
u_short ifindex;
@@ -786,6 +791,20 @@ struct filter_set {
enum action_types type;
};
+struct rdomain {
+ SIMPLEQ_ENTRY(rdomain) entry;
+ char descr[PEER_DESCR_LEN];
+ char ifmpe[IFNAMSIZ];
+ struct filter_set_head import;
+ struct filter_set_head export;
+ struct network_head net_l;
+ u_int64_t rd;
+ u_int rtableid;
+ u_int label;
+ int flags;
+};
+SIMPLEQ_HEAD(rdomain_head, rdomain);
+
struct rde_rib {
SIMPLEQ_ENTRY(rde_rib) entry;
char name[PEER_DESCR_LEN];
@@ -825,7 +844,8 @@ struct rde_memstats {
/* bgpd.c */
void send_nexthop_update(struct kroute_nexthop *);
void send_imsg_session(int, pid_t, void *, u_int16_t);
-int bgpd_redistribute(int, struct kroute *, struct kroute6 *);
+int send_network(int, struct network_config *,
+ struct filter_set_head *);
int bgpd_filternexthop(struct kroute *, struct kroute6 *);
/* log.c */
@@ -849,7 +869,7 @@ int host(const char *, struct bgpd_addr *, u_int8_t *);
/* kroute.c */
int kr_init(void);
-int ktable_update(struct rde_rib *);
+int ktable_update(u_int, char *, char *, int);
void ktable_preload(void);
void ktable_postload(void);
int ktable_exists(u_int, u_int *);
diff --git a/usr.sbin/bgpd/config.c b/usr.sbin/bgpd/config.c
index 5ac76924b78..da0be607bda 100644
--- a/usr.sbin/bgpd/config.c
+++ b/usr.sbin/bgpd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.52 2009/12/01 14:28:05 claudio Exp $ */
+/* $OpenBSD: config.c,v 1.53 2010/05/17 15:49:29 claudio Exp $ */
/*
* Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org>
@@ -20,6 +20,9 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <netmpls/mpls.h>
#include <errno.h>
#include <ifaddrs.h>
@@ -311,3 +314,28 @@ prepare_listeners(struct bgpd_config *conf)
}
}
}
+
+int
+get_mpe_label(struct rdomain *r)
+{
+ struct ifreq ifr;
+ struct shim_hdr shim;
+ int s;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s == -1)
+ return (-1);
+
+ bzero(&shim, sizeof(shim));
+ bzero(&ifr, sizeof(ifr));
+ strlcpy(ifr.ifr_name, r->ifmpe, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (caddr_t)&shim;
+
+ if (ioctl(s, SIOCGETLABEL , (caddr_t)&ifr) == -1) {
+ close(s);
+ return (-1);
+ }
+ close(s);
+ r->label = shim.shim_label;
+ return (0);
+}
diff --git a/usr.sbin/bgpd/kroute.c b/usr.sbin/bgpd/kroute.c
index fd7984fd23b..9dbe2a13ce7 100644
--- a/usr.sbin/bgpd/kroute.c
+++ b/usr.sbin/bgpd/kroute.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kroute.c,v 1.178 2010/05/03 13:09:38 claudio Exp $ */
+/* $OpenBSD: kroute.c,v 1.179 2010/05/17 15:49:29 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -27,6 +27,7 @@
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
+#include <netmpls/mpls.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
@@ -91,8 +92,10 @@ struct ktable *ktable_get(u_int);
int kr4_change(struct ktable *, struct kroute_full *);
int kr6_change(struct ktable *, struct kroute_full *);
+int krVPN4_change(struct ktable *, struct kroute_full *);
int kr4_delete(struct ktable *, struct kroute_full *);
int kr6_delete(struct ktable *, struct kroute_full *);
+int krVPN4_delete(struct ktable *, struct kroute_full *);
void kr_net_delete(struct network *);
struct network *kr_net_match(struct ktable *, struct kroute *);
struct network *kr_net_match6(struct ktable *, struct kroute6 *);
@@ -262,7 +265,6 @@ ktable_new(u_int rtableid, u_int rdomid, char *name, char *ifname, int fs)
RB_INIT(&kt->krt6);
RB_INIT(&kt->knt);
TAILQ_INIT(&kt->krn);
- LIST_INIT(&kt->redistlist);
kt->fib_conf = kt->fib_sync = fs;
kt->rtableid = rtableid;
kt->nhtableid = rdomid;
@@ -338,15 +340,15 @@ ktable_get(u_int rtableid)
}
int
-ktable_update(struct rde_rib *rr)
+ktable_update(u_int rtableid, char *name, char *ifname, int flags)
{
struct ktable *kt, *rkt;
u_int rdomid;
- if (!ktable_exists(rr->rtableid, &rdomid))
+ if (!ktable_exists(rtableid, &rdomid))
fatalx("King Bula lost a table"); /* may not happen */
- if (rdomid != rr->rtableid || rr->flags & F_RIB_NOFIB) {
+ if (rdomid != rtableid || flags & F_RIB_NOFIB) {
rkt = ktable_get(rdomid);
if (rkt == NULL) {
char buf[32];
@@ -363,21 +365,21 @@ ktable_update(struct rde_rib *rr)
}
}
- if (rr->flags & (F_RIB_NOEVALUATE | F_RIB_NOFIB))
+ if (flags & (F_RIB_NOEVALUATE | F_RIB_NOFIB))
/* only rdomain table must exist */
return (0);
- kt = ktable_get(rr->rtableid);
+ kt = ktable_get(rtableid);
if (kt == NULL) {
- if (ktable_new(rr->rtableid, rdomid, rr->name, NULL,
- !(rr->flags & F_RIB_NOFIBSYNC)))
+ if (ktable_new(rtableid, rdomid, name, ifname,
+ !(flags & F_RIB_NOFIBSYNC)))
return (-1);
} else {
/* fib sync has higher preference then no sync */
if (kt->state == RECONF_DELETE)
- kt->fib_conf = !(rr->flags & F_RIB_NOFIBSYNC);
+ kt->fib_conf = !(flags & F_RIB_NOFIBSYNC);
else if (!kt->fib_conf)
- kt->fib_conf = !(rr->flags & F_RIB_NOFIBSYNC);
+ kt->fib_conf = !(flags & F_RIB_NOFIBSYNC);
kt->state = RECONF_KEEP;
}
@@ -452,6 +454,8 @@ kr_change(u_int rtableid, struct kroute_full *kl)
return (kr4_change(kt, kl));
case AID_INET6:
return (kr6_change(kt, kl));
+ case AID_VPN_IPv4:
+ return (krVPN4_change(kt, kl));
}
log_warnx("kr_change: not handled AID");
return (-1);
@@ -572,6 +576,76 @@ kr6_change(struct ktable *kt, struct kroute_full *kl)
}
int
+krVPN4_change(struct ktable *kt, struct kroute_full *kl)
+{
+ struct kroute_node *kr;
+ int action = RTM_ADD;
+ u_int32_t mplslabel = 0;
+ u_int16_t labelid;
+
+ if ((kr = kroute_find(kt, kl->prefix.vpn4.addr.s_addr, kl->prefixlen,
+ RTP_BGP)) != NULL)
+ action = RTM_CHANGE;
+
+ /* nexthop within 127/8 -> ignore silently */
+ if ((kl->nexthop.v4.s_addr & htonl(IN_CLASSA_NET)) ==
+ htonl(INADDR_LOOPBACK & IN_CLASSA_NET))
+ return (0);
+
+ /* only single MPLS label are supported for now */
+ if (kl->prefix.vpn4.labellen != 3) {
+ log_warnx("krVPN4_change: %s/%u has not a single label",
+ log_addr(&kl->prefix), kl->prefixlen);
+ return (0);
+ }
+ mplslabel = (kl->prefix.vpn4.labelstack[0] << 24) |
+ (kl->prefix.vpn4.labelstack[1] << 16) |
+ (kl->prefix.vpn4.labelstack[2] << 8);
+ mplslabel = htonl(mplslabel);
+
+ labelid = rtlabel_name2id(kl->label);
+
+ /* for blackhole and reject routes nexthop needs to be 127.0.0.1 */
+ if (kl->flags & (F_BLACKHOLE|F_REJECT))
+ kl->nexthop.v4.s_addr = htonl(INADDR_LOOPBACK);
+
+ if (action == RTM_ADD) {
+ if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) {
+ log_warn("kr_change");
+ return (-1);
+ }
+ kr->r.prefix.s_addr = kl->prefix.vpn4.addr.s_addr;
+ kr->r.prefixlen = kl->prefixlen;
+ kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr;
+ kr->r.flags = kl->flags | F_BGPD_INSERTED | F_MPLS;
+ kr->r.priority = RTP_BGP;
+ kr->r.labelid = labelid;
+ kr->r.mplslabel = mplslabel;
+
+ if (kroute_insert(kt, kr) == -1)
+ free(kr);
+ } else {
+ kr->r.mplslabel = mplslabel;
+ kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr;
+ rtlabel_unref(kr->r.labelid);
+ kr->r.labelid = labelid;
+ if (kl->flags & F_BLACKHOLE)
+ kr->r.flags |= F_BLACKHOLE;
+ else
+ kr->r.flags &= ~F_BLACKHOLE;
+ if (kl->flags & F_REJECT)
+ kr->r.flags |= F_REJECT;
+ else
+ kr->r.flags &= ~F_REJECT;
+ }
+
+ if (send_rtmsg(kr_state.fd, action, kt, &kr->r) == -1)
+ return (-1);
+
+ return (0);
+}
+
+int
kr_delete(u_int rtableid, struct kroute_full *kl)
{
struct ktable *kt;
@@ -585,6 +659,8 @@ kr_delete(u_int rtableid, struct kroute_full *kl)
return (kr4_delete(kt, kl));
case AID_INET6:
return (kr6_delete(kt, kl));
+ case AID_VPN_IPv4:
+ return (krVPN4_delete(kt, kl));
}
log_warnx("kr_change: not handled AID");
return (-1);
@@ -636,6 +712,29 @@ kr6_delete(struct ktable *kt, struct kroute_full *kl)
return (0);
}
+int
+krVPN4_delete(struct ktable *kt, struct kroute_full *kl)
+{
+ struct kroute_node *kr;
+
+ if ((kr = kroute_find(kt, kl->prefix.vpn4.addr.s_addr, kl->prefixlen,
+ RTP_BGP)) == NULL)
+ return (0);
+
+ if (!(kr->r.flags & F_BGPD_INSERTED))
+ return (0);
+
+ if (send_rtmsg(kr_state.fd, RTM_DELETE, kt, &kr->r) == -1)
+ return (-1);
+
+ rtlabel_unref(kr->r.labelid);
+
+ if (kroute_remove(kt, kr) == -1)
+ return (-1);
+
+ return (0);
+}
+
void
kr_shutdown(void)
{
@@ -919,7 +1018,6 @@ kr_show_route(struct imsg *imsg)
RB_INIT(&ktab.krt6);
RB_INIT(&ktab.knt);
TAILQ_INIT(&ktab.krn);
- LIST_INIT(&ktab.redistlist);
send_imsg_session(IMSG_CTL_SHOW_FIB_TABLES,
imsg->hdr.pid, &ktab, sizeof(ktab));
@@ -945,19 +1043,144 @@ kr_ifinfo(char *ifname)
}
}
-struct redist_node {
- LIST_ENTRY(redist_node) entry;
- struct kroute *kr;
- struct kroute6 *kr6;
-};
+void
+kr_net_delete(struct network *n)
+{
+ filterset_free(&n->net.attrset);
+ free(n);
+}
+struct network *
+kr_net_match(struct ktable *kt, struct kroute *kr)
+{
+ struct network *xn;
+
+ TAILQ_FOREACH(xn, &kt->krn, entry) {
+ if (xn->net.prefix.aid != AID_INET)
+ continue;
+ switch (xn->net.type) {
+ case NETWORK_DEFAULT:
+ if (xn->net.prefixlen == kr->prefixlen &&
+ xn->net.prefix.v4.s_addr == kr->prefix.s_addr)
+ /* static match already redistributed */
+ return (NULL);
+ break;
+ case NETWORK_STATIC:
+ if (kr->flags & F_STATIC)
+ return (xn);
+ break;
+ case NETWORK_CONNECTED:
+ if (kr->flags & F_CONNECTED)
+ return (xn);
+ break;
+ }
+ }
+ return (NULL);
+}
+
+struct network *
+kr_net_match6(struct ktable *kt, struct kroute6 *kr6)
+{
+ struct network *xn;
+
+ TAILQ_FOREACH(xn, &kt->krn, entry) {
+ if (xn->net.prefix.aid != AID_INET6)
+ continue;
+ switch (xn->net.type) {
+ case NETWORK_DEFAULT:
+ if (xn->net.prefixlen == kr6->prefixlen &&
+ memcmp(&xn->net.prefix.v6, &kr6->prefix,
+ sizeof(struct in6_addr)) == 0)
+ /* static match already redistributed */
+ return (NULL);
+ break;
+ case NETWORK_STATIC:
+ if (kr6->flags & F_STATIC)
+ return (xn);
+ break;
+ case NETWORK_CONNECTED:
+ if (kr6->flags & F_CONNECTED)
+ return (xn);
+ break;
+ }
+ }
+ return (NULL);
+}
+
+struct network *
+kr_net_find(struct ktable *kt, struct network *n)
+{
+ struct network *xn;
+
+ TAILQ_FOREACH(xn, &kt->krn, entry) {
+ if (n->net.type != xn->net.type ||
+ n->net.prefixlen != xn->net.prefixlen ||
+ n->net.rtableid != xn->net.rtableid)
+ continue;
+ if (memcmp(&n->net.prefix, &xn->net.prefix,
+ sizeof(n->net.prefix)) == 0)
+ return (xn);
+ }
+ return (NULL);
+}
+
+int
+kr_net_reload(u_int rtableid, struct network_head *nh)
+{
+ struct network *n, *xn;
+ struct ktable *kt;
+
+ if ((kt = ktable_get(rtableid)) == NULL) {
+ log_warnx("kr_net_reload: non-existent rtableid %d", rtableid);
+ return (-1);
+ }
+
+ TAILQ_FOREACH(n, &kt->krn, entry)
+ n->net.old = 1;
+
+ while ((n = TAILQ_FIRST(nh)) != NULL) {
+ TAILQ_REMOVE(nh, n, entry);
+ n->net.old = 0;
+ n->net.rtableid = rtableid;
+ xn = kr_net_find(kt, n);
+ if (xn) {
+ xn->net.old = 0;
+ kr_net_delete(n);
+ } else
+ TAILQ_INSERT_TAIL(&kt->krn, n, entry);
+ }
+
+ for (n = TAILQ_FIRST(&kt->krn); n != NULL; n = xn) {
+ xn = TAILQ_NEXT(n, entry);
+ if (n->net.old) {
+ if (n->net.type == NETWORK_DEFAULT)
+ if (send_network(IMSG_NETWORK_REMOVE, &n->net,
+ NULL))
+ return (-1);
+ TAILQ_REMOVE(&kt->krn, n, entry);
+ kr_net_delete(n);
+ }
+ }
+
+ return (0);
+}
int
kr_redistribute(int type, struct ktable *kt, struct kroute *kr)
{
- struct redist_node *rn;
+ struct network *match;
+ struct network_config net;
u_int32_t a;
+ /* shortcut for removals */
+ if (type == IMSG_NETWORK_REMOVE) {
+ if (!(kr->flags & F_REDISTRIBUTED))
+ return (0); /* no match, don't redistribute */
+ kr->flags &= ~F_REDISTRIBUTED;
+ match = NULL;
+ goto sendit;
+ }
+
if (!(kr->flags & F_KERNEL))
return (0);
@@ -985,41 +1208,40 @@ kr_redistribute(int type, struct ktable *kt, struct kroute *kr)
if (kr->prefix.s_addr == INADDR_ANY && kr->prefixlen == 0)
return (0);
- /* Add or delete kr from list ... */
- LIST_FOREACH(rn, &kt->redistlist, entry)
- if (rn->kr == kr)
- break;
+ match = kr_net_match(kt, kr);
+ if (match == NULL) {
+ if (!(kr->flags & F_REDISTRIBUTED))
+ return (0); /* no match, don't redistribute */
+ /* route no longer matches but is redistributed, so remove */
+ kr->flags &= ~F_REDISTRIBUTED;
+ type = IMSG_NETWORK_REMOVE;
+ } else
+ kr->flags |= F_REDISTRIBUTED;
- switch (type) {
- case IMSG_NETWORK_ADD:
- if (rn == NULL) {
- if ((rn = calloc(1, sizeof(struct redist_node))) ==
- NULL) {
- log_warn("kr_redistribute");
- return (-1);
- }
- rn->kr = kr;
- LIST_INSERT_HEAD(&kt->redistlist, rn, entry);
- }
- break;
- case IMSG_NETWORK_REMOVE:
- if (rn != NULL) {
- LIST_REMOVE(rn, entry);
- free(rn);
- }
- break;
- default:
- errno = EINVAL;
- return (-1);
- }
+sendit:
+ bzero(&net, sizeof(net));
+ net.prefix.aid = AID_INET;
+ net.prefix.v4.s_addr = kr->prefix.s_addr;
+ net.prefixlen = kr->prefixlen;
+ net.rtableid = kt->rtableid;
- return (bgpd_redistribute(type, kr, NULL));
+ return (send_network(type, &net, match ? &match->net.attrset : NULL));
}
int
kr_redistribute6(int type, struct ktable *kt, struct kroute6 *kr6)
{
- struct redist_node *rn;
+ struct network *match;
+ struct network_config net;
+
+ /* shortcut for removals */
+ if (type == IMSG_NETWORK_REMOVE) {
+ if (!(kr6->flags & F_REDISTRIBUTED))
+ return (0); /* no match, don't redistribute */
+ kr6->flags &= ~F_REDISTRIBUTED;
+ match = NULL;
+ goto sendit;
+ }
if (!(kr6->flags & F_KERNEL))
return (0);
@@ -1051,63 +1273,62 @@ kr_redistribute6(int type, struct ktable *kt, struct kroute6 *kr6)
* never allow ::/0 the default route can only be redistributed
* with announce default.
*/
- if (memcmp(&kr6->prefix, &in6addr_any, sizeof(struct in6_addr)) == 0 &&
- kr6->prefixlen == 0)
+ if (kr6->prefixlen == 0 &&
+ memcmp(&kr6->prefix, &in6addr_any, sizeof(struct in6_addr)) == 0)
return (0);
- /* Add or delete kr from list ...
- * using a linear list to store the redistributed networks will hurt
- * as soon as redistribute ospf comes but until then keep it simple.
- */
- LIST_FOREACH(rn, &kt->redistlist, entry)
- if (rn->kr6 == kr6)
- break;
-
- switch (type) {
- case IMSG_NETWORK_ADD:
- if (rn == NULL) {
- if ((rn = calloc(1, sizeof(struct redist_node))) ==
- NULL) {
- log_warn("kr_redistribute");
- return (-1);
- }
- rn->kr6 = kr6;
- LIST_INSERT_HEAD(&kt->redistlist, rn, entry);
- }
- break;
- case IMSG_NETWORK_REMOVE:
- if (rn != NULL) {
- LIST_REMOVE(rn, entry);
- free(rn);
- }
- break;
- default:
- errno = EINVAL;
- return (-1);
- }
-
- return (bgpd_redistribute(type, NULL, kr6));
+ match = kr_net_match6(kt, kr6);
+ if (match == NULL) {
+ if (!(kr6->flags & F_REDISTRIBUTED))
+ return (0); /* no match, don't redistribute */
+ /* route no longer matches but is redistributed, so remove */
+ kr6->flags &= ~F_REDISTRIBUTED;
+ type = IMSG_NETWORK_REMOVE;
+ } else
+ kr6->flags |= F_REDISTRIBUTED;
+sendit:
+ bzero(&net, sizeof(net));
+ net.prefix.aid = AID_INET6;
+ memcpy(&net.prefix.v6, &kr6->prefix, sizeof(struct in6_addr));
+ net.prefixlen = kr6->prefixlen;
+ net.rtableid = kt->rtableid;
+
+ return (send_network(type, &net, match ? &match->net.attrset : NULL));
}
int
kr_reload(void)
{
struct ktable *kt;
- struct redist_node *rn;
+ struct kroute_node *kr;
+ struct kroute6_node *kr6;
struct knexthop_node *nh;
+ struct network *n;
u_int rid;
+ int hasdyn = 0;
for (rid = 0; rid < krt_size; rid++) {
if ((kt = ktable_get(rid)) == NULL)
continue;
- LIST_FOREACH(rn, &kt->redistlist, entry)
- if (bgpd_redistribute(IMSG_NETWORK_ADD, rn->kr,
- rn->kr6) == -1)
- return (-1);
-
RB_FOREACH(nh, knexthop_tree, KT2KNT(kt))
knexthop_validate(kt, nh);
+
+ TAILQ_FOREACH(n, &kt->krn, entry)
+ if (n->net.type == NETWORK_DEFAULT) {
+ if (send_network(IMSG_NETWORK_ADD, &n->net,
+ &n->net.attrset))
+ return (-1);
+ } else
+ hasdyn = 1;
+
+ if (hasdyn) {
+ /* only evaluate the full tree if we need */
+ RB_FOREACH(kr, kroute_tree, &kt->krt)
+ kr_redistribute(IMSG_NETWORK_ADD, kt, &kr->r);
+ RB_FOREACH(kr6, kroute6_tree, &kt->krt6)
+ kr_redistribute6(IMSG_NETWORK_ADD, kt, &kr6->r);
+ }
}
return (0);
@@ -2314,11 +2535,16 @@ if_announce(void *msg)
int
send_rtmsg(int fd, int action, struct ktable *kt, struct kroute *kroute)
{
- struct iovec iov[5];
+ struct iovec iov[7];
struct rt_msghdr hdr;
struct sockaddr_in prefix;
struct sockaddr_in nexthop;
struct sockaddr_in mask;
+ struct {
+ struct sockaddr_dl dl;
+ char pad[sizeof(long)];
+ } ifp;
+ struct sockaddr_mpls mpls;
struct sockaddr_rtlabel label;
int iovcnt = 0;
@@ -2379,6 +2605,33 @@ send_rtmsg(int fd, int action, struct ktable *kt, struct kroute *kroute)
iov[iovcnt].iov_base = &mask;
iov[iovcnt++].iov_len = sizeof(mask);
+ if (kt->ifindex) {
+ bzero(&ifp, sizeof(ifp));
+ ifp.dl.sdl_len = sizeof(struct sockaddr_dl);
+ ifp.dl.sdl_family = AF_LINK;
+ ifp.dl.sdl_index = kt->ifindex;
+ /* adjust header */
+ hdr.rtm_addrs |= RTA_IFP;
+ hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_dl));
+ /* adjust iovec */
+ iov[iovcnt].iov_base = &ifp;
+ iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_dl));
+ }
+
+ if (kroute->flags & F_MPLS) {
+ bzero(&mpls, sizeof(mpls));
+ mpls.smpls_len = sizeof(mpls);
+ mpls.smpls_family = AF_MPLS;
+ mpls.smpls_label = kroute->mplslabel;
+ /* adjust header */
+ hdr.rtm_mpls = MPLS_OP_PUSH;
+ hdr.rtm_addrs |= RTA_SRC;
+ hdr.rtm_msglen += sizeof(mpls);
+ /* adjust iovec */
+ iov[iovcnt].iov_base = &mpls;
+ iov[iovcnt++].iov_len = sizeof(mpls);
+ }
+
if (kroute->labelid) {
bzero(&label, sizeof(label));
label.sr_len = sizeof(label);
diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y
index cc41bd888c3..2d426aa4140 100644
--- a/usr.sbin/bgpd/parse.y
+++ b/usr.sbin/bgpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.253 2010/05/03 13:09:38 claudio Exp $ */
+/* $OpenBSD: parse.y,v 1.254 2010/05/17 15:49:29 claudio Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -25,6 +25,7 @@
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <netmpls/mpls.h>
#include <ctype.h>
#include <err.h>
@@ -74,10 +75,12 @@ char *symget(const char *);
static struct bgpd_config *conf;
static struct mrt_head *mrtconf;
-static struct network_head *netconf;
+static struct network_head *netconf, *gnetconf;
static struct peer *peer_l, *peer_l_old;
static struct peer *curpeer;
static struct peer *curgroup;
+static struct rdomain *currdom;
+static struct rdomain_head *rdom_l;
static struct filter_head *filter_l;
static struct filter_head *peerfilter_l;
static struct filter_head *groupfilter_l;
@@ -163,6 +166,7 @@ typedef struct {
%}
%token AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE RTABLE
+%token RDOMAIN RD EXPORTTRGT IMPORTTRGT
%token RDE RIB EVALUATE IGNORE COMPARE
%token GROUP NEIGHBOR NETWORK
%token REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART
@@ -187,7 +191,7 @@ typedef struct {
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.number> asnumber as4number optnumber yesno inout
-%type <v.number> espah family restart origincode
+%type <v.number> espah family restart origincode nettype
%type <v.string> string filter_rib
%type <v.addr> address
%type <v.prefix> prefix addrspec
@@ -210,6 +214,7 @@ grammar : /* empty */
| grammar include '\n'
| grammar conf_main '\n'
| grammar varset '\n'
+ | grammar rdomain '\n'
| grammar neighbor '\n'
| grammar group '\n'
| grammar filterrule '\n'
@@ -431,47 +436,7 @@ conf_main : AS as4number {
}
free($2);
}
- | NETWORK prefix filter_set {
- struct network *n;
-
- if ((n = calloc(1, sizeof(struct network))) == NULL)
- fatal("new_network");
- memcpy(&n->net.prefix, &$2.prefix,
- sizeof(n->net.prefix));
- n->net.prefixlen = $2.len;
- move_filterset($3, &n->net.attrset);
- free($3);
-
- TAILQ_INSERT_TAIL(netconf, n, entry);
- }
- | NETWORK family STATIC filter_set {
- if ($2 == AFI_IPv4) {
- conf->flags |= BGPD_FLAG_REDIST_STATIC;
- move_filterset($4, &conf->staticset);
- } else if ($2 == AFI_IPv6) {
- conf->flags |= BGPD_FLAG_REDIST6_STATIC;
- move_filterset($4, &conf->staticset6);
- } else {
- yyerror("unknown family");
- free($4);
- YYERROR;
- }
- free($4);
- }
- | NETWORK family CONNECTED filter_set {
- if ($2 == AFI_IPv4) {
- conf->flags |= BGPD_FLAG_REDIST_CONNECTED;
- move_filterset($4, &conf->connectset);
- } else if ($2 == AFI_IPv6) {
- conf->flags |= BGPD_FLAG_REDIST6_CONNECTED;
- move_filterset($4, &conf->connectset6);
- } else {
- yyerror("unknown family");
- free($4);
- YYERROR;
- }
- free($4);
- }
+ | network
| DUMP STRING STRING optnumber {
int action;
@@ -625,6 +590,39 @@ mrtdump : DUMP STRING inout STRING optnumber {
}
;
+network : NETWORK prefix filter_set {
+ struct network *n;
+
+ if ((n = calloc(1, sizeof(struct network))) == NULL)
+ fatal("new_network");
+ memcpy(&n->net.prefix, &$2.prefix,
+ sizeof(n->net.prefix));
+ n->net.prefixlen = $2.len;
+ move_filterset($3, &n->net.attrset);
+ free($3);
+
+ TAILQ_INSERT_TAIL(netconf, n, entry);
+ }
+ | NETWORK family nettype filter_set {
+ struct network *n;
+
+ if ((n = calloc(1, sizeof(struct network))) == NULL)
+ fatal("new_network");
+ if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) ==
+ -1) {
+ yyerror("unknown family");
+ filterset_free($4);
+ free($4);
+ YYERROR;
+ }
+ n->net.type = $3 ? NETWORK_STATIC : NETWORK_CONNECTED;
+ move_filterset($4, &n->net.attrset);
+ free($4);
+
+ TAILQ_INSERT_TAIL(netconf, n, entry);
+ }
+ ;
+
inout : IN { $$ = 1; }
| OUT { $$ = 0; }
;
@@ -710,6 +708,138 @@ optnumber : /* empty */ { $$ = 0; }
| NUMBER
;
+rdomain : RDOMAIN NUMBER optnl '{' optnl {
+ if (ktable_exists($2, NULL) != 1) {
+ yyerror("rdomain %lld does not exist", $2);
+ YYERROR;
+ }
+ if (!(currdom = calloc(1, sizeof(struct rdomain))))
+ fatal(NULL);
+ currdom->rtableid = $2;
+ TAILQ_INIT(&currdom->import);
+ TAILQ_INIT(&currdom->export);
+ TAILQ_INIT(&currdom->net_l);
+ netconf = &currdom->net_l;
+ }
+ rdomainopts_l '}' {
+ /* insert into list */
+ SIMPLEQ_INSERT_TAIL(rdom_l, currdom, entry);
+ currdom = NULL;
+ netconf = gnetconf;
+ }
+
+rdomainopts_l : rdomainopts_l rdomainoptsl
+ | rdomainoptsl
+ ;
+
+rdomainoptsl : rdomainopts nl
+ ;
+
+rdomainopts : RD STRING {
+ struct filter_extcommunity ext;
+ u_int64_t rd;
+
+ if (parseextcommunity(&ext, "rt", $2) == -1) {
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ /*
+ * RD is almost encode like an ext-community,
+ * but only almost so convert here.
+ */
+ if (community_ext_conv(&ext, 0, &rd)) {
+ yyerror("bad encoding of rd");
+ YYERROR;
+ }
+ rd = betoh64(rd) & 0xffffffffffffULL;
+ switch (ext.type) {
+ case EXT_COMMUNITY_TWO_AS:
+ rd |= (0ULL << 48);
+ break;
+ case EXT_COMMUNITY_IPV4:
+ rd |= (1ULL << 48);
+ break;
+ case EXT_COMMUNITY_FOUR_AS:
+ rd |= (2ULL << 48);
+ break;
+ default:
+ yyerror("bad encoding of rd");
+ YYERROR;
+ }
+ currdom->rd = htobe64(rd);
+ }
+ | EXPORTTRGT STRING STRING {
+ struct filter_set *set;
+
+ if ((set = calloc(1, sizeof(struct filter_set))) ==
+ NULL)
+ fatal(NULL);
+ set->type = ACTION_SET_EXT_COMMUNITY;
+ if (parseextcommunity(&set->action.ext_community,
+ $2, $3) == -1) {
+ free($3);
+ free($2);
+ free(set);
+ YYERROR;
+ }
+ free($3);
+ free($2);
+ TAILQ_INSERT_TAIL(&currdom->export, set, entry);
+ }
+ | IMPORTTRGT STRING STRING {
+ struct filter_set *set;
+
+ if ((set = calloc(1, sizeof(struct filter_set))) ==
+ NULL)
+ fatal(NULL);
+ set->type = ACTION_SET_EXT_COMMUNITY;
+ if (parseextcommunity(&set->action.ext_community,
+ $2, $3) == -1) {
+ free($3);
+ free($2);
+ free(set);
+ YYERROR;
+ }
+ free($3);
+ free($2);
+ TAILQ_INSERT_TAIL(&currdom->import, set, entry);
+ }
+ | DESCR string {
+ if (strlcpy(currdom->descr, $2,
+ sizeof(currdom->descr)) >=
+ sizeof(currdom->descr)) {
+ yyerror("descr \"%s\" too long: max %u",
+ $2, sizeof(currdom->descr) - 1);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ }
+ | FIBUPDATE yesno {
+ if ($2 == 0)
+ currdom->flags |= F_RIB_NOFIBSYNC;
+ else
+ currdom->flags &= ~F_RIB_NOFIBSYNC;
+ }
+ | network
+ | DEPEND ON STRING {
+ /* XXX this is a hack */
+ if (if_nametoindex($3) == 0) {
+ yyerror("interface %s does not exist", $3);
+ free($3);
+ YYERROR;
+ }
+ strlcpy(currdom->ifmpe, $3, IFNAMSIZ);
+ free($3);
+ if (get_mpe_label(currdom)) {
+ yyerror("failed to get mpls label from %s",
+ currdom->ifmpe);
+ YYERROR;
+ }
+ }
+ ;
+
neighbor : { curpeer = new_peer(); }
NEIGHBOR addrspec {
memcpy(&curpeer->conf.remote_addr, &$3.prefix,
@@ -1176,6 +1306,10 @@ family : IPV4 { $$ = AFI_IPv4; }
| IPV6 { $$ = AFI_IPv6; }
;
+nettype : STATIC { $$ = 1; },
+ | CONNECTED { $$ = 0; }
+ ;
+
espah : ESP { $$ = 1; }
| AH { $$ = 0; }
;
@@ -1953,6 +2087,7 @@ lookup(char *s)
{ "enforce", ENFORCE},
{ "esp", ESP},
{ "evaluate", EVALUATE},
+ { "export-target", EXPORTTRGT},
{ "ext-community", EXTCOMMUNITY},
{ "fib-update", FIBUPDATE},
{ "from", FROM},
@@ -1960,6 +2095,7 @@ lookup(char *s)
{ "holdtime", HOLDTIME},
{ "ignore", IGNORE},
{ "ike", IKE},
+ { "import-target", IMPORTTRGT},
{ "in", IN},
{ "include", INCLUDE},
{ "inet", IPV4},
@@ -1995,7 +2131,9 @@ lookup(char *s)
{ "prepend-self", PREPEND_SELF},
{ "qualify", QUALIFY},
{ "quick", QUICK},
+ { "rd", RD},
{ "rde", RDE},
+ { "rdomain", RDOMAIN},
{ "refresh", REFRESH },
{ "reject", REJECT},
{ "remote-as", REMOTEAS},
@@ -2361,7 +2499,7 @@ popfile(void)
int
parse_config(char *filename, struct bgpd_config *xconf,
struct mrt_head *xmconf, struct peer **xpeers, struct network_head *nc,
- struct filter_head *xfilter_l)
+ struct filter_head *xfilter_l, struct rdomain_head *xrdom_l)
{
struct sym *sym, *next;
struct peer *p, *pnext;
@@ -2369,6 +2507,7 @@ parse_config(char *filename, struct bgpd_config *xconf,
struct network *n;
struct filter_rule *r;
struct rde_rib *rr;
+ struct rdomain *rd;
int errors = 0;
if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL)
@@ -2404,12 +2543,14 @@ parse_config(char *filename, struct bgpd_config *xconf,
id = 1;
/* network list is always empty in the parent */
- netconf = nc;
+ gnetconf = netconf = nc;
TAILQ_INIT(netconf);
/* init the empty filter list for later */
TAILQ_INIT(xfilter_l);
+ SIMPLEQ_INIT(xrdom_l);
+ rdom_l = xrdom_l;
- add_rib("Adj-RIB-In", 0, F_RIB_NOEVALUATE);
+ add_rib("Adj-RIB-In", 0, F_RIB_NOFIB | F_RIB_NOEVALUATE);
add_rib("Loc-RIB", 0, 0);
yyparse();
@@ -2470,6 +2611,19 @@ parse_config(char *filename, struct bgpd_config *xconf,
SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
free(rr);
}
+ while ((rd = SIMPLEQ_FIRST(rdom_l)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(rdom_l, entry);
+ filterset_free(&rd->export);
+ filterset_free(&rd->import);
+
+ while ((n = TAILQ_FIRST(&rd->net_l)) != NULL) {
+ TAILQ_REMOVE(&rd->net_l, n, entry);
+ filterset_free(&n->net.attrset);
+ free(n);
+ }
+
+ free(rd);
+ }
} else {
errors += merge_config(xconf, conf, peer_l, listen_addrs);
errors += mrt_mergeconfig(xmconf, mrtconf);
diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c
index 5a94342ddf0..860aebd1913 100644
--- a/usr.sbin/bgpd/printconf.c
+++ b/usr.sbin/bgpd/printconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: printconf.c,v 1.80 2010/05/03 13:09:38 claudio Exp $ */
+/* $OpenBSD: printconf.c,v 1.81 2010/05/17 15:49:29 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -31,6 +31,9 @@ void print_extcommunity(struct filter_extcommunity *);
void print_origin(u_int8_t);
void print_set(struct filter_set_head *);
void print_mainconf(struct bgpd_config *);
+void print_rdomain_targets(struct filter_set_head *, const char *);
+void print_rdomain(struct rdomain *);
+const char *print_af(u_int8_t);
void print_network(struct network_config *);
void print_peer(struct peer_config *, struct bgpd_config *,
const char *);
@@ -262,43 +265,67 @@ print_mainconf(struct bgpd_config *conf)
printf("nexthop qualify via bgp\n");
if (conf->flags & BGPD_FLAG_NEXTHOP_DEFAULT)
printf("nexthop qualify via default\n");
+}
- if (conf->flags & BGPD_FLAG_REDIST_CONNECTED) {
- printf("network inet connected");
- if (!TAILQ_EMPTY(&conf->connectset))
- printf(" ");
- print_set(&conf->connectset);
- printf("\n");
- }
- if (conf->flags & BGPD_FLAG_REDIST_STATIC) {
- printf("network inet static");
- if (!TAILQ_EMPTY(&conf->staticset))
- printf(" ");
- print_set(&conf->staticset);
- printf("\n");
- }
- if (conf->flags & BGPD_FLAG_REDIST6_CONNECTED) {
- printf("network inet6 connected");
- if (!TAILQ_EMPTY(&conf->connectset6))
- printf(" ");
- print_set(&conf->connectset6);
- printf("\n");
- }
- if (conf->flags & BGPD_FLAG_REDIST6_STATIC) {
- printf("network inet6 static");
- if (!TAILQ_EMPTY(&conf->staticset6))
- printf(" ");
- print_set(&conf->staticset6);
+void
+print_rdomain_targets(struct filter_set_head *set, const char *tgt)
+{
+ struct filter_set *s;
+ TAILQ_FOREACH(s, set, entry) {
+ printf("\t%s ", tgt);
+ print_extcommunity(&s->action.ext_community);
printf("\n");
}
- if (conf->rtableid)
- printf("rtable %u\n", conf->rtableid);
+}
+
+void
+print_rdomain(struct rdomain *r)
+{
+ printf("rdomain %u {\n", r->rtableid);
+ printf("\tdescr \"%s\"\n", r->descr);
+ if (r->flags & F_RIB_NOFIBSYNC)
+ printf("\tfib-update no\n");
+ else
+ printf("\tfib-update yes\n");
+ printf("\tdepend on %s\n", r->ifmpe);
+
+ printf("\n\t%s\n", log_rd(r->rd));
+
+ print_rdomain_targets(&r->export, "export-target");
+ print_rdomain_targets(&r->import, "import-target");
+
+ printf("}\n");
+}
+
+const char *
+print_af(u_int8_t aid)
+{
+ /*
+ * Hack around the fact that aid2str() will return "IPv4 unicast"
+ * for AID_INET. AID_INET and AID_INET6 need special handling and
+ * the other AID should never end up here (at least for now).
+ */
+ if (aid == AID_INET)
+ return ("inet");
+ if (aid == AID_INET6);
+ return ("inet6");
+ return (aid2str(aid));
}
void
print_network(struct network_config *n)
{
- printf("network %s/%u", log_addr(&n->prefix), n->prefixlen);
+ switch (n->type) {
+ case NETWORK_STATIC:
+ printf("network %s static", print_af(n->prefix.aid));
+ break;
+ case NETWORK_CONNECTED:
+ printf("network %s connected", print_af(n->prefix.aid));
+ break;
+ default:
+ printf("network %s/%u", log_addr(&n->prefix), n->prefixlen);
+ break;
+ }
if (!TAILQ_EMPTY(&n->attrset))
printf(" ");
print_set(&n->attrset);
@@ -666,16 +693,23 @@ peer_compare(const void *aa, const void *bb)
void
print_config(struct bgpd_config *conf, struct rib_names *rib_l,
struct network_head *net_l, struct peer *peer_l,
- struct filter_head *rules_l, struct mrt_head *mrt_l)
+ struct filter_head *rules_l, struct mrt_head *mrt_l,
+ struct rdomain_head *rdom_l)
{
struct filter_rule *r;
struct network *n;
struct rde_rib *rr;
+ struct rdomain *rd;
xmrt_l = mrt_l;
- printf("\n");
print_mainconf(conf);
printf("\n");
+ TAILQ_FOREACH(n, net_l, entry)
+ print_network(&n->net);
+ printf("\n");
+ SIMPLEQ_FOREACH(rd, rdom_l, entry)
+ print_rdomain(rd);
+ printf("\n");
SIMPLEQ_FOREACH(rr, rib_l, entry) {
if (rr->flags & F_RIB_NOEVALUATE)
printf("rde rib %s no evaluate\n", rr->name);
@@ -687,9 +721,6 @@ print_config(struct bgpd_config *conf, struct rib_names *rib_l,
"no" : "yes");
}
printf("\n");
- TAILQ_FOREACH(n, net_l, entry)
- print_network(&n->net);
- printf("\n");
print_mrt(0, 0, "", "");
printf("\n");
print_groups(conf, peer_l);
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index 0f9cd241a11..c1a3462f6ad 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.293 2010/05/04 10:25:31 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.294 2010/05/17 15:49:29 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -82,6 +82,7 @@ void rde_dump_ctx_new(struct ctl_show_rib_request *, pid_t,
void rde_dump_mrt_new(struct mrt *, pid_t, int);
void rde_dump_done(void *);
+int rde_rdomain_import(struct rde_aspath *, struct rdomain *);
void rde_up_dump_upcall(struct rib_entry *, void *);
void rde_softreconfig_out(struct rib_entry *, void *);
void rde_softreconfig_in(struct rib_entry *, void *);
@@ -99,7 +100,6 @@ void peer_down(u_int32_t);
void peer_dump(u_int32_t, u_int8_t);
void peer_send_eor(struct rde_peer *, u_int8_t);
-void network_init(struct network_head *);
void network_add(struct network_config *, int);
void network_delete(struct network_config *, int);
void network_dump_upcall(struct rib_entry *, void *);
@@ -113,6 +113,7 @@ time_t reloadtime;
struct rde_peer_head peerlist;
struct rde_peer *peerself;
struct filter_head *rules_l, *newrules;
+struct rdomain_head *rdomains_l, *newdomains;
struct imsgbuf *ibuf_se;
struct imsgbuf *ibuf_se_ctl;
struct imsgbuf *ibuf_main;
@@ -220,6 +221,10 @@ rde_main(int pipe_m2r[2], int pipe_s2r[2], int pipe_m2s[2], int pipe_s2rctl[2],
if (rules_l == NULL)
fatal(NULL);
TAILQ_INIT(rules_l);
+ rdomains_l = calloc(1, sizeof(struct rdomain_head));
+ if (rdomains_l == NULL)
+ fatal(NULL);
+ SIMPLEQ_INIT(rdomains_l);
if ((conf = malloc(sizeof(struct bgpd_config))) == NULL)
fatal(NULL);
log_info("route decision engine ready");
@@ -535,6 +540,7 @@ badnet:
void
rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
{
+ static struct rdomain *rd;
struct imsg imsg;
struct mrt xmrt;
struct rde_rib rn;
@@ -557,20 +563,12 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
break;
switch (imsg.hdr.type) {
- case IMSG_RECONF_CONF:
- reloadtime = time(NULL);
- newrules = calloc(1, sizeof(struct filter_head));
- if (newrules == NULL)
- fatal(NULL);
- TAILQ_INIT(newrules);
- if ((nconf = malloc(sizeof(struct bgpd_config))) ==
- NULL)
- fatal(NULL);
- memcpy(nconf, imsg.data, sizeof(struct bgpd_config));
- for (rid = 0; rid < rib_size; rid++)
- ribs[rid].state = RECONF_DELETE;
- break;
case IMSG_NETWORK_ADD:
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct network_config)) {
+ log_warnx("rde_dispatch: wrong imsg len");
+ break;
+ }
memcpy(&netconf_p, imsg.data, sizeof(netconf_p));
TAILQ_INIT(&netconf_p.attrset);
parent_set = &netconf_p.attrset;
@@ -589,6 +587,26 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
TAILQ_INIT(&netconf_p.attrset);
network_delete(&netconf_p, 1);
break;
+ case IMSG_RECONF_CONF:
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct bgpd_config))
+ fatalx("IMSG_RECONF_CONF bad len");
+ reloadtime = time(NULL);
+ newrules = calloc(1, sizeof(struct filter_head));
+ if (newrules == NULL)
+ fatal(NULL);
+ TAILQ_INIT(newrules);
+ newdomains = calloc(1, sizeof(struct rdomain_head));
+ if (newdomains == NULL)
+ fatal(NULL);
+ SIMPLEQ_INIT(newdomains);
+ if ((nconf = malloc(sizeof(struct bgpd_config))) ==
+ NULL)
+ fatal(NULL);
+ memcpy(nconf, imsg.data, sizeof(struct bgpd_config));
+ for (rid = 0; rid < rib_size; rid++)
+ ribs[rid].state = RECONF_DELETE;
+ break;
case IMSG_RECONF_RIB:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
sizeof(struct rde_rib))
@@ -619,12 +637,42 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
parent_set = &r->set;
TAILQ_INSERT_TAIL(newrules, r, entry);
break;
+ case IMSG_RECONF_RDOMAIN:
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct rdomain))
+ fatalx("IMSG_RECONF_RDOMAIN bad len");
+ if ((rd = malloc(sizeof(struct rdomain))) == NULL)
+ fatal(NULL);
+ memcpy(rd, imsg.data, sizeof(struct rdomain));
+ TAILQ_INIT(&rd->import);
+ TAILQ_INIT(&rd->export);
+ SIMPLEQ_INSERT_TAIL(newdomains, rd, entry);
+ break;
+ case IMSG_RECONF_RDOMAIN_EXPORT:
+ if (rd == NULL) {
+ log_warnx("rde_dispatch_imsg_parent: "
+ "IMSG_RECONF_RDOMAIN_EXPORT unexpected");
+ break;
+ }
+ parent_set = &rd->export;
+ break;
+ case IMSG_RECONF_RDOMAIN_IMPORT:
+ if (rd == NULL) {
+ log_warnx("rde_dispatch_imsg_parent: "
+ "IMSG_RECONF_RDOMAIN_IMPORT unexpected");
+ break;
+ }
+ parent_set = &rd->import;
+ break;
+ case IMSG_RECONF_RDOMAIN_DONE:
+ parent_set = NULL;
+ break;
case IMSG_RECONF_DONE:
if (nconf == NULL)
fatalx("got IMSG_RECONF_DONE but no config");
if ((nconf->flags & BGPD_FLAG_NO_EVALUATE)
!= (conf->flags & BGPD_FLAG_NO_EVALUATE)) {
- log_warnx( "change to/from route-collector "
+ log_warnx("change to/from route-collector "
"mode ignored");
if (conf->flags & BGPD_FLAG_NO_EVALUATE)
nconf->flags |= BGPD_FLAG_NO_EVALUATE;
@@ -643,7 +691,16 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
peerself->conf.local_as = conf->as;
peerself->conf.remote_as = conf->as;
peerself->short_as = conf->short_as;
- prefix_network_clean(peerself, reloadtime, 0);
+
+ /* apply new set of rdomain, sync will be done later */
+ while ((rd = SIMPLEQ_FIRST(rdomains_l)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(rdomains_l, entry);
+ filterset_free(&rd->import);
+ filterset_free(&rd->export);
+ free(rd);
+ }
+ free(rdomains_l);
+ rdomains_l = newdomains;
/* check if filter changed */
LIST_FOREACH(peer, &peerlist, peer_l) {
@@ -696,12 +753,16 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
}
free(rules_l);
rules_l = newrules;
+
log_info("RDE reconfigured");
break;
case IMSG_NEXTHOP_UPDATE:
nexthop_update(imsg.data);
break;
case IMSG_FILTER_SET:
+ if (imsg.hdr.len > IMSG_HEADER_SIZE +
+ sizeof(struct filter_set))
+ fatalx("IMSG_RECONF_CONF bad len");
if (parent_set == NULL) {
log_warnx("rde_dispatch_imsg_parent: "
"IMSG_FILTER_SET unexpected");
@@ -2230,12 +2291,25 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t pid, int fd)
/*
* kroute specific functions
*/
+int
+rde_rdomain_import(struct rde_aspath *asp, struct rdomain *rd)
+{
+ struct filter_set *s;
+
+ TAILQ_FOREACH(s, &rd->import, entry) {
+ if (community_ext_match(asp, &s->action.ext_community, 0))
+ return (1);
+ }
+ return (0);
+}
+
void
rde_send_kroute(struct prefix *new, struct prefix *old, u_int16_t ribid)
{
struct kroute_full kr;
struct bgpd_addr addr;
struct prefix *p;
+ struct rdomain *rd;
enum imsg_type type;
/*
@@ -2268,9 +2342,35 @@ rde_send_kroute(struct prefix *new, struct prefix *old, u_int16_t ribid)
strlcpy(kr.label, rtlabel_id2name(p->aspath->rtlabelid),
sizeof(kr.label));
- if (imsg_compose(ibuf_main, type, ribs[ribid].rtableid, 0, -1, &kr,
- sizeof(kr)) == -1)
- fatal("imsg_compose error");
+ switch (addr.aid) {
+ case AID_VPN_IPv4:
+ if (ribid != 1)
+ /* not Loc-RIB, no update for VPNs */
+ break;
+
+ SIMPLEQ_FOREACH(rd, rdomains_l, entry) {
+ if (addr.vpn4.rd != rd->rd)
+ continue;
+ if (!rde_rdomain_import(p->aspath, rd))
+ continue;
+ /* must send exit_nexthop so that correct MPLS tunnel
+ * is chosen
+ */
+ if (type == IMSG_KROUTE_CHANGE)
+ memcpy(&kr.nexthop,
+ &p->aspath->nexthop->exit_nexthop,
+ sizeof(kr.nexthop));
+ if (imsg_compose(ibuf_main, type, rd->rtableid, 0, -1,
+ &kr, sizeof(kr)) == -1)
+ fatal("imsg_compose error");
+ }
+ break;
+ default:
+ if (imsg_compose(ibuf_main, type, ribs[ribid].rtableid, 0, -1,
+ &kr, sizeof(kr)) == -1)
+ fatal("imsg_compose error");
+ break;
+ }
}
/*
@@ -2969,25 +3069,43 @@ peer_send_eor(struct rde_peer *peer, u_int8_t aid)
* network announcement stuff
*/
void
-network_init(struct network_head *net_l)
-{
- struct network *n;
-
- reloadtime = time(NULL);
-
- while ((n = TAILQ_FIRST(net_l)) != NULL) {
- TAILQ_REMOVE(net_l, n, entry);
- network_add(&n->net, 1);
- free(n);
- }
-}
-
-void
network_add(struct network_config *nc, int flagstatic)
{
+ struct rdomain *rd;
struct rde_aspath *asp;
+ struct filter_set_head *vpnset = NULL;
+ in_addr_t prefix4;
u_int16_t i;
+ if (nc->rtableid) {
+ SIMPLEQ_FOREACH(rd, rdomains_l, entry) {
+ if (rd->rtableid != nc->rtableid)
+ continue;
+ switch (nc->prefix.aid) {
+ case AID_INET:
+ prefix4 = nc->prefix.v4.s_addr;
+ bzero(&nc->prefix, sizeof(nc->prefix));
+ nc->prefix.aid = AID_VPN_IPv4;
+ nc->prefix.vpn4.rd = rd->rd;
+ nc->prefix.vpn4.addr.s_addr = prefix4;
+ nc->prefix.vpn4.labellen = 3;
+ nc->prefix.vpn4.labelstack[0] =
+ (rd->label >> 12) & 0xff;
+ nc->prefix.vpn4.labelstack[1] =
+ (rd->label >> 4) & 0xff;
+ nc->prefix.vpn4.labelstack[2] =
+ (rd->label << 4) & 0xf0;
+ nc->prefix.vpn4.labelstack[2] |= BGP_MPLS_BOS;
+ vpnset = &rd->export;
+ break;
+ default:
+ log_warnx("unable to VPNize prefix");
+ filterset_free(&nc->attrset);
+ return;
+ }
+ }
+ }
+
asp = path_get();
asp->aspath = aspath_get(NULL, 0);
asp->origin = ORIGIN_IGP;
@@ -2998,6 +3116,8 @@ network_add(struct network_config *nc, int flagstatic)
asp->flags |= F_ANN_DYNAMIC;
rde_apply_set(asp, &nc->attrset, nc->prefix.aid, peerself, peerself);
+ if (vpnset)
+ rde_apply_set(asp, vpnset, nc->prefix.aid, peerself, peerself);
for (i = 1; i < rib_size; i++)
path_update(&ribs[i], peerself, asp, &nc->prefix,
nc->prefixlen);
@@ -3009,12 +3129,41 @@ network_add(struct network_config *nc, int flagstatic)
void
network_delete(struct network_config *nc, int flagstatic)
{
- u_int32_t flags = F_PREFIX_ANNOUNCED;
- u_int32_t i;
+ struct rdomain *rd;
+ in_addr_t prefix4;
+ u_int32_t flags = F_PREFIX_ANNOUNCED;
+ u_int32_t i;
if (!flagstatic)
flags |= F_ANN_DYNAMIC;
+ if (nc->rtableid) {
+ SIMPLEQ_FOREACH(rd, rdomains_l, entry) {
+ if (rd->rtableid != nc->rtableid)
+ continue;
+ switch (nc->prefix.aid) {
+ case AID_INET:
+ prefix4 = nc->prefix.v4.s_addr;
+ bzero(&nc->prefix, sizeof(nc->prefix));
+ nc->prefix.aid = AID_VPN_IPv4;
+ nc->prefix.vpn4.rd = rd->rd;
+ nc->prefix.vpn4.addr.s_addr = prefix4;
+ nc->prefix.vpn4.labellen = 3;
+ nc->prefix.vpn4.labelstack[0] =
+ (rd->label >> 12) & 0xff;
+ nc->prefix.vpn4.labelstack[1] =
+ (rd->label >> 4) & 0xff;
+ nc->prefix.vpn4.labelstack[2] =
+ (rd->label << 4) & 0xf0;
+ nc->prefix.vpn4.labelstack[2] |= BGP_MPLS_BOS;
+ break;
+ default:
+ log_warnx("unable to VPNize prefix");
+ return;
+ }
+ }
+ }
+
for (i = rib_size - 1; i > 0; i--)
prefix_remove(&ribs[i], peerself, &nc->prefix, nc->prefixlen,
flags);
diff --git a/usr.sbin/bgpd/session.h b/usr.sbin/bgpd/session.h
index 42229218760..9484cf68cd9 100644
--- a/usr.sbin/bgpd/session.h
+++ b/usr.sbin/bgpd/session.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.h,v 1.105 2010/05/03 13:09:38 claudio Exp $ */
+/* $OpenBSD: session.h,v 1.106 2010/05/17 15:49:29 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -246,12 +246,14 @@ void log_conn_attempt(const struct peer *, struct sockaddr *);
/* parse.y */
int parse_config(char *, struct bgpd_config *, struct mrt_head *,
- struct peer **, struct network_head *, struct filter_head *);
+ struct peer **, struct network_head *, struct filter_head *,
+ struct rdomain_head *);
/* config.c */
int merge_config(struct bgpd_config *, struct bgpd_config *,
struct peer *, struct listen_addrs *);
void prepare_listeners(struct bgpd_config *);
+int get_mpe_label(struct rdomain *);
/* rde.c */
pid_t rde_main(int[2], int[2], int[2], int[2], int);
@@ -271,7 +273,7 @@ int pfkey_init(struct bgpd_sysdep *);
/* printconf.c */
void print_config(struct bgpd_config *, struct rib_names *,
struct network_head *, struct peer *, struct filter_head *,
- struct mrt_head *);
+ struct mrt_head *, struct rdomain_head *);
/* carp.c */
int carp_demote_init(char *, int);