diff options
-rw-r--r-- | doc/bird.sgml | 176 | ||||
-rw-r--r-- | nest/config.Y | 52 | ||||
-rw-r--r-- | nest/iface.c | 67 | ||||
-rw-r--r-- | nest/iface.h | 14 | ||||
-rw-r--r-- | nest/rt-dev.c | 2 | ||||
-rw-r--r-- | proto/bgp/attrs.c | 20 | ||||
-rw-r--r-- | proto/bgp/bgp.c | 15 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 12 | ||||
-rw-r--r-- | proto/bgp/packets.c | 60 | ||||
-rw-r--r-- | proto/ospf/config.Y | 15 | ||||
-rw-r--r-- | proto/ospf/iface.c | 2 | ||||
-rw-r--r-- | proto/ospf/ospf.c | 4 | ||||
-rw-r--r-- | proto/rip/config.Y | 25 | ||||
-rw-r--r-- | proto/rip/rip.c | 4 | ||||
-rw-r--r-- | sysdep/linux/netlink/netlink.c | 41 |
15 files changed, 334 insertions, 175 deletions
diff --git a/doc/bird.sgml b/doc/bird.sgml index f62881c3..c73872b7 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -206,6 +206,7 @@ protocol device { protocol rip { export all; import all; + interface "*"; } </code> @@ -298,19 +299,88 @@ to zero to disable it. An empty <cf><m/switch/</cf> is equivalent to <cf/on/ <p>There are several options that give sense only with certain protocols: <descrip> - <tag>passwords { password "<m/password/" from <m/time/ to <m/time/ passive <m/time/ id - <m/num/ [...] }</tag> Specifies passwords to be used with this protocol. <cf>Passive <m/time/</cf> is - time from which the password is not used for sending, but it is recognized on reception. <cf/id/ is password ID as needed by - certain protocols. Format of <cf><m/time/</cf> is <tt>dd-mm-yyyy HH:MM:SS</tt>. - - <tag>interface "<m/mask/"|<m/prefix/ [ { <m/option/ ; [...] } ]</tag> Specifies which - interfaces is this protocol active on and allows you to set options on a - per-interface basis. Mask is specified as in shell-like patterns, thus <cf>interface - "*" { mode broadcast; };</cf> will start the protocol on all interfaces with <cf>mode - broadcast;</cf> option. If the first character of mask is <cf/-/, such interfaces are - excluded. Masks are parsed left-to-right, thus <cf/interface "-eth*", "*";/ means all but - the ethernets. Default: none. + <tag><label id="dsc-iface">interface [-] [ "<m/mask/" ] [ <m/prefix/ ] [, ...] [ { <m/option/ ; [...] } ]</tag> + + Specifies a set of interfaces on which the protocol is activated with + given interface-specific options. A set of interfaces specified by one + interface option is described using an interface pattern. The + interface pattern consists of a sequence of clauses (separted by + commas), each clause may contain a mask, a prefix, or both of them. An + interface matches the clause if its name matches the mask (if + specified) and its address matches the prefix (if specified). Mask is + specified as shell-like pattern. + + An interface matches the pattern if it matches any of its + clauses. If the clause begins with <cf/-/, matching interfaces are + excluded. Patterns are parsed left-to-right, thus + <cf/interface "eth0", -"eth*", "*";/ means eth0 and all + non-ethernets. + + An interface option can be used more times with different + interfaces-specific options, in that case for given interface + the first matching interface option is used. + + This option is allowed in Direct, OSPF and RIP protocols, + but in OSPF protocol it is used in <cf/area/ subsection. + + Default: none. + + Examples: + + <cf>interface "*" { type broadcast; };</cf> - start the protocol on all interfaces with + <cf>type broadcast</cf> option. + + <cf>interface "eth1", "eth4", "eth5" { type pointopoint; };</cf> - start the protocol + on enumerated interfaces with <cf>type pointopoint</cf> option. + + <cf>interface -192.168.1.0/24, 192.168.0.0/16;</cf> - start the protocol on all + interfaces that have address from 192.168.0.0/16, but not + from 192.168.1.0/24. + + <cf>interface -192.168.1.0/24, 192.168.0.0/16;</cf> - start the protocol on all + interfaces that have address from 192.168.0.0/16, but not + from 192.168.1.0/24. + + <cf>interface "eth*" 192.168.1.0/24;</cf> - start the protocol on all + ethernet interfaces that have address from 192.168.1.0/24. + + <tag><label id="dsc-pass">password "<m/password/" [ { id <m/num/; generate from <m/time/; generate to <m/time/; accept from <m/time/; accept to <m/time/; } ]</tag> + Specifies a password that can be used by the protocol. Password option can + be used more times to specify more passwords. If more passwords are + specified, it is a protocol-dependent decision which one is really + used. Specifying passwords does not mean that authentication is + enabled, authentication can be enabled by separate, protocol-dependent + <cf/authentication/ option. + + This option is allowed in OSPF and RIP protocols. BGP has also + <cf/password/ option, but it is slightly different and described + separately. + + Default: none. +</descrip> + +<p>Password option can contain section with some (not necessary all) password sub-options: + +<descrip> + <tag>id <M>num</M></tag> + ID of the password, (0-255). If it's not used, BIRD will choose + ID based on an order of the password item in the interface. For + example, second password item in one interface will have default + ID 2. ID is used by some routing protocols to identify which + password was used to authenticate protocol packets. + + <tag>generate from "<m/time/"</tag> + The start time of the usage of the password for packet signing. + The format of <cf><m/time/</cf> is <tt>dd-mm-yyyy HH:MM:SS</tt>. + + <tag>generate to "<m/time/"</tag> + The last time of the usage of the password for packet signing. + + <tag>accept from "<m/time/"</tag> + The start time of the usage of the password for packet verification. + <tag>accept to "<m/time/"</tag> + The last time of the usage of the password for packet verification. </descrip> <chapt>Remote control @@ -327,6 +397,9 @@ codes along with the messages. You do not necessarily need to use <file/birdc/ t own applications could do that, too -- the format of communication between BIRD and <file/birdc/ is stable (see the programmer's documentation). +Many commands have the <m/name/ of the protocol instance as an argument. +This argument can be omitted if there exists only a single instance. + <p>Here is a brief list of supported functions: <descrip> @@ -339,12 +412,23 @@ BIRD and <file/birdc/ is stable (see the programmer's documentation). <tag>show protocols [all]</tag> Show list of protocol instances along with tables they are connected to and protocol status, possibly giving verbose information, if <cf/all/ is specified. - <tag>show ospf [interface|neighbors] [<m/name/] ["<m/interface/"]</tag> - Show detailed information about OSPF protocol, possibly giving a verbose list of interfaces and neighbors. The <m/name/ of the protocol instance can be omitted if there exists only a single instance. + <tag>show ospf interface [<m/name/] ["<m/interface/"]</tag> + Show detailed information about OSPF interfaces. + + <tag>show ospf neighbors [<m/name/] ["<m/interface/"]</tag> + Show a list of OSPF neighbors and a state of adjacency to them. + + <tag>show ospf state [<m/name/]</tag> + Show detailed information about OSPF areas based on a content of link-state database. + It shows network topology, aggregated networks and routers from other areas and external routes. + + <tag>show ospf topology [<m/name/]</tag> + Show a topology of OSPF areas based on a content of link-state database. + It is just a stripped-down version of 'show ospf state'. <tag>show static [<m/name/]</tag> - Show detailed information about static routes. The <m/name/ of the protocol instance can be omitted if there exists only a single instance. - + Show detailed information about static routes. + <tag>show interfaces [summary]</tag> Show the list of interfaces. For each interface, print its type, state, MTU and addresses assigned. @@ -367,7 +451,7 @@ BIRD and <file/birdc/ is stable (see the programmer's documentation). a given filter (<cf>filter <m/name/</cf> or <cf>filter { <m/filter/ } </cf> or matching a given condition (<cf>where <m/condition/</cf>). The <cf/import/ and <cf/preimport/ switches ask for printing of entries - that are imported to the specified protocol. With <cf/preimport/, the + that are imported to the specified protocol. With <cf/preimport/, the import filter of the protocol is skipped. <p>You can also select just routes added by a specific protocol. @@ -515,14 +599,14 @@ incompatible with each other (that is to prevent you from shooting in the foot). Sets of prefixes are special: their literals does not allow ranges, but allows prefix patterns that are written as <cf><M>ipaddress</M>/<M>pxlen</M>{<M>low</M>,<M>high</M>}</cf>. - Prefix <cf><m>ip1</m>/<m>len1</m></cf> matches prefix pattern <cf><m>ip2</m>/<m>len2</m>{<m>l</m>, <m>h</m>}</cf> iff - the first <cf>min(len1, len2)</cf> bits of <cf/ip1/> and <cf/ip2/ are identical and <cf>len1 ≤ ip1 ≤ len2</cf>. - A valid prefix pattern has to satisfy <cf/low ≤ high/, but <cf/pxlen/ is not constrained by <cf/low/ + Prefix <cf><m>ip1</m>/<m>len1</m></cf> matches prefix pattern <cf><m>ip2</m>/<m>len2</m>{<m>l</m>,<m>h</m>}</cf> iff + the first <cf>min(len1, len2)</cf> bits of <cf/ip1/ and <cf/ip2/ are identical and <cf>len1 <= ip1 <= len2</cf>. + A valid prefix pattern has to satisfy <cf>low <= high</cf>, but <cf/pxlen/ is not constrained by <cf/low/ or <cf/high/. Obviously, a prefix matches a prefix set literal iff it matches any prefix pattern in the prefix set literal. There are also two shorthands for prefix patterns: <cf><m>address</m>/<m/len/+</cf> is a shorthand for - <cf><m>address</m>/<m/len/{<m/len/,<m/maxlen/}</cf> (where <cf><m>maxlen</m></c> is 32 for IPv4 and 128 for IPv6), + <cf><m>address</m>/<m/len/{<m/len/,<m/maxlen/}</cf> (where <cf><m>maxlen</m></cf> is 32 for IPv4 and 128 for IPv6), that means network prefix <cf><m>address</m>/<m/len/</cf> and all its subnets. <cf><m>address</m>/<m/len/-</cf> is a shorthand for <cf><m>address</m>/<m/len/{0,<m/len/}</cf>, that means network prefix <cf><m>address</m>/<m/len/</cf> and all its supernets (network prefixes that contain it). @@ -531,7 +615,7 @@ incompatible with each other (that is to prevent you from shooting in the foot). prefix <cf>1.0.0.0/8</cf>, all subprefixes of <cf>2.0.0.0/8</cf>, all superprefixes of <cf>3.0.0.0/8</cf> and prefixes <cf/4.X.X.X/ whose prefix length is 16 to 24. <cf>[ 0.0.0.0/0{20,24} ]</cf> matches all prefixes (regardless of IP address) whose prefix length is 20 to 24, <cf>[ 1.2.3.4/32- ]</cf> matches any prefix that contains IP address - <cf>1.2.3.4</cf>. <cf>1.2.0.0/16 ˜ [ 1.0.0.0/8{ 15 , 17 } ]</cf> is true, + <cf>1.2.3.4</cf>. <cf>1.2.0.0/16 ˜ [ 1.0.0.0/8{15,17} ]</cf> is true, but <cf>1.0.0.0/16 ˜ [ 1.0.0.0/8- ]</cf> is false. Cisco-style patterns like <cf>10.0.0.0/8 ge 16 le 24</cf> can be expressed @@ -1175,6 +1259,7 @@ protocol ospf <name> { <tag>interface <M>pattern</M></tag> Defines that the specified interfaces belong to the area being defined. + See <ref id="dsc-iface" name="interface"> common option for detailed description. <tag>virtual link <M>id</M></tag> Virtual link to router with the router id. Virtual link acts as a @@ -1260,24 +1345,7 @@ protocol ospf <name> { <tag>password "<M>text</M>"</tag> An 8-byte or 16-byte password used for authentication. - - <tag>id <M>num</M></tag> - ID of the password, (0-255). If it's not used, BIRD will choose - ID based on an order of the password item in the interface. For - example, second password item in one interface will have default - ID 2. - - <tag>generate from <M>date</M></tag> - The start time of the usage of the password for packet signing. - - <tag>generate to <M>date</M></tag> - The last time of the usage of the password for packet signing. - - <tag>accept from <M>date</M></tag> - The start time of the usage of the password for packet verification. - - <tag>accept to <M>date</M></tag> - The last time of the usage of the password for packet verification. + See <ref id="dsc-pass" name="password"> common option for detailed description. <tag>neighbors { <m/set/ } </tag> A set of neighbors to which Hello messages on nonbroadcast networks @@ -1313,7 +1381,7 @@ protocol ospf MyOSPF { accept; } reject; - }; + }; area 0.0.0.0 { interface "eth*" { cost 11; @@ -1326,17 +1394,15 @@ protocol ospf MyOSPF { interface "ppp*" { cost 100; authentication cryptographic; - passwords { - password "abc" { - id 1; - generate to "22-04-2003 11:00:06"; - accept from "17-01-2001 12:01:05"; - }; - password "def" { - id 2; - generate to "22-07-2005 17:03:21"; - accept from "22-02-2001 11:34:06"; - }; + password "abc" { + id 1; + generate to "22-04-2003 11:00:06"; + accept from "17-01-2001 12:01:05"; + }; + password "def" { + id 2; + generate to "22-07-2005 17:03:21"; + accept from "22-02-2001 11:34:06"; }; }; interface "arc0" { @@ -1500,7 +1566,7 @@ because there are no good implementations of OSPFv3. <tag/authentication none|plaintext|md5/ selects authentication method to be used. <cf/none/ means that packets are not authenticated at all, <cf/plaintext/ means that a plaintext password is embedded into each packet, and <cf/md5/ means that packets are authenticated using a MD5 cryptographic - hash. If you set authentication to not-none, it is a good idea to add <cf>passwords { }</cf> + hash. If you set authentication to not-none, it is a good idea to add <cf>password</cf> section. Default: none. <tag>honor always|neighbor|never </tag>specifies when should requests for dumping routing table @@ -1565,8 +1631,8 @@ protocol rip MyRIP_test { port 1520; period 10; garbage time 60; - interface "eth0" { metric 3; mode multicast; } - "eth1" { metric 2; mode broadcast; }; + interface "eth0" { metric 3; mode multicast; }; + interface "eth*" { metric 2; mode broadcast; }; honor neighbor; authentication none; import filter { print "importing"; accept; }; diff --git a/nest/config.Y b/nest/config.Y index d500f458..efff1313 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -18,6 +18,7 @@ CF_DEFINES static struct proto_config *this_proto; static struct iface_patt *this_ipatt; +static struct iface_patt_node *this_ipn; static list *this_p_list; static struct password_item *this_p_item; static int password_id; @@ -146,12 +147,36 @@ debug_default: /* Interface patterns */ -iface_patt: - TEXT { this_ipatt->pattern = $1; this_ipatt->prefix = IPA_NONE; this_ipatt->pxlen = 0; } - | prefix { this_ipatt->pattern = NULL; this_ipatt->prefix = $1.addr; this_ipatt->pxlen = $1.len; } - | TEXT prefix { this_ipatt->pattern = $1; this_ipatt->prefix = $2.addr; this_ipatt->pxlen = $2.len; } +iface_patt_node_init: + /* EMPTY */ { + struct iface_patt_node *ipn = cfg_allocz(sizeof(struct iface_patt_node)); + add_tail(&this_ipatt->ipn_list, NODE ipn); + this_ipn = ipn; + } + ; + +iface_patt_node_body: + TEXT { this_ipn->pattern = $1; this_ipn->prefix = IPA_NONE; this_ipn->pxlen = 0; } + | prefix { this_ipn->pattern = NULL; this_ipn->prefix = $1.addr; this_ipn->pxlen = $1.len; } + | TEXT prefix { this_ipn->pattern = $1; this_ipn->prefix = $2.addr; this_ipn->pxlen = $2.len; } + ; + +iface_negate: + { this_ipn->positive = 1; } + | '-' { this_ipn->positive = 0; } + ; + +iface_patt_node: + iface_patt_node_init iface_negate iface_patt_node_body + ; + + +iface_patt_list: + iface_patt_node + | iface_patt_list ',' iface_patt_node ; + /* Direct device route protocol */ CF_ADDTO(proto, dev_proto '}') @@ -167,25 +192,20 @@ dev_proto_start: proto_start DIRECT { dev_proto: dev_proto_start proto_name '{' | dev_proto proto_item ';' - | dev_proto dev_iface_list ';' + | dev_proto dev_iface_patt ';' ; -dev_iface_entry_init: +dev_iface_init: /* EMPTY */ { struct rt_dev_config *p = (void *) this_proto; - struct iface_patt *k = cfg_allocz(sizeof(struct iface_patt)); - add_tail(&p->iface_list, &k->n); - this_ipatt = k; + this_ipatt = cfg_allocz(sizeof(struct iface_patt)); + add_tail(&p->iface_list, NODE this_ipatt); + init_list(&this_ipatt->ipn_list); } ; -dev_iface_entry: - dev_iface_entry_init iface_patt - ; - -dev_iface_list: - INTERFACE dev_iface_entry - | dev_iface_list ',' dev_iface_entry +dev_iface_patt: + INTERFACE dev_iface_init iface_patt_list ; /* Debug flags */ diff --git a/nest/iface.c b/nest/iface.c index 157a977a..01f25810 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -543,32 +543,72 @@ if_init(void) * Interface Pattern Lists */ -struct iface_patt * -iface_patt_match(list *l, struct iface *i) +static int +iface_patt_match(struct iface_patt *ifp, struct iface *i) { - struct iface_patt *p; + struct iface_patt_node *p; - WALK_LIST(p, *l) + WALK_LIST(p, ifp->ipn_list) { char *t = p->pattern; - int ok = 1; + int pos = p->positive; + if (t) { if (*t == '-') { t++; - ok = 0; + pos = !pos; } + if (!patmatch(t, i->name)) continue; } - if (!i->addr || !ipa_in_net(i->addr->ip, p->prefix, p->pxlen)) - continue; - return ok ? p : NULL; + + if (p->pxlen) + if (!i->addr || !ipa_in_net(i->addr->ip, p->prefix, p->pxlen)) + continue; + + return pos; } + + return 0; +} + +struct iface_patt * +iface_patt_find(list *l, struct iface *i) +{ + struct iface_patt *p; + + WALK_LIST(p, *l) + if (iface_patt_match(p, i)) + return p; + return NULL; } +static int +iface_plists_equal(struct iface_patt *pa, struct iface_patt *pb) +{ + struct iface_patt_node *x, *y; + + x = HEAD(pa->ipn_list); + y = HEAD(pb->ipn_list); + while (x->n.next && y->n.next) + { + if ((x->positive != y->positive) || + (!x->pattern && y->pattern) || /* This nasty lines where written by me... :-( Feela */ + (!y->pattern && x->pattern) || + ((x->pattern != y->pattern) && strcmp(x->pattern, y->pattern)) || + !ipa_equal(x->prefix, y->prefix) || + (x->pxlen != y->pxlen)) + return 0; + x = (void *) x->n.next; + y = (void *) y->n.next; + } + return (!x->n.next && !y->n.next); +} + int iface_patts_equal(list *a, list *b, int (*comp)(struct iface_patt *, struct iface_patt *)) { @@ -578,13 +618,8 @@ iface_patts_equal(list *a, list *b, int (*comp)(struct iface_patt *, struct ifac y = HEAD(*b); while (x->n.next && y->n.next) { - if ((!x->pattern && y->pattern) || /* This nasty lines where written by me... :-( Feela */ - (!y->pattern && x->pattern) || - (!(x->pattern==y->pattern) && - strcmp(x->pattern, y->pattern)) || - !ipa_equal(x->prefix, y->prefix) || - x->pxlen != y->pxlen || - comp && !comp(x, y)) + if (!iface_plists_equal(x, y) || + (comp && !comp(x, y))) return 0; x = (void *) x->n.next; y = (void *) y->n.next; diff --git a/nest/iface.h b/nest/iface.h index e37f9522..f884dd90 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -116,16 +116,22 @@ void neigh_init(struct pool *); * Interface Pattern Lists */ -struct iface_patt { +struct iface_patt_node { node n; - byte *pattern; /* Interface name pattern */ - ip_addr prefix; /* Interface prefix */ + int positive; + byte *pattern; + ip_addr prefix; int pxlen; +}; + +struct iface_patt { + node n; + list ipn_list; /* A list of struct iface_patt_node */ /* Protocol-specific data follow after this structure */ }; -struct iface_patt *iface_patt_match(list *, struct iface *); +struct iface_patt *iface_patt_find(list *, struct iface *); int iface_patts_equal(list *, list *, int (*)(struct iface_patt *, struct iface_patt *)); #endif diff --git a/nest/rt-dev.c b/nest/rt-dev.c index 269346de..348bcc2e 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -30,7 +30,7 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad) struct rt_dev_config *P = (void *) p->cf; if (!EMPTY_LIST(P->iface_list) && - !iface_patt_match(&P->iface_list, ad->iface)) + !iface_patt_find(&P->iface_list, ad->iface)) /* Empty list is automagically treated as "*" */ return; if (c & IF_CHANGE_DOWN) diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index a015c2b3..8a849e73 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -786,18 +786,13 @@ bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p put_u16(z+2, p->local_as); } - z = bgp_set_attr_wa(ea->attrs+2, pool, BA_NEXT_HOP, sizeof(ip_addr)); + z = bgp_set_attr_wa(ea->attrs+2, pool, BA_NEXT_HOP, NEXT_HOP_LENGTH); if (p->cf->next_hop_self || - !p->is_internal || - rta->dest != RTD_ROUTER) - { - if (ipa_nonzero(p->cf->source_addr)) - *(ip_addr *)z = p->cf->source_addr; - else - *(ip_addr *)z = p->local_addr; - } + rta->dest != RTD_ROUTER || + (!p->is_internal && (e->attrs->iface != p->neigh->iface))) + set_next_hop(z, p->source_addr); else - *(ip_addr *)z = e->attrs->gw; + set_next_hop(z, e->attrs->gw); bgp_set_attr(ea->attrs+3, BA_LOCAL_PREF, 0); @@ -860,14 +855,15 @@ bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p } a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP)); - if (a && (p->is_internal || (!p->is_internal && e->attrs->iface == p->neigh->iface))) + if (a && !p->cf->next_hop_self && (p->is_internal || (!p->is_internal && e->attrs->iface == p->neigh->iface))) { /* Leave the original next hop attribute, will check later where does it point */ } else { /* Need to create new one */ - bgp_attach_attr_ip(attrs, pool, BA_NEXT_HOP, p->local_addr); + byte *b = bgp_attach_attr_wa(attrs, pool, BA_NEXT_HOP, NEXT_HOP_LENGTH); + set_next_hop(b, p->source_addr); } if (rr) diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 41c8d533..cbc699bb 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -500,10 +500,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c DBG("BGP: Connecting\n"); s = sk_new(p->p.pool); s->type = SK_TCP_ACTIVE; - if (ipa_nonzero(p->cf->source_addr)) - s->saddr = p->cf->source_addr; - else - s->saddr = p->local_addr; + s->saddr = p->source_addr; s->daddr = p->cf->remote_ip; s->dport = BGP_PORT; s->ttl = p->cf->multihop ? : 1; @@ -609,17 +606,23 @@ static void bgp_start_neighbor(struct bgp_proto *p) { p->local_addr = p->neigh->iface->addr->ip; - DBG("BGP: local=%I remote=%I\n", p->local_addr, p->next_hop); + p->source_addr = ipa_nonzero(p->cf->source_addr) ? p->cf->source_addr : p->local_addr; + + DBG("BGP: local=%I remote=%I\n", p->source_addr, p->next_hop); #ifdef IPV6 { struct ifa *a; - p->local_link = ipa_or(ipa_build(0xfe80,0,0,0), ipa_and(p->local_addr, ipa_build(0,0,~0,~0))); + p->local_link = IPA_NONE; WALK_LIST(a, p->neigh->iface->addrs) if (a->scope == SCOPE_LINK) { p->local_link = a->ip; break; } + + if (! ipa_nonzero(p->local_link)) + log(L_WARN "%s: Missing link local address on interface %s", p->p.name, p->neigh->iface->name); + DBG("BGP: Selected link-level address %I\n", p->local_link); } #endif diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index d5448a68..8477f9e5 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -79,6 +79,7 @@ struct bgp_proto { ip_addr next_hop; /* Either the peer or multihop_via */ struct neighbor *neigh; /* Neighbor entry corresponding to next_hop */ ip_addr local_addr; /* Address of the local end of the link to next_hop */ + ip_addr source_addr; /* Address used as advertised next hop, usually local_addr */ struct event *event; /* Event for respawning and shutting process */ struct bgp_bucket **bucket_hash; /* Hash table of attribute buckets */ unsigned int hash_size, hash_count, hash_limit; @@ -147,6 +148,17 @@ void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code /* attrs.c */ +/* Hack: although BA_NEXT_HOP attribute has type EAF_TYPE_IP_ADDRESS, in IPv6 + * we store two addesses in it - a global address and a link local address. + */ +#ifdef IPV6 +#define NEXT_HOP_LENGTH (2*sizeof(ip_addr)) +static inline void set_next_hop(byte *b, ip_addr addr) { ((ip_addr *) b)[0] = addr; ((ip_addr *) b)[1] = IPA_NONE; } +#else +#define NEXT_HOP_LENGTH sizeof(ip_addr) +static inline void set_next_hop(byte *b, ip_addr addr) { ((ip_addr *) b)[0] = addr; } +#endif + void bgp_attach_attr(struct ea_list **to, struct linpool *pool, unsigned attr, uintptr_t val); byte *bgp_attach_attr_wa(struct ea_list **to, struct linpool *pool, unsigned attr, unsigned len); struct rta *bgp_decode_attrs(struct bgp_conn *conn, byte *a, unsigned int len, struct linpool *pool, int mandatory); diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 1370ee70..27adc166 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -234,10 +234,10 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) { struct bgp_proto *p = conn->bgp; struct bgp_bucket *buck; - int size, is_ll; + int size; int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4; byte *w, *tmp, *tstart; - ip_addr ip, ip_ll; + ip_addr *ipp, ip, ip_ll; ea_list *ea; eattr *nh; neighbor *n; @@ -291,26 +291,42 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) *tmp++ = 1; nh = ea_find(buck->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP)); ASSERT(nh); - ip = *(ip_addr *) nh->u.ptr->data; - is_ll = 0; - if (ipa_equal(ip, p->local_addr)) - { - is_ll = 1; - ip_ll = p->local_link; - } + + /* We have two addresses here in 'nh'. Really. */ + ipp = (ip_addr *) nh->u.ptr->data; + ip = ipp[0]; + ip_ll = IPA_NONE; + + if (ipa_equal(ip, p->source_addr)) + ip_ll = p->local_link; else { + /* If we send a route with 'third party' next hop destinated + * in the same interface, we should also send a link local + * next hop address. We use the received one (stored in the + * other part of BA_NEXT_HOP eattr). If we didn't received + * it (for example it is a static route), we can't use + * 'third party' next hop and we have to use local IP address + * as next hop. Sending original next hop address without + * link local address seems to be a natural way to solve that + * problem, but it is contrary to RFC 2545 and Quagga does not + * accept such routes. + */ + n = neigh_find(&p->p, &ip, 0); if (n && n->iface == p->neigh->iface) { - /* FIXME: We are assuming the global scope addresses use the lower 64 bits - * as an interface identifier which hasn't necessarily to be true. - */ - is_ll = 1; - ip_ll = ipa_or(ipa_build(0xfe800000,0,0,0), ipa_and(ip, ipa_build(0,0,~0,~0))); + if (ipa_nonzero(ipp[1])) + ip_ll = ipp[1]; + else + { + ip = p->source_addr; + ip_ll = p->local_link; + } } } - if (is_ll) + + if (ipa_nonzero(ip_ll)) { *tmp++ = 32; ipa_hton(ip); @@ -326,6 +342,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) memcpy(tmp, &ip, 16); tmp += 16; } + *tmp++ = 0; /* No SNPA information */ tmp += bgp_encode_prefixes(p, tmp, buck, remains - (8+3+32+1)); ea->attrs[0].u.ptr->length = tmp - tstart; @@ -778,9 +795,18 @@ bgp_do_rx_update(struct bgp_conn *conn, if (len < 1 || (*x != 16 && *x != 32) || len < *x + 2) goto bad; - byte *nh = bgp_attach_attr_wa(&a0->eattrs, bgp_linpool, BA_NEXT_HOP, 16); + ip_addr *nh = (ip_addr *) bgp_attach_attr_wa(&a0->eattrs, bgp_linpool, BA_NEXT_HOP, NEXT_HOP_LENGTH); memcpy(nh, x+1, 16); - ipa_ntoh(*(ip_addr *)nh); + ipa_ntoh(nh[0]); + + /* We store received link local address in the other part of BA_NEXT_HOP eattr. */ + if (*x == 32) + { + memcpy(nh+1, x+17, 16); + ipa_ntoh(nh[1]); + } + else + nh[1] = IPA_NONE; /* Also ignore one reserved byte */ len -= *x + 2; diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index bfe2d9c8..7f7d6a31 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -13,9 +13,9 @@ CF_HDR CF_DEFINES #define OSPF_CFG ((struct ospf_config *) this_proto) -static struct ospf_area_config *this_area; -static struct iface_patt *this_ipatt; #define OSPF_PATT ((struct ospf_iface_patt *) this_ipatt) + +static struct ospf_area_config *this_area; static struct nbma_node *this_nbma; static struct area_net_config *this_pref; @@ -90,7 +90,7 @@ ospf_area_item: STUB COST expr { this_area->stub = $3 ; if($3<=0) cf_error("Stub cost must be greater than zero"); } | STUB bool {if($2) { if(!this_area->stub) this_area->stub=DEFAULT_STUB_COST;}else{ this_area->stub=0;}} | NETWORKS '{' pref_list '}' - | INTERFACE ospf_iface_list + | INTERFACE ospf_iface | ospf_vlink ; @@ -122,6 +122,7 @@ ospf_vlink_start: VIRTUAL LINK idval if (this_area->areaid == 0) cf_error("Virtual link cannot be in backbone"); this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt)); add_tail(&this_area->vlink_list, NODE this_ipatt); + init_list(&this_ipatt->ipn_list); OSPF_PATT->vid = $3; OSPF_PATT->cost = COST_D; OSPF_PATT->helloint = HELLOINT_D; @@ -222,6 +223,7 @@ ospf_iface_start: { this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt)); add_tail(&this_area->patt_list, NODE this_ipatt); + init_list(&this_ipatt->ipn_list); OSPF_PATT->cost = COST_D; OSPF_PATT->helloint = HELLOINT_D; OSPF_PATT->pollint = POLLINT_D; @@ -251,12 +253,7 @@ ospf_iface_opt_list: ; ospf_iface: - ospf_iface_start iface_patt ospf_iface_opt_list { finish_iface_config(OSPF_PATT); } - ; - -ospf_iface_list: - ospf_iface - | ospf_iface_list ',' ospf_iface + ospf_iface_start iface_patt_list ospf_iface_opt_list { finish_iface_config(OSPF_PATT); } ; opttext: diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index a4c97413..5162f9f0 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -550,7 +550,7 @@ ospf_iface_notify(struct proto *p, unsigned flags, struct iface *iface) WALK_LIST(ac, c->area_list) { if (ip = (struct ospf_iface_patt *) - iface_patt_match(&ac->patt_list, iface)) + iface_patt_find(&ac->patt_list, iface)) break; } diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index 1eae3762..0cab1d7b 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -634,11 +634,11 @@ ospf_reconfigure(struct proto *p, struct proto_config *c) WALK_LIST(ifa, po->iface_list) { if (oldip = (struct ospf_iface_patt *) - iface_patt_match(&oldac->patt_list, ifa->iface)) + iface_patt_find(&oldac->patt_list, ifa->iface)) { /* Now reconfigure interface */ if (!(newip = (struct ospf_iface_patt *) - iface_patt_match(&newac->patt_list, ifa->iface))) + iface_patt_find(&newac->patt_list, ifa->iface))) return 0; /* HELLO TIMER */ diff --git a/proto/rip/config.Y b/proto/rip/config.Y index f1ae43cb..9a11069e 100644 --- a/proto/rip/config.Y +++ b/proto/rip/config.Y @@ -55,7 +55,7 @@ rip_cfg: | rip_cfg HONOR ALWAYS ';' { RIP_CFG->honor = HO_ALWAYS; } | rip_cfg HONOR NEIGHBOR ';' { RIP_CFG->honor = HO_NEIGHBOR; } | rip_cfg HONOR NEVER ';' { RIP_CFG->honor = HO_NEVER; } - | rip_cfg rip_iface_list ';' + | rip_cfg INTERFACE rip_iface ';' ; rip_auth: @@ -64,6 +64,7 @@ rip_auth: | NONE { $$=AT_NONE; } ; + rip_mode: BROADCAST { $$=IM_BROADCAST; } | MULTICAST { $$=0; } @@ -78,28 +79,26 @@ rip_iface_item: ; rip_iface_opts: - '{' + /* empty */ | rip_iface_opts rip_iface_item ';' ; -rip_iface_opt_list: /* EMPTY */ | rip_iface_opts '}' ; +rip_iface_opt_list: + /* empty */ + | '{' rip_iface_opts '}' + ; rip_iface_init: /* EMPTY */ { - struct rip_patt *k = cfg_allocz(sizeof(struct rip_patt)); - k->metric = 1; - add_tail(&RIP_CFG->iface_list, &k->i.n); - this_ipatt = &k->i; + this_ipatt = cfg_allocz(sizeof(struct rip_patt)); + add_tail(&RIP_CFG->iface_list, NODE this_ipatt); + init_list(&this_ipatt->ipn_list); + RIP_IPATT->metric = 1; } ; rip_iface: - rip_iface_init iface_patt rip_iface_opt_list - ; - -rip_iface_list: - INTERFACE rip_iface - | rip_iface_list ',' rip_iface + rip_iface_init iface_patt_list rip_iface_opt_list ; CF_ADDTO(dynamic_attr, RIP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_RIP_METRIC); }) diff --git a/proto/rip/rip.c b/proto/rip/rip.c index b5a4cc36..12cc8783 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -742,7 +742,7 @@ rip_real_if_add(struct object_lock *lock) struct iface *iface = lock->iface; struct proto *p = lock->data; struct rip_interface *rif; - struct iface_patt *k = iface_patt_match(&P_CF->iface_list, iface); + struct iface_patt *k = iface_patt_find(&P_CF->iface_list, iface); if (!k) bug("This can not happen! It existed few seconds ago!" ); @@ -771,7 +771,7 @@ rip_if_notify(struct proto *p, unsigned c, struct iface *iface) } } if (c & IF_CHANGE_UP) { - struct iface_patt *k = iface_patt_match(&P_CF->iface_list, iface); + struct iface_patt *k = iface_patt_find(&P_CF->iface_list, iface); struct object_lock *lock; struct rip_patt *PATT = (struct rip_patt *) k; diff --git a/sysdep/linux/netlink/netlink.c b/sysdep/linux/netlink/netlink.c index 4c81aa62..e586847a 100644 --- a/sysdep/linux/netlink/netlink.c +++ b/sysdep/linux/netlink/netlink.c @@ -42,16 +42,16 @@ struct nl_sock { int fd; u32 seq; + byte *rx_buffer; /* Receive buffer */ + struct nlmsghdr *last_hdr; /* Recently received packet */ + unsigned int last_size; }; -static struct nl_sock nl_scan = {-1, 0}; /* Netlink socket for synchronous scan */ -static struct nl_sock nl_req = {-1, 0}; /* Netlink socket for requests */ - -static byte *nl_rx_buffer; /* Receive buffer */ #define NL_RX_SIZE 8192 -static struct nlmsghdr *nl_last_hdr; /* Recently received packet */ -static unsigned int nl_last_size; +static struct nl_sock nl_scan = {.fd = -1}; /* Netlink socket for synchronous scan */ +static struct nl_sock nl_req = {.fd = -1}; /* Netlink socket for requests */ + static void nl_open_sock(struct nl_sock *nl) @@ -62,6 +62,9 @@ nl_open_sock(struct nl_sock *nl) if (nl->fd < 0) die("Unable to open rtnetlink socket: %m"); nl->seq = now; + nl->rx_buffer = xmalloc(NL_RX_SIZE); + nl->last_hdr = NULL; + nl->last_size = 0; } } @@ -70,9 +73,6 @@ nl_open(void) { nl_open_sock(&nl_scan); nl_open_sock(&nl_req); - - if (nl_rx_buffer == NULL) - nl_rx_buffer = xmalloc(NL_RX_SIZE); } static void @@ -86,7 +86,7 @@ nl_send(struct nl_sock *nl, struct nlmsghdr *nh) nh->nlmsg_seq = ++(nl->seq); if (sendto(nl->fd, nh, nh->nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) die("rtnetlink sendto: %m"); - nl_last_hdr = NULL; + nl->last_hdr = NULL; } static void @@ -108,9 +108,9 @@ nl_get_reply(struct nl_sock *nl) { for(;;) { - if (!nl_last_hdr) + if (!nl->last_hdr) { - struct iovec iov = { nl_rx_buffer, NL_RX_SIZE }; + struct iovec iov = { nl->rx_buffer, NL_RX_SIZE }; struct sockaddr_nl sa; struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 }; int x = recvmsg(nl->fd, &m, 0); @@ -121,15 +121,15 @@ nl_get_reply(struct nl_sock *nl) DBG("Non-kernel packet\n"); continue; } - nl_last_size = x; - nl_last_hdr = (void *) nl_rx_buffer; + nl->last_size = x; + nl->last_hdr = (void *) nl->rx_buffer; if (m.msg_flags & MSG_TRUNC) bug("nl_get_reply: got truncated reply which should be impossible"); } - if (NLMSG_OK(nl_last_hdr, nl_last_size)) + if (NLMSG_OK(nl->last_hdr, nl->last_size)) { - struct nlmsghdr *h = nl_last_hdr; - nl_last_hdr = NLMSG_NEXT(h, nl_last_size); + struct nlmsghdr *h = nl->last_hdr; + nl->last_hdr = NLMSG_NEXT(h, nl->last_size); if (h->nlmsg_seq != nl->seq) { log(L_WARN "nl_get_reply: Ignoring out of sequence netlink packet (%x != %x)", @@ -138,9 +138,9 @@ nl_get_reply(struct nl_sock *nl) } return h; } - if (nl_last_size) - log(L_WARN "nl_get_reply: Found packet remnant of size %d", nl_last_size); - nl_last_hdr = NULL; + if (nl->last_size) + log(L_WARN "nl_get_reply: Found packet remnant of size %d", nl->last_size); + nl->last_hdr = NULL; } } @@ -797,7 +797,6 @@ nl_async_hook(sock *sk, int size UNUSED) int x; unsigned int len; - nl_last_hdr = NULL; /* Discard packets accidentally remaining in the rxbuf */ x = recvmsg(sk->fd, &m, 0); if (x < 0) { |