diff options
-rw-r--r-- | usr.sbin/bgpd/bgpd.8 | 15 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.c | 143 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.conf.5 | 124 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 52 | ||||
-rw-r--r-- | usr.sbin/bgpd/config.c | 30 | ||||
-rw-r--r-- | usr.sbin/bgpd/kroute.c | 427 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 248 | ||||
-rw-r--r-- | usr.sbin/bgpd/printconf.c | 101 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.c | 221 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.h | 8 |
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); |