summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/bird.sgml176
-rw-r--r--nest/config.Y52
-rw-r--r--nest/iface.c67
-rw-r--r--nest/iface.h14
-rw-r--r--nest/rt-dev.c2
-rw-r--r--proto/bgp/attrs.c20
-rw-r--r--proto/bgp/bgp.c15
-rw-r--r--proto/bgp/bgp.h12
-rw-r--r--proto/bgp/packets.c60
-rw-r--r--proto/ospf/config.Y15
-rw-r--r--proto/ospf/iface.c2
-rw-r--r--proto/ospf/ospf.c4
-rw-r--r--proto/rip/config.Y25
-rw-r--r--proto/rip/rip.c4
-rw-r--r--sysdep/linux/netlink/netlink.c41
15 files changed, 334 insertions, 175 deletions
diff --git a/doc/bird.sgml b/doc/bird.sgml
index f62881c..c73872b 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 &le; ip1 &le; len2</cf>.
- A valid prefix pattern has to satisfy <cf/low &le; 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 &lt;= ip1 &lt;= len2</cf>.
+ A valid prefix pattern has to satisfy <cf>low &lt;= 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 &tilde; [ 1.0.0.0/8{ 15 , 17 } ]</cf> is true,
+ <cf>1.2.3.4</cf>. <cf>1.2.0.0/16 &tilde; [ 1.0.0.0/8{15,17} ]</cf> is true,
but <cf>1.0.0.0/16 &tilde; [ 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 &lt;name&gt; {
<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 &lt;name&gt; {
<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 d500f45..efff131 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 157a977..01f2581 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 e37f952..f884dd9 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 269346d..348bcc2 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 a015c2b..8a849e7 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 41c8d53..cbc699b 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 d5448a6..8477f9e 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 1370ee7..27adc16 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 bfe2d9c..7f7d6a3 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 a4c9741..5162f9f 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 1eae376..0cab1d7 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 f1ae43c..9a11069 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 b5a4cc3..12cc878 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 4c81aa6..e586847 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)
{