Merge branch 'int-new' into nexthop-merged
This commit is contained in:
commit
c609d03986
39 changed files with 1284 additions and 455 deletions
23
NEWS
23
NEWS
|
@ -1,3 +1,26 @@
|
||||||
|
Version 2.0.0-pre0 (2016-12-07)
|
||||||
|
o Integrated IPv4 + IPv6 design
|
||||||
|
o Major BGP protocol redesign
|
||||||
|
o BGP multicast support (SAFI 2)
|
||||||
|
o BGP flowspec support (RFC 5575)
|
||||||
|
o New RPKI-Router protocol
|
||||||
|
o New build system
|
||||||
|
o Unit tests
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
Protocols and tables are now connected using explicit channels, most related
|
||||||
|
protocol options (table, import, export, ...) are now channel options. See
|
||||||
|
doc/bird.conf.example2 for configuration examples.
|
||||||
|
|
||||||
|
|
||||||
|
Version 1.6.3 (2016-12-21)
|
||||||
|
o Large BGP communities
|
||||||
|
o BFD authentication (MD5, SHA1)
|
||||||
|
o SHA1 and SHA2 authentication for RIP and OSPF
|
||||||
|
o Improved documentation
|
||||||
|
o Several bug fixes
|
||||||
|
|
||||||
Version 1.6.2 (2016-09-29)
|
Version 1.6.2 (2016-09-29)
|
||||||
o Fixes serious bug introduced in the previous version
|
o Fixes serious bug introduced in the previous version
|
||||||
|
|
||||||
|
|
|
@ -186,8 +186,7 @@ fi
|
||||||
|
|
||||||
AC_SUBST(iproutedir)
|
AC_SUBST(iproutedir)
|
||||||
|
|
||||||
# all_protocols="$proto_bfd babel bgp ospf pipe radv rip $proto_rpki static"
|
all_protocols="$proto_bfd babel bgp ospf pipe radv rip $proto_rpki static"
|
||||||
all_protocols="$proto_bfd bgp ospf pipe radv rip $proto_rpki static "
|
|
||||||
|
|
||||||
all_protocols=`echo $all_protocols | sed 's/ /,/g'`
|
all_protocols=`echo $all_protocols | sed 's/ /,/g'`
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This is an example configuration file.
|
* This is an example configuration file
|
||||||
|
* (for version 1.x.x, obsolete)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
# Yes, even shell-like comments work...
|
# Yes, even shell-like comments work...
|
||||||
|
|
267
doc/bird.conf.example2
Normal file
267
doc/bird.conf.example2
Normal file
|
@ -0,0 +1,267 @@
|
||||||
|
/*
|
||||||
|
* This is an example configuration file for MB-BGP setting
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
log "bird.log" all;
|
||||||
|
# debug protocols all;
|
||||||
|
|
||||||
|
router id 192.168.1.1;
|
||||||
|
|
||||||
|
ipv4 table master4;
|
||||||
|
ipv6 table master6;
|
||||||
|
|
||||||
|
ipv4 table mcast4;
|
||||||
|
ipv6 table mcast6;
|
||||||
|
|
||||||
|
flow4 table flowtab4;
|
||||||
|
flow6 table flowtab6;
|
||||||
|
|
||||||
|
|
||||||
|
protocol device {
|
||||||
|
scan time 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol kernel kernel4 {
|
||||||
|
scan time 20;
|
||||||
|
|
||||||
|
ipv4 {
|
||||||
|
export all;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol kernel kernel6 {
|
||||||
|
scan time 20;
|
||||||
|
|
||||||
|
ipv6 {
|
||||||
|
export all;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protocol static static4 {
|
||||||
|
ipv4;
|
||||||
|
|
||||||
|
route 10.10.0.0/24 via 192.168.1.2;
|
||||||
|
route 10.10.1.0/24 via 192.168.1.2 { bgp_large_community.add((10,20,30)); bgp_large_community.add((10,(20*3),10)); };
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol static static6 {
|
||||||
|
ipv6;
|
||||||
|
|
||||||
|
route 2001:db8:10:10::/64 via 2001:db8:1:1::10;
|
||||||
|
route 2001:db8:10:11::/64 via 2001:db8:1:1::10;
|
||||||
|
|
||||||
|
route 2001:db8:1:1::/64 via fe80::ec9b:67ff:fe60:fd5d % ve1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# RFC 5575 flow specification
|
||||||
|
protocol static flowstat4 {
|
||||||
|
flow4;
|
||||||
|
|
||||||
|
route flow4 {
|
||||||
|
dst 10.0.0.0/8;
|
||||||
|
proto = 23;
|
||||||
|
dport > 24 && < 30 || 40..50,60..70,80;
|
||||||
|
sport > 24 && < 30 || = 40 || 50,60..70,80;
|
||||||
|
icmp type 80;
|
||||||
|
icmp code 90;
|
||||||
|
tcp flags 0x03/0x0f;
|
||||||
|
length 2048..65535;
|
||||||
|
dscp = 63;
|
||||||
|
fragment dont_fragment, is_fragment || !first_fragment;
|
||||||
|
} drop;
|
||||||
|
|
||||||
|
route flow4 {
|
||||||
|
dst 11.0.0.0/8;
|
||||||
|
proto = 0x12;
|
||||||
|
sport > 0x5678 && < 0x9abc || 0xdef0 || 0x1234,0x5678,0x9abc..0xdef0;
|
||||||
|
dport = 50;
|
||||||
|
tcp flags 0xabcd/0xbbdd;
|
||||||
|
} drop;
|
||||||
|
|
||||||
|
route flow4 {
|
||||||
|
dst 12.0.0.0/32;
|
||||||
|
tcp flags ! 0 / 0x9999;
|
||||||
|
} drop;
|
||||||
|
|
||||||
|
route flow4 {
|
||||||
|
dst 220.0.254.0/24;
|
||||||
|
tcp flags 0x99 / 0x9999;
|
||||||
|
} drop;
|
||||||
|
|
||||||
|
route flow4 {
|
||||||
|
dst 220.0.254.192/28;
|
||||||
|
tcp flags !0xffff / 0xFFFF;
|
||||||
|
} drop;
|
||||||
|
|
||||||
|
route flow4 {
|
||||||
|
dst 15.0.0.0/8;
|
||||||
|
tcp flags !0x9999/0x9999;
|
||||||
|
} drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol static flowstat6 {
|
||||||
|
flow6;
|
||||||
|
|
||||||
|
route flow6 {
|
||||||
|
dst fec0:1122:3344:5566::1/128;
|
||||||
|
src 0000:0000:0000:0001:1234:5678:9800:0000/101 offset 63;
|
||||||
|
next header = 23;
|
||||||
|
sport 24..30, 42 || 50,60,70..80;
|
||||||
|
dport = 50;
|
||||||
|
tcp flags 0x03/0x0f, !0/0xff || 0x33/0x33;
|
||||||
|
fragment !is_fragment || !first_fragment;
|
||||||
|
label 0xaaaa/0xaaaa && 0x33/0x33;
|
||||||
|
} drop;
|
||||||
|
|
||||||
|
route flow6 {
|
||||||
|
dst fec0:1122:3344:5566::1/128;
|
||||||
|
src ::1:1234:5678:9800:0/101 offset 63;
|
||||||
|
next header = 23;
|
||||||
|
dport = 50;
|
||||||
|
sport > 24 && < 30 || = 40 || = 50 || = 60 || >= 70 && <= 80;
|
||||||
|
tcp flags 0x3/0x3 && 0x0/0xc;
|
||||||
|
} drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protocol pipe {
|
||||||
|
table master4;
|
||||||
|
peer table mcast4;
|
||||||
|
import none;
|
||||||
|
export where source = RTS_OSPF;
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol pipe {
|
||||||
|
table master6;
|
||||||
|
peer table mcast6;
|
||||||
|
import none;
|
||||||
|
export where source = RTS_OSPF;
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol ospf2 ospf4 {
|
||||||
|
# ecmp;
|
||||||
|
|
||||||
|
ipv4 {
|
||||||
|
import all;
|
||||||
|
# export where source = RTS_STATIC;
|
||||||
|
};
|
||||||
|
|
||||||
|
area 0 {
|
||||||
|
interface "ve0" { stub; };
|
||||||
|
interface "ve1" { hello 5; type ptp; };
|
||||||
|
interface "ve2" { hello 5; type bcast; ttl security; };
|
||||||
|
interface "ve3" { hello 5; type bcast; ttl security; };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protocol ospf3 ospf6 {
|
||||||
|
# ecmp;
|
||||||
|
|
||||||
|
ipv6 {
|
||||||
|
import all;
|
||||||
|
# export where source = RTS_STATIC;
|
||||||
|
};
|
||||||
|
|
||||||
|
area 0 {
|
||||||
|
interface "ve0" { stub; };
|
||||||
|
interface "ve1" { hello 5; type ptp; };
|
||||||
|
interface "ve2" { hello 5; type bcast; };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol bgp {
|
||||||
|
local 192.168.11.1 as 1000;
|
||||||
|
neighbor 192.168.11.2 as 2000;
|
||||||
|
# local 192.168.1.1 as 1000;
|
||||||
|
# neighbor 192.168.2.1 as 2000;
|
||||||
|
# multihop;
|
||||||
|
# rr client;
|
||||||
|
# strict bind;
|
||||||
|
# debug all;
|
||||||
|
|
||||||
|
# regular IPv4 unicast (1/1)
|
||||||
|
ipv4 {
|
||||||
|
# connects to master4 table by default
|
||||||
|
import all;
|
||||||
|
export where source ~ [ RTS_STATIC, RTS_BGP ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# regular IPv6 unicast (2/1)
|
||||||
|
ipv6 {
|
||||||
|
# connects to master6 table by default
|
||||||
|
import all;
|
||||||
|
export where source ~ [ RTS_STATIC, RTS_BGP ];
|
||||||
|
# next hop address 2001:db8:1:1::1;
|
||||||
|
};
|
||||||
|
|
||||||
|
# IPv4 multicast topology (1/2)
|
||||||
|
ipv4 multicast {
|
||||||
|
# explicit IPv4 table
|
||||||
|
table mcast4;
|
||||||
|
import all;
|
||||||
|
export all;
|
||||||
|
};
|
||||||
|
|
||||||
|
# IPv6 multicast topology (2/2)
|
||||||
|
ipv6 multicast {
|
||||||
|
# explicit IPv6 table
|
||||||
|
table mcast6;
|
||||||
|
import all;
|
||||||
|
export all;
|
||||||
|
# next hop address 2001:db8:1:1::1;
|
||||||
|
};
|
||||||
|
|
||||||
|
# IPv4 Flowspec (1/133)
|
||||||
|
flow4 {
|
||||||
|
# connects to flowtab4 table by default
|
||||||
|
import all;
|
||||||
|
export all;
|
||||||
|
};
|
||||||
|
|
||||||
|
# IPv6 Flowspec (2/133)
|
||||||
|
flow6 {
|
||||||
|
# connects to flowtab6 table by default
|
||||||
|
import all;
|
||||||
|
export all;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol bgp {
|
||||||
|
local 192.168.1.1 as 1000;
|
||||||
|
neighbor 192.168.3.1 as 1000;
|
||||||
|
multihop;
|
||||||
|
rr client;
|
||||||
|
|
||||||
|
ipv4 {
|
||||||
|
import all;
|
||||||
|
export where source ~ [ RTS_STATIC, RTS_BGP ];
|
||||||
|
};
|
||||||
|
|
||||||
|
ipv6 {
|
||||||
|
import all;
|
||||||
|
export where source ~ [ RTS_STATIC, RTS_BGP ];
|
||||||
|
next hop address 2001:db8:1:1::1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol bgp {
|
||||||
|
local 2001:db8:1:1::1 as 1000;
|
||||||
|
neighbor 2001:db8:4:1::1 as 1000;
|
||||||
|
multihop;
|
||||||
|
rr client;
|
||||||
|
|
||||||
|
ipv4 {
|
||||||
|
import all;
|
||||||
|
export where source ~ [ RTS_STATIC, RTS_BGP ];
|
||||||
|
next hop address 192.168.4.1;
|
||||||
|
};
|
||||||
|
|
||||||
|
ipv6 {
|
||||||
|
import all;
|
||||||
|
export where source ~ [ RTS_STATIC, RTS_BGP ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1945,12 +1945,11 @@ avoid routing loops.
|
||||||
|
|
||||||
<p>BIRD supports all requirements of the BGP4 standard as defined in
|
<p>BIRD supports all requirements of the BGP4 standard as defined in
|
||||||
<rfc id="4271"> It also supports the community attributes (<rfc id="1997">),
|
<rfc id="4271"> It also supports the community attributes (<rfc id="1997">),
|
||||||
capability negotiation (<rfc id="5492">), MD5 password authentication (<rfc
|
capability negotiation (<rfc id="5492">), MD5 password authentication
|
||||||
id="2385">), extended communities (<rfc id="4360">), route reflectors (<rfc
|
(<rfc id="2385">), extended communities (<rfc id="4360">), route reflectors
|
||||||
id="4456">), graceful restart (<rfc id="4724">), multiprotocol extensions
|
(<rfc id="4456">), AS confederations (<rfc id="5065">), graceful restart
|
||||||
(<rfc id="4760">), 4B AS numbers (<rfc id="4893">), and 4B AS numbers in
|
(<rfc id="4724">), multiprotocol extensions (<rfc id="4760">), 4B AS numbers
|
||||||
extended communities (<rfc id="5668">).
|
(<rfc id="4893">), and 4B AS numbers in extended communities (<rfc id="5668">).
|
||||||
|
|
||||||
|
|
||||||
For IPv6, it uses the standard multiprotocol extensions defined in
|
For IPv6, it uses the standard multiprotocol extensions defined in
|
||||||
<rfc id="4760"> and applied to IPv6 according to <rfc id="2545">.
|
<rfc id="4760"> and applied to IPv6 according to <rfc id="2545">.
|
||||||
|
@ -2041,6 +2040,16 @@ using the following configuration parameters:
|
||||||
source address for the BGP session. Default: the address of the local
|
source address for the BGP session. Default: the address of the local
|
||||||
end of the interface our neighbor is connected to.
|
end of the interface our neighbor is connected to.
|
||||||
|
|
||||||
|
<tag><label id="bgp-strict-bind">strict bind <m/switch/</tag>
|
||||||
|
Specify whether BGP listening socket should be bound to a specific local
|
||||||
|
address (the same as the <cf/source address/) and associated interface,
|
||||||
|
or to all addresses. Binding to a specific address could be useful in
|
||||||
|
cases like running multiple BIRD instances on a machine, each using its
|
||||||
|
IP address. Note that listening sockets bound to a specific address and
|
||||||
|
to all addresses collide, therefore either all BGP protocols (of the
|
||||||
|
same address family and using the same local port) should have set
|
||||||
|
<cf/strict bind/, or none of them. Default: disabled.
|
||||||
|
|
||||||
<tag><label id="bgp-next-hop-self">next hop self</tag>
|
<tag><label id="bgp-next-hop-self">next hop self</tag>
|
||||||
Avoid calculation of the Next Hop attribute and always advertise our own
|
Avoid calculation of the Next Hop attribute and always advertise our own
|
||||||
source address as a next hop. This needs to be used only occasionally to
|
source address as a next hop. This needs to be used only occasionally to
|
||||||
|
@ -2113,7 +2122,7 @@ using the following configuration parameters:
|
||||||
Note that full (ICMP protection, for example) <rfc id="5082"> support is
|
Note that full (ICMP protection, for example) <rfc id="5082"> support is
|
||||||
provided by Linux only. Default: disabled.
|
provided by Linux only. Default: disabled.
|
||||||
|
|
||||||
<tag><label id="bgp-pass">password <m/string/</tag>
|
<tag><label id="bgp-password">password <m/string/</tag>
|
||||||
Use this password for MD5 authentication of BGP sessions (<rfc id="2385">). When
|
Use this password for MD5 authentication of BGP sessions (<rfc id="2385">). When
|
||||||
used on BSD systems, see also <cf/setkey/ option below. Default: no
|
used on BSD systems, see also <cf/setkey/ option below. Default: no
|
||||||
authentication.
|
authentication.
|
||||||
|
@ -2134,6 +2143,21 @@ using the following configuration parameters:
|
||||||
accepting incoming connections. In passive mode, outgoing connections
|
accepting incoming connections. In passive mode, outgoing connections
|
||||||
are not initiated. Default: off.
|
are not initiated. Default: off.
|
||||||
|
|
||||||
|
<tag><label id="bgp-confederation">confederation <m/number/</tag>
|
||||||
|
BGP confederations (<rfc id="5065">) are collections of autonomous
|
||||||
|
systems that act as one entity to external systems, represented by one
|
||||||
|
confederation identifier (instead of AS numbers). This option allows to
|
||||||
|
enable BGP confederation behavior and to specify the local confederation
|
||||||
|
identifier. When BGP confederations are used, all BGP speakers that are
|
||||||
|
members of the BGP confederation should have the same confederation
|
||||||
|
identifier configured. Default: 0 (no confederation).
|
||||||
|
|
||||||
|
<tag><label id="bgp-confederation-member">confederation member <m/switch/</tag>
|
||||||
|
When BGP confederations are used, this option allows to specify whether
|
||||||
|
the BGP neighbor is a member of the same confederation as the local BGP
|
||||||
|
speaker. The option is unnecessary (and ignored) for IBGP sessions, as
|
||||||
|
the same AS number implies the same confederation. Default: no.
|
||||||
|
|
||||||
<tag><label id="bgp-rr-client">rr client</tag>
|
<tag><label id="bgp-rr-client">rr client</tag>
|
||||||
Be a route reflector and treat the neighbor as a route reflection
|
Be a route reflector and treat the neighbor as a route reflection
|
||||||
client. Default: disabled.
|
client. Default: disabled.
|
||||||
|
@ -2256,13 +2280,6 @@ using the following configuration parameters:
|
||||||
This option is relevant to IPv4 mode with enabled capability
|
This option is relevant to IPv4 mode with enabled capability
|
||||||
advertisement only. Default: on.
|
advertisement only. Default: on.
|
||||||
|
|
||||||
<tag><label id="bgp-route-limit">route limit <m/number/</tag>
|
|
||||||
The maximal number of routes that may be imported from the protocol. If
|
|
||||||
the route limit is exceeded, the connection is closed with an error.
|
|
||||||
Limit is currently implemented as <cf>import limit <m/number/ action
|
|
||||||
restart</cf>. This option is obsolete and it is replaced by
|
|
||||||
<ref id="proto-import-limit" name="import limit option">. Default: no limit.
|
|
||||||
|
|
||||||
<tag><label id="bgp-disable-after-error">disable after error <m/switch/</tag>
|
<tag><label id="bgp-disable-after-error">disable after error <m/switch/</tag>
|
||||||
When an error is encountered (either locally or by the other side),
|
When an error is encountered (either locally or by the other side),
|
||||||
disable the instance automatically and wait for an administrator to fix
|
disable the instance automatically and wait for an administrator to fix
|
||||||
|
|
|
@ -1578,6 +1578,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
||||||
case P('<','='): TWOARGS; break;
|
case P('<','='): TWOARGS; break;
|
||||||
|
|
||||||
case '!': ONEARG; break;
|
case '!': ONEARG; break;
|
||||||
|
case P('!', '~'):
|
||||||
case '~': TWOARGS; break;
|
case '~': TWOARGS; break;
|
||||||
case P('d','e'): ONEARG; break;
|
case P('d','e'): ONEARG; break;
|
||||||
|
|
||||||
|
|
|
@ -957,7 +957,7 @@ fragment_val_str(u8 val)
|
||||||
return "???";
|
return "???";
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static uint
|
||||||
net_format_flow(char *buf, uint blen, const byte *data, uint dlen, int ipv6)
|
net_format_flow(char *buf, uint blen, const byte *data, uint dlen, int ipv6)
|
||||||
{
|
{
|
||||||
buffer b = {
|
buffer b = {
|
||||||
|
@ -1125,7 +1125,7 @@ net_format_flow(char *buf, uint blen, const byte *data, uint dlen, int ipv6)
|
||||||
* of written chars. If final string is too large, the string will ends the with
|
* of written chars. If final string is too large, the string will ends the with
|
||||||
* ' ...}' sequence and zero-terminator.
|
* ' ...}' sequence and zero-terminator.
|
||||||
*/
|
*/
|
||||||
int
|
uint
|
||||||
flow4_net_format(char *buf, uint blen, const net_addr_flow4 *f)
|
flow4_net_format(char *buf, uint blen, const net_addr_flow4 *f)
|
||||||
{
|
{
|
||||||
return net_format_flow(buf, blen, f->data, f->length - sizeof(net_addr_flow4), 0);
|
return net_format_flow(buf, blen, f->data, f->length - sizeof(net_addr_flow4), 0);
|
||||||
|
@ -1141,7 +1141,7 @@ flow4_net_format(char *buf, uint blen, const net_addr_flow4 *f)
|
||||||
* of written chars. If final string is too large, the string will ends the with
|
* of written chars. If final string is too large, the string will ends the with
|
||||||
* ' ...}' sequence and zero-terminator.
|
* ' ...}' sequence and zero-terminator.
|
||||||
*/
|
*/
|
||||||
int
|
uint
|
||||||
flow6_net_format(char *buf, uint blen, const net_addr_flow6 *f)
|
flow6_net_format(char *buf, uint blen, const net_addr_flow6 *f)
|
||||||
{
|
{
|
||||||
return net_format_flow(buf, blen, f->data, f->length - sizeof(net_addr_flow6), 1);
|
return net_format_flow(buf, blen, f->data, f->length - sizeof(net_addr_flow6), 1);
|
||||||
|
|
|
@ -42,6 +42,9 @@ const char *flow_type_str(enum flow_type type, int ipv6);
|
||||||
|
|
||||||
uint flow_write_length(byte *data, u16 len);
|
uint flow_write_length(byte *data, u16 len);
|
||||||
|
|
||||||
|
static inline u16 flow_hdr_length(const byte *data)
|
||||||
|
{ return ((*data & 0xf0) == 0xf0) ? 2 : 1; }
|
||||||
|
|
||||||
static inline u16 flow_read_length(const byte *data)
|
static inline u16 flow_read_length(const byte *data)
|
||||||
{ return ((*data & 0xf0) == 0xf0) ? get_u16(data) & 0x0fff : *data; }
|
{ return ((*data & 0xf0) == 0xf0) ? get_u16(data) & 0x0fff : *data; }
|
||||||
|
|
||||||
|
@ -128,7 +131,7 @@ void flow6_validate_cf(net_addr_flow6 *f);
|
||||||
* Net Formatting
|
* Net Formatting
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int flow4_net_format(char *buf, uint blen, const net_addr_flow4 *f);
|
uint flow4_net_format(char *buf, uint blen, const net_addr_flow4 *f);
|
||||||
int flow6_net_format(char *buf, uint blen, const net_addr_flow6 *f);
|
uint flow6_net_format(char *buf, uint blen, const net_addr_flow6 *f);
|
||||||
|
|
||||||
#endif /* _BIRD_FLOWSPEC_H_ */
|
#endif /* _BIRD_FLOWSPEC_H_ */
|
||||||
|
|
|
@ -30,20 +30,17 @@ t_read_length(void)
|
||||||
{
|
{
|
||||||
byte data[] = { 0xcc, 0xcc, 0xcc };
|
byte data[] = { 0xcc, 0xcc, 0xcc };
|
||||||
|
|
||||||
u16 get;
|
|
||||||
u16 expect;
|
|
||||||
|
|
||||||
for (uint expect = 0; expect < 0xf0; expect++)
|
for (uint expect = 0; expect < 0xf0; expect++)
|
||||||
{
|
{
|
||||||
*data = expect;
|
*data = expect;
|
||||||
get = flow_read_length(data);
|
uint get = flow_read_length(data);
|
||||||
bt_assert_msg(get == expect, "Testing get length 0x%02x (get 0x%02x)", expect, get);
|
bt_assert_msg(get == expect, "Testing get length 0x%02x (get 0x%02x)", expect, get);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint expect = 0; expect <= 0xfff; expect++)
|
for (uint expect = 0; expect <= 0xfff; expect++)
|
||||||
{
|
{
|
||||||
put_u16(data, expect | 0xf000);
|
put_u16(data, expect | 0xf000);
|
||||||
get = flow_read_length(data);
|
uint get = flow_read_length(data);
|
||||||
bt_assert_msg(get == expect, "Testing get length 0x%03x (get 0x%03x)", expect, get);
|
bt_assert_msg(get == expect, "Testing get length 0x%03x (get 0x%03x)", expect, get);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,12 +51,10 @@ static int
|
||||||
t_write_length(void)
|
t_write_length(void)
|
||||||
{
|
{
|
||||||
byte data[] = { 0xcc, 0xcc, 0xcc };
|
byte data[] = { 0xcc, 0xcc, 0xcc };
|
||||||
uint offset;
|
|
||||||
byte *c;
|
|
||||||
|
|
||||||
for (uint expect = 0; expect <= 0xfff; expect++)
|
for (uint expect = 0; expect <= 0xfff; expect++)
|
||||||
{
|
{
|
||||||
offset = flow_write_length(data, expect);
|
uint offset = flow_write_length(data, expect);
|
||||||
|
|
||||||
uint set = (expect < 0xf0) ? *data : (get_u16(data) & 0x0fff);
|
uint set = (expect < 0xf0) ? *data : (get_u16(data) & 0x0fff);
|
||||||
bt_assert_msg(set == expect, "Testing set length 0x%03x (set 0x%03x)", expect, set);
|
bt_assert_msg(set == expect, "Testing set length 0x%03x (set 0x%03x)", expect, set);
|
||||||
|
|
|
@ -25,6 +25,12 @@
|
||||||
(v).data = mb_allocz(pool, HASH_SIZE(v) * sizeof(* (v).data)); \
|
(v).data = mb_allocz(pool, HASH_SIZE(v) * sizeof(* (v).data)); \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
#define HASH_FREE(v) \
|
||||||
|
({ \
|
||||||
|
mb_free((v).data); \
|
||||||
|
(v) = (typeof(v)){ }; \
|
||||||
|
})
|
||||||
|
|
||||||
#define HASH_FIND(v,id,key...) \
|
#define HASH_FIND(v,id,key...) \
|
||||||
({ \
|
({ \
|
||||||
u32 _h = HASH_FN(v, id, key); \
|
u32 _h = HASH_FN(v, id, key); \
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
Summary: BIRD Internet Routing Daemon
|
Summary: BIRD Internet Routing Daemon
|
||||||
Name: bird
|
Name: bird
|
||||||
Version: 1.6.2
|
Version: 2.0.0
|
||||||
Release: 1
|
Release: 1
|
||||||
Copyright: GPL
|
Copyright: GPL
|
||||||
Group: Networking/Daemons
|
Group: Networking/Daemons
|
||||||
|
|
331
nest/a-path.c
331
nest/a-path.c
|
@ -25,7 +25,7 @@
|
||||||
#define BAD(DSC, VAL) ({ err_dsc = DSC; err_val = VAL; goto bad; })
|
#define BAD(DSC, VAL) ({ err_dsc = DSC; err_val = VAL; goto bad; })
|
||||||
|
|
||||||
int
|
int
|
||||||
as_path_valid(byte *data, uint len, int bs, char *err, uint elen)
|
as_path_valid(byte *data, uint len, int bs, int confed, char *err, uint elen)
|
||||||
{
|
{
|
||||||
byte *pos = data;
|
byte *pos = data;
|
||||||
char *err_dsc = NULL;
|
char *err_dsc = NULL;
|
||||||
|
@ -43,9 +43,21 @@ as_path_valid(byte *data, uint len, int bs, char *err, uint elen)
|
||||||
if (len < slen)
|
if (len < slen)
|
||||||
BAD("segment framing error", len);
|
BAD("segment framing error", len);
|
||||||
|
|
||||||
/* XXXX handle CONFED segments */
|
switch (type)
|
||||||
if ((type != AS_PATH_SET) && (type != AS_PATH_SEQUENCE))
|
{
|
||||||
|
case AS_PATH_SET:
|
||||||
|
case AS_PATH_SEQUENCE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AS_PATH_CONFED_SEQUENCE:
|
||||||
|
case AS_PATH_CONFED_SET:
|
||||||
|
if (!confed)
|
||||||
|
BAD("AS_CONFED* segment", type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
BAD("unknown segment", type);
|
BAD("unknown segment", type);
|
||||||
|
}
|
||||||
|
|
||||||
if (pos[1] == 0)
|
if (pos[1] == 0)
|
||||||
BAD("zero-length segment", type);
|
BAD("zero-length segment", type);
|
||||||
|
@ -157,10 +169,13 @@ as_path_contains_confed(const struct adata *path)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
struct adata *
|
||||||
as_path_strip_confed_(byte *dst, const byte *src, uint len)
|
as_path_strip_confed(struct linpool *pool, const struct adata *path)
|
||||||
{
|
{
|
||||||
const byte *end = src + len;
|
struct adata *res = lp_alloc_adata(pool, path->length);
|
||||||
|
const byte *src = path->data;
|
||||||
|
const byte *end = src + path->length;
|
||||||
|
byte *dst = res->data;
|
||||||
|
|
||||||
while (src < end)
|
while (src < end)
|
||||||
{
|
{
|
||||||
|
@ -176,18 +191,15 @@ as_path_strip_confed_(byte *dst, const byte *src, uint len)
|
||||||
|
|
||||||
src += slen;
|
src += slen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fix the result length */
|
||||||
|
res->length = dst - res->data;
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct adata *
|
struct adata *
|
||||||
as_path_strip_confed(struct linpool *pool, const struct adata *op)
|
as_path_prepend2(struct linpool *pool, const struct adata *op, int seq, u32 as)
|
||||||
{
|
|
||||||
struct adata *np = lp_alloc_adata(pool, op->length);
|
|
||||||
as_path_strip_confed_(np->data, op->data, op->length);
|
|
||||||
return np;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct adata *
|
|
||||||
as_path_prepend2(struct linpool *pool, const struct adata *op, int seq, u32 as, int strip)
|
|
||||||
{
|
{
|
||||||
struct adata *np;
|
struct adata *np;
|
||||||
const byte *pos = op->data;
|
const byte *pos = op->data;
|
||||||
|
@ -218,10 +230,7 @@ as_path_prepend2(struct linpool *pool, const struct adata *op, int seq, u32 as,
|
||||||
{
|
{
|
||||||
byte *dst = np->data + 2 + BS * np->data[1];
|
byte *dst = np->data + 2 + BS * np->data[1];
|
||||||
|
|
||||||
if (strip)
|
memcpy(dst, pos, len);
|
||||||
as_path_strip_confed_(dst, pos, len);
|
|
||||||
else
|
|
||||||
memcpy(dst, pos, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return np;
|
return np;
|
||||||
|
@ -325,46 +334,49 @@ as_path_merge(struct linpool *pool, struct adata *p1, struct adata *p2)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
as_path_format(const struct adata *path, byte *buf, uint size)
|
as_path_format(const struct adata *path, byte *bb, uint size)
|
||||||
{
|
{
|
||||||
const byte *p = path->data;
|
buffer buf = { .start = bb, .pos = bb, .end = bb + size }, *b = &buf;
|
||||||
const byte *e = p + path->length;
|
const byte *pos = path->data;
|
||||||
byte *end = buf + size - 16;
|
const byte *end = pos + path->length;
|
||||||
int sp = 1;
|
const char *ops, *cls;
|
||||||
int l, isset;
|
|
||||||
|
|
||||||
while (p < e)
|
b->pos[0] = 0;
|
||||||
|
|
||||||
|
while (pos < end)
|
||||||
|
{
|
||||||
|
uint type = pos[0];
|
||||||
|
uint len = pos[1];
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
{
|
{
|
||||||
if (buf > end)
|
case AS_PATH_SET: ops = "{"; cls = "}"; break;
|
||||||
{
|
case AS_PATH_SEQUENCE: ops = NULL; cls = NULL; break;
|
||||||
strcpy(buf, " ...");
|
case AS_PATH_CONFED_SEQUENCE: ops = "("; cls = ")"; break;
|
||||||
return;
|
case AS_PATH_CONFED_SET: ops = "({"; cls = "})"; break;
|
||||||
}
|
default: bug("Invalid path segment");
|
||||||
isset = (*p++ == AS_PATH_SET);
|
|
||||||
l = *p++;
|
|
||||||
if (isset)
|
|
||||||
{
|
|
||||||
if (!sp)
|
|
||||||
*buf++ = ' ';
|
|
||||||
*buf++ = '{';
|
|
||||||
sp = 0;
|
|
||||||
}
|
|
||||||
while (l-- && buf <= end)
|
|
||||||
{
|
|
||||||
if (!sp)
|
|
||||||
*buf++ = ' ';
|
|
||||||
buf += bsprintf(buf, "%u", get_as(p));
|
|
||||||
p += BS;
|
|
||||||
sp = 0;
|
|
||||||
}
|
|
||||||
if (isset)
|
|
||||||
{
|
|
||||||
*buf++ = ' ';
|
|
||||||
*buf++ = '}';
|
|
||||||
sp = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
*buf = 0;
|
|
||||||
|
if (ops)
|
||||||
|
buffer_puts(b, ops);
|
||||||
|
|
||||||
|
while (len--)
|
||||||
|
{
|
||||||
|
buffer_print(b, len ? "%u " : "%u", get_as(pos));
|
||||||
|
pos += BS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cls)
|
||||||
|
buffer_puts(b, cls);
|
||||||
|
|
||||||
|
if (pos < end)
|
||||||
|
buffer_puts(b, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle overflow */
|
||||||
|
if (b->pos == b->end)
|
||||||
|
strcpy(b->end - 12, "...");
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -399,66 +411,80 @@ as_path_getlen(const struct adata *path)
|
||||||
int
|
int
|
||||||
as_path_get_last(const struct adata *path, u32 *orig_as)
|
as_path_get_last(const struct adata *path, u32 *orig_as)
|
||||||
{
|
{
|
||||||
|
const byte *pos = path->data;
|
||||||
|
const byte *end = pos + path->length;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
u32 res = 0;
|
u32 val = 0;
|
||||||
const u8 *p = path->data;
|
|
||||||
const u8 *q = p+path->length;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
while (p<q)
|
while (pos < end)
|
||||||
|
{
|
||||||
|
uint type = pos[0];
|
||||||
|
uint len = pos[1];
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
if (!len)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
{
|
{
|
||||||
switch (*p++)
|
case AS_PATH_SET:
|
||||||
{
|
case AS_PATH_CONFED_SET:
|
||||||
case AS_PATH_SET:
|
found = 0;
|
||||||
if (len = *p++)
|
break;
|
||||||
{
|
|
||||||
found = 0;
|
case AS_PATH_SEQUENCE:
|
||||||
p += BS * len;
|
case AS_PATH_CONFED_SEQUENCE:
|
||||||
}
|
val = get_as(pos + BS * (len - 1));
|
||||||
break;
|
found = 1;
|
||||||
case AS_PATH_SEQUENCE:
|
break;
|
||||||
if (len = *p++)
|
|
||||||
{
|
default:
|
||||||
found = 1;
|
bug("Invalid path segment");
|
||||||
res = get_as(p + BS * (len - 1));
|
|
||||||
p += BS * len;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default: bug("Invalid path segment");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pos += BS * len;
|
||||||
|
}
|
||||||
|
|
||||||
if (found)
|
if (found)
|
||||||
*orig_as = res;
|
*orig_as = val;
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32
|
u32
|
||||||
as_path_get_last_nonaggregated(const struct adata *path)
|
as_path_get_last_nonaggregated(const struct adata *path)
|
||||||
{
|
{
|
||||||
const u8 *p = path->data;
|
const byte *pos = path->data;
|
||||||
const u8 *q = p+path->length;
|
const byte *end = pos + path->length;
|
||||||
u32 res = 0;
|
u32 val = 0;
|
||||||
int len;
|
|
||||||
|
|
||||||
while (p<q)
|
while (pos < end)
|
||||||
|
{
|
||||||
|
uint type = pos[0];
|
||||||
|
uint len = pos[1];
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
if (!len)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
{
|
{
|
||||||
switch (*p++)
|
case AS_PATH_SET:
|
||||||
{
|
case AS_PATH_CONFED_SET:
|
||||||
case AS_PATH_SET:
|
return val;
|
||||||
return res;
|
|
||||||
|
|
||||||
case AS_PATH_SEQUENCE:
|
case AS_PATH_SEQUENCE:
|
||||||
if (len = *p++)
|
case AS_PATH_CONFED_SEQUENCE:
|
||||||
res = get_as(p + BS * (len - 1));
|
val = get_as(pos + BS * (len - 1));
|
||||||
p += BS * len;
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
default: bug("Invalid path segment");
|
default:
|
||||||
}
|
bug("Invalid path segment");
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
pos += BS * len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -468,11 +494,47 @@ as_path_get_first(const struct adata *path, u32 *last_as)
|
||||||
|
|
||||||
if ((path->length == 0) || (p[0] != AS_PATH_SEQUENCE) || (p[1] == 0))
|
if ((path->length == 0) || (p[0] != AS_PATH_SEQUENCE) || (p[1] == 0))
|
||||||
return 0;
|
return 0;
|
||||||
else
|
|
||||||
|
*last_as = get_as(p+2);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
as_path_get_first_regular(const struct adata *path, u32 *last_as)
|
||||||
|
{
|
||||||
|
const byte *pos = path->data;
|
||||||
|
const byte *end = pos + path->length;
|
||||||
|
|
||||||
|
while (pos < end)
|
||||||
|
{
|
||||||
|
uint type = pos[0];
|
||||||
|
uint len = pos[1];
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
{
|
{
|
||||||
*last_as = get_as(p+2);
|
case AS_PATH_SET:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case AS_PATH_SEQUENCE:
|
||||||
|
if (len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*last_as = get_as(pos);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
case AS_PATH_CONFED_SEQUENCE:
|
||||||
|
case AS_PATH_CONFED_SET:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
bug("Invalid path segment");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pos += BS * len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -597,43 +659,50 @@ struct pm_pos
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parse_path(const struct adata *path, struct pm_pos *pos)
|
parse_path(const struct adata *path, struct pm_pos *pp)
|
||||||
{
|
{
|
||||||
const u8 *p = path->data;
|
const byte *pos = path->data;
|
||||||
const u8 *q = p + path->length;
|
const byte *end = pos + path->length;
|
||||||
struct pm_pos *opos = pos;
|
struct pm_pos *op = pp;
|
||||||
int i, len;
|
uint i;
|
||||||
|
|
||||||
|
while (pos < end)
|
||||||
|
{
|
||||||
|
uint type = pos[0];
|
||||||
|
uint len = pos[1];
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
while (p < q)
|
switch (type)
|
||||||
switch (*p++)
|
{
|
||||||
|
case AS_PATH_SET:
|
||||||
|
case AS_PATH_CONFED_SET:
|
||||||
|
pp->set = 1;
|
||||||
|
pp->mark = 0;
|
||||||
|
pp->val.sp = pos - 1;
|
||||||
|
pp++;
|
||||||
|
|
||||||
|
pos += BS * len;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AS_PATH_SEQUENCE:
|
||||||
|
case AS_PATH_CONFED_SEQUENCE:
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
case AS_PATH_SET:
|
pp->set = 0;
|
||||||
pos->set = 1;
|
pp->mark = 0;
|
||||||
pos->mark = 0;
|
pp->val.asn = get_as(pos);
|
||||||
pos->val.sp = p;
|
pp++;
|
||||||
len = *p;
|
|
||||||
p += 1 + BS * len;
|
|
||||||
pos++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AS_PATH_SEQUENCE:
|
|
||||||
len = *p++;
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
pos->set = 0;
|
|
||||||
pos->mark = 0;
|
|
||||||
pos->val.asn = get_as(p);
|
|
||||||
p += BS;
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
pos += BS;
|
||||||
bug("as_path_match: Invalid path component");
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
return pos - opos;
|
default:
|
||||||
|
bug("Invalid path segment");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pp - op;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -680,7 +749,7 @@ pm_mark(struct pm_pos *pos, int i, int plen, int *nl, int *nh)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* AS path matching is nontrivial. Because AS path can
|
/* AS path matching is nontrivial. Because AS path can
|
||||||
* contain sets, it is not a plain wildcard matching. A set
|
* contain sets, it is not a plain wildcard matching. A set
|
||||||
* in an AS path is interpreted as it might represent any
|
* in an AS path is interpreted as it might represent any
|
||||||
* sequence of AS numbers from that set (possibly with
|
* sequence of AS numbers from that set (possibly with
|
||||||
* repetitions). So it is also a kind of a pattern,
|
* repetitions). So it is also a kind of a pattern,
|
||||||
|
@ -718,7 +787,7 @@ as_path_match(const struct adata *path, struct f_path_mask *mask)
|
||||||
|
|
||||||
l = h = 0;
|
l = h = 0;
|
||||||
pos[0].mark = 1;
|
pos[0].mark = 1;
|
||||||
|
|
||||||
while (mask)
|
while (mask)
|
||||||
{
|
{
|
||||||
/* We remove this mark to not step after pos[plen] */
|
/* We remove this mark to not step after pos[plen] */
|
||||||
|
|
|
@ -85,15 +85,19 @@ t_path_format(void)
|
||||||
bt_debug("Prepending ASN: %10u \n", i);
|
bt_debug("Prepending ASN: %10u \n", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BUFFER_SIZE 26
|
#define BUFFER_SIZE 120
|
||||||
byte buf[BUFFER_SIZE] = {};
|
byte buf[BUFFER_SIZE] = {};
|
||||||
|
|
||||||
|
as_path_format(&empty_as_path, buf, BUFFER_SIZE);
|
||||||
|
bt_assert_msg(strcmp(buf, "") == 0, "Buffer(%zu): '%s'", strlen(buf), buf);
|
||||||
|
|
||||||
as_path_format(as_path, buf, BUFFER_SIZE);
|
as_path_format(as_path, buf, BUFFER_SIZE);
|
||||||
bt_assert_msg(strcmp(buf, "4294967294 4294967293 ...") == 0, "Buffer(%zu): '%s'", strlen(buf), buf);
|
bt_assert_msg(strcmp(buf, "4294967294 4294967293 4294967292 4294967291 4294967290 4294967289 4294967288 4294967287 4294967286 4294967285") == 0, "Buffer(%zu): '%s'", strlen(buf), buf);
|
||||||
|
|
||||||
#define SMALL_BUFFER_SIZE 25
|
#define SMALL_BUFFER_SIZE 25
|
||||||
byte buf2[SMALL_BUFFER_SIZE] = {};
|
byte buf2[SMALL_BUFFER_SIZE] = {};
|
||||||
as_path_format(as_path, buf2, SMALL_BUFFER_SIZE);
|
as_path_format(as_path, buf2, SMALL_BUFFER_SIZE);
|
||||||
bt_assert_msg(strcmp(buf2, "4294967294 ...") == 0, "Small Buffer(%zu): '%s'", strlen(buf2), buf2);
|
bt_assert_msg(strcmp(buf2, "4294967294 42...") == 0, "Small Buffer(%zu): '%s'", strlen(buf2), buf2);
|
||||||
|
|
||||||
rfree(lp);
|
rfree(lp);
|
||||||
|
|
||||||
|
|
23
nest/a-set.c
23
nest/a-set.c
|
@ -233,6 +233,26 @@ lc_set_contains(struct adata *list, lcomm val)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct adata *
|
||||||
|
int_set_prepend(struct linpool *pool, struct adata *list, u32 val)
|
||||||
|
{
|
||||||
|
struct adata *res;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (int_set_contains(list, val))
|
||||||
|
return list;
|
||||||
|
|
||||||
|
len = list ? list->length : 0;
|
||||||
|
res = lp_alloc(pool, sizeof(struct adata) + len + 4);
|
||||||
|
res->length = len + 4;
|
||||||
|
|
||||||
|
if (list)
|
||||||
|
memcpy(res->data + 4, list->data, list->length);
|
||||||
|
|
||||||
|
* (u32 *) res->data = val;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
struct adata *
|
struct adata *
|
||||||
int_set_add(struct linpool *pool, struct adata *list, u32 val)
|
int_set_add(struct linpool *pool, struct adata *list, u32 val)
|
||||||
|
@ -250,8 +270,7 @@ int_set_add(struct linpool *pool, struct adata *list, u32 val)
|
||||||
if (list)
|
if (list)
|
||||||
memcpy(res->data, list->data, list->length);
|
memcpy(res->data, list->data, list->length);
|
||||||
|
|
||||||
u32 *c = (u32 *) (res->data + len);
|
* (u32 *) (res->data + len) = val;
|
||||||
*c = val;
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,13 +30,13 @@
|
||||||
|
|
||||||
struct f_tree;
|
struct f_tree;
|
||||||
|
|
||||||
int as_path_valid(byte *data, uint len, int bs, char *err, uint elen);
|
int as_path_valid(byte *data, uint len, int bs, int confed, char *err, uint elen);
|
||||||
int as_path_16to32(byte *dst, byte *src, uint len);
|
int as_path_16to32(byte *dst, byte *src, uint len);
|
||||||
int as_path_32to16(byte *dst, byte *src, uint len);
|
int as_path_32to16(byte *dst, byte *src, uint len);
|
||||||
int as_path_contains_as4(const struct adata *path);
|
int as_path_contains_as4(const struct adata *path);
|
||||||
int as_path_contains_confed(const struct adata *path);
|
int as_path_contains_confed(const struct adata *path);
|
||||||
struct adata *as_path_strip_confed(struct linpool *pool, const struct adata *op);
|
struct adata *as_path_strip_confed(struct linpool *pool, const struct adata *op);
|
||||||
struct adata *as_path_prepend2(struct linpool *pool, const struct adata *op, int seq, u32 as, int strip);
|
struct adata *as_path_prepend2(struct linpool *pool, const struct adata *op, int seq, u32 as);
|
||||||
struct adata *as_path_to_old(struct linpool *pool, const struct adata *path);
|
struct adata *as_path_to_old(struct linpool *pool, const struct adata *path);
|
||||||
void as_path_cut(struct adata *path, uint num);
|
void as_path_cut(struct adata *path, uint num);
|
||||||
struct adata *as_path_merge(struct linpool *pool, struct adata *p1, struct adata *p2);
|
struct adata *as_path_merge(struct linpool *pool, struct adata *p1, struct adata *p2);
|
||||||
|
@ -44,6 +44,7 @@ void as_path_format(const struct adata *path, byte *buf, uint size);
|
||||||
int as_path_getlen(const struct adata *path);
|
int as_path_getlen(const struct adata *path);
|
||||||
int as_path_getlen_int(const struct adata *path, int bs);
|
int as_path_getlen_int(const struct adata *path, int bs);
|
||||||
int as_path_get_first(const struct adata *path, u32 *orig_as);
|
int as_path_get_first(const struct adata *path, u32 *orig_as);
|
||||||
|
int as_path_get_first_regular(const struct adata *path, u32 *last_as);
|
||||||
int as_path_get_last(const struct adata *path, u32 *last_as);
|
int as_path_get_last(const struct adata *path, u32 *last_as);
|
||||||
u32 as_path_get_last_nonaggregated(const struct adata *path);
|
u32 as_path_get_last_nonaggregated(const struct adata *path);
|
||||||
int as_path_contains(const struct adata *path, u32 as, int min);
|
int as_path_contains(const struct adata *path, u32 as, int min);
|
||||||
|
@ -51,7 +52,7 @@ int as_path_match_set(const struct adata *path, struct f_tree *set);
|
||||||
struct adata *as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32 key, int pos);
|
struct adata *as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32 key, int pos);
|
||||||
|
|
||||||
static inline struct adata *as_path_prepend(struct linpool *pool, const struct adata *path, u32 as)
|
static inline struct adata *as_path_prepend(struct linpool *pool, const struct adata *path, u32 as)
|
||||||
{ return as_path_prepend2(pool, path, AS_PATH_SEQUENCE, as, 0); }
|
{ return as_path_prepend2(pool, path, AS_PATH_SEQUENCE, as); }
|
||||||
|
|
||||||
|
|
||||||
#define PM_ASN 0
|
#define PM_ASN 0
|
||||||
|
@ -180,6 +181,7 @@ int lc_set_format(struct adata *set, int from, byte *buf, uint size);
|
||||||
int int_set_contains(struct adata *list, u32 val);
|
int int_set_contains(struct adata *list, u32 val);
|
||||||
int ec_set_contains(struct adata *list, u64 val);
|
int ec_set_contains(struct adata *list, u64 val);
|
||||||
int lc_set_contains(struct adata *list, lcomm val);
|
int lc_set_contains(struct adata *list, lcomm val);
|
||||||
|
struct adata *int_set_prepend(struct linpool *pool, struct adata *list, u32 val);
|
||||||
struct adata *int_set_add(struct linpool *pool, struct adata *list, u32 val);
|
struct adata *int_set_add(struct linpool *pool, struct adata *list, u32 val);
|
||||||
struct adata *ec_set_add(struct linpool *pool, struct adata *list, u64 val);
|
struct adata *ec_set_add(struct linpool *pool, struct adata *list, u64 val);
|
||||||
struct adata *lc_set_add(struct linpool *pool, struct adata *list, lcomm val);
|
struct adata *lc_set_add(struct linpool *pool, struct adata *list, lcomm val);
|
||||||
|
|
|
@ -490,7 +490,7 @@ int
|
||||||
channel_reconfigure(struct channel *c, struct channel_config *cf)
|
channel_reconfigure(struct channel *c, struct channel_config *cf)
|
||||||
{
|
{
|
||||||
/* FIXME: better handle these changes, also handle in_keep_filtered */
|
/* FIXME: better handle these changes, also handle in_keep_filtered */
|
||||||
if ((c->table != cf->table->table) || (c->ra_mode != cf->ra_mode))
|
if ((c->table != cf->table->table) || (cf->ra_mode && (c->ra_mode != cf->ra_mode)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
int import_changed = !filter_same(c->in_filter, cf->in_filter);
|
int import_changed = !filter_same(c->in_filter, cf->in_filter);
|
||||||
|
|
|
@ -258,6 +258,7 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED);
|
||||||
|
|
||||||
|
|
||||||
/* Types of route announcement, also used as flags */
|
/* Types of route announcement, also used as flags */
|
||||||
|
#define RA_UNDEF 0 /* Undefined RA type */
|
||||||
#define RA_OPTIMAL 1 /* Announcement of optimal route change */
|
#define RA_OPTIMAL 1 /* Announcement of optimal route change */
|
||||||
#define RA_ACCEPTED 2 /* Announcement of first accepted route */
|
#define RA_ACCEPTED 2 /* Announcement of first accepted route */
|
||||||
#define RA_ANY 3 /* Announcement of any route change */
|
#define RA_ANY 3 /* Announcement of any route change */
|
||||||
|
|
|
@ -2,3 +2,5 @@ src := babel.c packets.c
|
||||||
obj := $(src-o-files)
|
obj := $(src-o-files)
|
||||||
$(all-daemon)
|
$(all-daemon)
|
||||||
$(cf-local)
|
$(cf-local)
|
||||||
|
|
||||||
|
tests_objs := $(tests_objs) $(src-o-files)
|
|
@ -53,8 +53,7 @@ static void babel_dump_route(struct babel_route *r);
|
||||||
static void babel_select_route(struct babel_entry *e);
|
static void babel_select_route(struct babel_entry *e);
|
||||||
static void babel_send_route_request(struct babel_entry *e, struct babel_neighbor *n);
|
static void babel_send_route_request(struct babel_entry *e, struct babel_neighbor *n);
|
||||||
static void babel_send_wildcard_request(struct babel_iface *ifa);
|
static void babel_send_wildcard_request(struct babel_iface *ifa);
|
||||||
static int babel_cache_seqno_request(struct babel_proto *p, ip_addr prefix, u8 plen,
|
static int babel_cache_seqno_request(struct babel_proto *p, net_addr *n, u64 router_id, u16 seqno);
|
||||||
u64 router_id, u16 seqno);
|
|
||||||
static void babel_trigger_iface_update(struct babel_iface *ifa);
|
static void babel_trigger_iface_update(struct babel_iface *ifa);
|
||||||
static void babel_trigger_update(struct babel_proto *p);
|
static void babel_trigger_update(struct babel_proto *p);
|
||||||
static void babel_send_seqno_request(struct babel_entry *e);
|
static void babel_send_seqno_request(struct babel_entry *e);
|
||||||
|
@ -67,27 +66,25 @@ static inline void babel_iface_kick_timer(struct babel_iface *ifa);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
babel_init_entry(struct fib_node *n)
|
babel_init_entry(void *E)
|
||||||
{
|
{
|
||||||
struct babel_entry *e = (void *) n;
|
struct babel_entry *e = E;
|
||||||
e->proto = NULL;
|
|
||||||
e->selected_in = NULL;
|
|
||||||
e->selected_out = NULL;
|
|
||||||
e->updated = now;
|
e->updated = now;
|
||||||
init_list(&e->sources);
|
init_list(&e->sources);
|
||||||
init_list(&e->routes);
|
init_list(&e->routes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct babel_entry *
|
static inline struct babel_entry *
|
||||||
babel_find_entry(struct babel_proto *p, ip_addr prefix, u8 plen)
|
babel_find_entry(struct babel_proto *p, const net_addr *n)
|
||||||
{
|
{
|
||||||
return fib_find(&p->rtable, &prefix, plen);
|
return fib_find(&p->rtable, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct babel_entry *
|
static struct babel_entry *
|
||||||
babel_get_entry(struct babel_proto *p, ip_addr prefix, u8 plen)
|
babel_get_entry(struct babel_proto *p, const net_addr *n)
|
||||||
{
|
{
|
||||||
struct babel_entry *e = fib_get(&p->rtable, &prefix, plen);
|
struct babel_entry *e = fib_get(&p->rtable, n);
|
||||||
e->proto = p;
|
e->proto = p;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
@ -180,8 +177,8 @@ babel_flush_route(struct babel_route *r)
|
||||||
{
|
{
|
||||||
struct babel_proto *p = r->e->proto;
|
struct babel_proto *p = r->e->proto;
|
||||||
|
|
||||||
DBG("Babel: Flush route %I/%d router_id %lR neigh %I\n",
|
DBG("Babel: Flush route %N router_id %lR neigh %I\n",
|
||||||
r->e->n.prefix, r->e->n.pxlen, r->router_id, r->neigh ? r->neigh->addr : IPA_NONE);
|
r->e->n.addr, r->router_id, r->neigh ? r->neigh->addr : IPA_NONE);
|
||||||
|
|
||||||
rem_node(NODE r);
|
rem_node(NODE r);
|
||||||
|
|
||||||
|
@ -203,8 +200,8 @@ babel_expire_route(struct babel_route *r)
|
||||||
struct babel_proto *p = r->e->proto;
|
struct babel_proto *p = r->e->proto;
|
||||||
struct babel_entry *e = r->e;
|
struct babel_entry *e = r->e;
|
||||||
|
|
||||||
TRACE(D_EVENTS, "Route expiry timer for %I/%d router-id %lR fired",
|
TRACE(D_EVENTS, "Route expiry timer for %N router-id %lR fired",
|
||||||
e->n.prefix, e->n.pxlen, r->router_id);
|
e->n.addr, r->router_id);
|
||||||
|
|
||||||
if (r->metric < BABEL_INFINITY)
|
if (r->metric < BABEL_INFINITY)
|
||||||
{
|
{
|
||||||
|
@ -229,16 +226,14 @@ babel_refresh_route(struct babel_route *r)
|
||||||
static void
|
static void
|
||||||
babel_expire_routes(struct babel_proto *p)
|
babel_expire_routes(struct babel_proto *p)
|
||||||
{
|
{
|
||||||
struct babel_entry *e;
|
|
||||||
struct babel_route *r, *rx;
|
struct babel_route *r, *rx;
|
||||||
struct fib_iterator fit;
|
struct fib_iterator fit;
|
||||||
|
|
||||||
FIB_ITERATE_INIT(&fit, &p->rtable);
|
FIB_ITERATE_INIT(&fit, &p->rtable);
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
FIB_ITERATE_START(&p->rtable, &fit, n)
|
FIB_ITERATE_START(&p->rtable, &fit, struct babel_entry, e)
|
||||||
{
|
{
|
||||||
e = (struct babel_entry *) n;
|
|
||||||
int changed = 0;
|
int changed = 0;
|
||||||
|
|
||||||
WALK_LIST_DELSAFE(r, rx, e->routes)
|
WALK_LIST_DELSAFE(r, rx, e->routes)
|
||||||
|
@ -261,7 +256,7 @@ loop:
|
||||||
* babel_rt_notify() -> p->rtable change, invalidating hidden variables.
|
* babel_rt_notify() -> p->rtable change, invalidating hidden variables.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FIB_ITERATE_PUT(&fit, n);
|
FIB_ITERATE_PUT(&fit);
|
||||||
babel_select_route(e);
|
babel_select_route(e);
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
@ -271,12 +266,12 @@ loop:
|
||||||
/* Remove empty entries */
|
/* Remove empty entries */
|
||||||
if (EMPTY_LIST(e->sources) && EMPTY_LIST(e->routes))
|
if (EMPTY_LIST(e->sources) && EMPTY_LIST(e->routes))
|
||||||
{
|
{
|
||||||
FIB_ITERATE_PUT(&fit, n);
|
FIB_ITERATE_PUT(&fit);
|
||||||
fib_delete(&p->rtable, e);
|
fib_delete(&p->rtable, e);
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FIB_ITERATE_END(n);
|
FIB_ITERATE_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct babel_neighbor *
|
static struct babel_neighbor *
|
||||||
|
@ -476,8 +471,7 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
|
||||||
|
|
||||||
if (r)
|
if (r)
|
||||||
{
|
{
|
||||||
net *n = net_get(p->p.table, e->n.prefix, e->n.pxlen);
|
rta a0 = {
|
||||||
rta A = {
|
|
||||||
.src = p->p.main_source,
|
.src = p->p.main_source,
|
||||||
.source = RTS_BABEL,
|
.source = RTS_BABEL,
|
||||||
.scope = SCOPE_UNIVERSE,
|
.scope = SCOPE_UNIVERSE,
|
||||||
|
@ -489,22 +483,20 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (r->metric < BABEL_INFINITY)
|
if (r->metric < BABEL_INFINITY)
|
||||||
A.gw = r->next_hop;
|
a0.gw = r->next_hop;
|
||||||
|
|
||||||
rta *a = rta_lookup(&A);
|
rta *a = rta_lookup(&a0);
|
||||||
rte *rte = rte_get_temp(a);
|
rte *rte = rte_get_temp(a);
|
||||||
rte->u.babel.metric = r->metric;
|
rte->u.babel.metric = r->metric;
|
||||||
rte->u.babel.router_id = r->router_id;
|
rte->u.babel.router_id = r->router_id;
|
||||||
rte->net = n;
|
|
||||||
rte->pflags = 0;
|
rte->pflags = 0;
|
||||||
|
|
||||||
rte_update(&p->p, n, rte);
|
rte_update(&p->p, e->n.addr, rte);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Retraction */
|
/* Retraction */
|
||||||
net *n = net_find(p->p.table, e->n.prefix, e->n.pxlen);
|
rte_update(&p->p, e->n.addr, NULL);
|
||||||
rte_update(&p->p, n, NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,8 +533,8 @@ babel_select_route(struct babel_entry *e)
|
||||||
((!e->selected_in && cur->metric < BABEL_INFINITY) ||
|
((!e->selected_in && cur->metric < BABEL_INFINITY) ||
|
||||||
(e->selected_in && cur->metric < e->selected_in->metric)))
|
(e->selected_in && cur->metric < e->selected_in->metric)))
|
||||||
{
|
{
|
||||||
TRACE(D_EVENTS, "Picked new route for prefix %I/%d: router id %lR metric %d",
|
TRACE(D_EVENTS, "Picked new route for prefix %N: router id %lR metric %d",
|
||||||
e->n.prefix, e->n.pxlen, cur->router_id, cur->metric);
|
e->n.addr, cur->router_id, cur->metric);
|
||||||
|
|
||||||
e->selected_in = cur;
|
e->selected_in = cur;
|
||||||
e->updated = now;
|
e->updated = now;
|
||||||
|
@ -557,8 +549,8 @@ babel_select_route(struct babel_entry *e)
|
||||||
babel_build_rte() will set the unreachable flag if the metric is BABEL_INFINITY.*/
|
babel_build_rte() will set the unreachable flag if the metric is BABEL_INFINITY.*/
|
||||||
if (e->selected_in)
|
if (e->selected_in)
|
||||||
{
|
{
|
||||||
TRACE(D_EVENTS, "Lost feasible route for prefix %I/%d",
|
TRACE(D_EVENTS, "Lost feasible route for prefix %N",
|
||||||
e->n.prefix, e->n.pxlen);
|
e->n.addr);
|
||||||
|
|
||||||
e->selected_in->metric = BABEL_INFINITY;
|
e->selected_in->metric = BABEL_INFINITY;
|
||||||
e->updated = now;
|
e->updated = now;
|
||||||
|
@ -576,7 +568,7 @@ babel_select_route(struct babel_entry *e)
|
||||||
/* No route currently selected, and no new one selected; this means we
|
/* No route currently selected, and no new one selected; this means we
|
||||||
don't have a route to this destination anymore (and were probably
|
don't have a route to this destination anymore (and were probably
|
||||||
called from an expiry timer). Remove the route from the nest. */
|
called from an expiry timer). Remove the route from the nest. */
|
||||||
TRACE(D_EVENTS, "Flushing route for prefix %I/%d", e->n.prefix, e->n.pxlen);
|
TRACE(D_EVENTS, "Flushing route for prefix %N", e->n.addr);
|
||||||
|
|
||||||
e->selected_in = NULL;
|
e->selected_in = NULL;
|
||||||
e->updated = now;
|
e->updated = now;
|
||||||
|
@ -663,12 +655,11 @@ babel_send_route_request(struct babel_entry *e, struct babel_neighbor *n)
|
||||||
struct babel_iface *ifa = n->ifa;
|
struct babel_iface *ifa = n->ifa;
|
||||||
union babel_msg msg = {};
|
union babel_msg msg = {};
|
||||||
|
|
||||||
TRACE(D_PACKETS, "Sending route request for %I/%d to %I",
|
TRACE(D_PACKETS, "Sending route request for %N to %I",
|
||||||
e->n.prefix, e->n.pxlen, n->addr);
|
e->n.addr, n->addr);
|
||||||
|
|
||||||
msg.type = BABEL_TLV_ROUTE_REQUEST;
|
msg.type = BABEL_TLV_ROUTE_REQUEST;
|
||||||
msg.route_request.prefix = e->n.prefix;
|
net_copy(&msg.route_request.net, e->n.addr);
|
||||||
msg.route_request.plen = e->n.pxlen;
|
|
||||||
|
|
||||||
babel_send_unicast(&msg, ifa, n->addr);
|
babel_send_unicast(&msg, ifa, n->addr);
|
||||||
}
|
}
|
||||||
|
@ -698,18 +689,17 @@ babel_send_seqno_request(struct babel_entry *e)
|
||||||
union babel_msg msg = {};
|
union babel_msg msg = {};
|
||||||
|
|
||||||
s = babel_find_source(e, r->router_id);
|
s = babel_find_source(e, r->router_id);
|
||||||
if (!s || !babel_cache_seqno_request(p, e->n.prefix, e->n.pxlen, r->router_id, s->seqno + 1))
|
if (!s || !babel_cache_seqno_request(p, e->n.addr, r->router_id, s->seqno + 1))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TRACE(D_PACKETS, "Sending seqno request for %I/%d router-id %lR seqno %d",
|
TRACE(D_PACKETS, "Sending seqno request for %N router-id %lR seqno %d",
|
||||||
e->n.prefix, e->n.pxlen, r->router_id, s->seqno + 1);
|
e->n.addr, r->router_id, s->seqno + 1);
|
||||||
|
|
||||||
msg.type = BABEL_TLV_SEQNO_REQUEST;
|
msg.type = BABEL_TLV_SEQNO_REQUEST;
|
||||||
msg.seqno_request.plen = e->n.pxlen;
|
|
||||||
msg.seqno_request.seqno = s->seqno + 1;
|
|
||||||
msg.seqno_request.hop_count = BABEL_INITIAL_HOP_COUNT;
|
msg.seqno_request.hop_count = BABEL_INITIAL_HOP_COUNT;
|
||||||
|
msg.seqno_request.seqno = s->seqno + 1;
|
||||||
msg.seqno_request.router_id = r->router_id;
|
msg.seqno_request.router_id = r->router_id;
|
||||||
msg.seqno_request.prefix = e->n.prefix;
|
net_copy(&msg.seqno_request.net, e->n.addr);
|
||||||
|
|
||||||
WALK_LIST(ifa, p->interfaces)
|
WALK_LIST(ifa, p->interfaces)
|
||||||
babel_enqueue(&msg, ifa);
|
babel_enqueue(&msg, ifa);
|
||||||
|
@ -725,18 +715,17 @@ babel_unicast_seqno_request(struct babel_route *r)
|
||||||
union babel_msg msg = {};
|
union babel_msg msg = {};
|
||||||
|
|
||||||
s = babel_find_source(e, r->router_id);
|
s = babel_find_source(e, r->router_id);
|
||||||
if (!s || !babel_cache_seqno_request(p, e->n.prefix, e->n.pxlen, r->router_id, s->seqno + 1))
|
if (!s || !babel_cache_seqno_request(p, e->n.addr, r->router_id, s->seqno + 1))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TRACE(D_PACKETS, "Sending seqno request for %I/%d router-id %lR seqno %d",
|
TRACE(D_PACKETS, "Sending seqno request for %N router-id %lR seqno %d",
|
||||||
e->n.prefix, e->n.pxlen, r->router_id, s->seqno + 1);
|
e->n.addr, r->router_id, s->seqno + 1);
|
||||||
|
|
||||||
msg.type = BABEL_TLV_SEQNO_REQUEST;
|
msg.type = BABEL_TLV_SEQNO_REQUEST;
|
||||||
msg.seqno_request.plen = e->n.pxlen;
|
|
||||||
msg.seqno_request.seqno = s->seqno + 1;
|
|
||||||
msg.seqno_request.hop_count = BABEL_INITIAL_HOP_COUNT;
|
msg.seqno_request.hop_count = BABEL_INITIAL_HOP_COUNT;
|
||||||
|
msg.seqno_request.seqno = s->seqno + 1;
|
||||||
msg.seqno_request.router_id = r->router_id;
|
msg.seqno_request.router_id = r->router_id;
|
||||||
msg.seqno_request.prefix = e->n.prefix;
|
net_copy(&msg.seqno_request.net, e->n.addr);
|
||||||
|
|
||||||
babel_send_unicast(&msg, ifa, r->neigh->addr);
|
babel_send_unicast(&msg, ifa, r->neigh->addr);
|
||||||
}
|
}
|
||||||
|
@ -756,9 +745,8 @@ babel_send_update(struct babel_iface *ifa, bird_clock_t changed)
|
||||||
{
|
{
|
||||||
struct babel_proto *p = ifa->proto;
|
struct babel_proto *p = ifa->proto;
|
||||||
|
|
||||||
FIB_WALK(&p->rtable, n)
|
FIB_WALK(&p->rtable, struct babel_entry, e)
|
||||||
{
|
{
|
||||||
struct babel_entry *e = (void *) n;
|
|
||||||
struct babel_route *r = e->selected_out;
|
struct babel_route *r = e->selected_out;
|
||||||
|
|
||||||
if (!r)
|
if (!r)
|
||||||
|
@ -776,17 +764,16 @@ babel_send_update(struct babel_iface *ifa, bird_clock_t changed)
|
||||||
if (e->updated < changed)
|
if (e->updated < changed)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
TRACE(D_PACKETS, "Sending update for %I/%d router-id %lR seqno %d metric %d",
|
TRACE(D_PACKETS, "Sending update for %N router-id %lR seqno %d metric %d",
|
||||||
e->n.prefix, e->n.pxlen, r->router_id, r->seqno, r->metric);
|
e->n.addr, r->router_id, r->seqno, r->metric);
|
||||||
|
|
||||||
union babel_msg msg = {};
|
union babel_msg msg = {};
|
||||||
msg.type = BABEL_TLV_UPDATE;
|
msg.type = BABEL_TLV_UPDATE;
|
||||||
msg.update.plen = e->n.pxlen;
|
|
||||||
msg.update.interval = ifa->cf->update_interval;
|
msg.update.interval = ifa->cf->update_interval;
|
||||||
msg.update.seqno = r->seqno;
|
msg.update.seqno = r->seqno;
|
||||||
msg.update.metric = r->metric;
|
msg.update.metric = r->metric;
|
||||||
msg.update.prefix = e->n.prefix;
|
|
||||||
msg.update.router_id = r->router_id;
|
msg.update.router_id = r->router_id;
|
||||||
|
net_copy(&msg.update.net, e->n.addr);
|
||||||
|
|
||||||
babel_enqueue(&msg, ifa);
|
babel_enqueue(&msg, ifa);
|
||||||
|
|
||||||
|
@ -839,20 +826,18 @@ babel_trigger_update(struct babel_proto *p)
|
||||||
|
|
||||||
/* A retraction is an update with an infinite metric */
|
/* A retraction is an update with an infinite metric */
|
||||||
static void
|
static void
|
||||||
babel_send_retraction(struct babel_iface *ifa, ip_addr prefix, int plen)
|
babel_send_retraction(struct babel_iface *ifa, net_addr *n)
|
||||||
{
|
{
|
||||||
struct babel_proto *p = ifa->proto;
|
struct babel_proto *p = ifa->proto;
|
||||||
union babel_msg msg = {};
|
union babel_msg msg = {};
|
||||||
|
|
||||||
TRACE(D_PACKETS, "Sending retraction for %I/%d seqno %d",
|
TRACE(D_PACKETS, "Sending retraction for %N seqno %d", n, p->update_seqno);
|
||||||
prefix, plen, p->update_seqno);
|
|
||||||
|
|
||||||
msg.type = BABEL_TLV_UPDATE;
|
msg.type = BABEL_TLV_UPDATE;
|
||||||
msg.update.plen = plen;
|
|
||||||
msg.update.interval = ifa->cf->update_interval;
|
msg.update.interval = ifa->cf->update_interval;
|
||||||
msg.update.seqno = p->update_seqno;
|
msg.update.seqno = p->update_seqno;
|
||||||
msg.update.metric = BABEL_INFINITY;
|
msg.update.metric = BABEL_INFINITY;
|
||||||
msg.update.prefix = prefix;
|
msg.update.net = *n;
|
||||||
|
|
||||||
babel_enqueue(&msg, ifa);
|
babel_enqueue(&msg, ifa);
|
||||||
}
|
}
|
||||||
|
@ -941,22 +926,20 @@ babel_expire_seqno_requests(struct babel_proto *p)
|
||||||
* found. Otherwise, a new entry is stored in the cache.
|
* found. Otherwise, a new entry is stored in the cache.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
babel_cache_seqno_request(struct babel_proto *p, ip_addr prefix, u8 plen,
|
babel_cache_seqno_request(struct babel_proto *p, net_addr *n,
|
||||||
u64 router_id, u16 seqno)
|
u64 router_id, u16 seqno)
|
||||||
{
|
{
|
||||||
struct babel_seqno_request *r;
|
struct babel_seqno_request *r;
|
||||||
|
|
||||||
WALK_LIST(r, p->seqno_cache)
|
WALK_LIST(r, p->seqno_cache)
|
||||||
{
|
{
|
||||||
if (ipa_equal(r->prefix, prefix) && (r->plen == plen) &&
|
if (net_equal(&r->net, n) && (r->router_id == router_id) && (r->seqno == seqno))
|
||||||
(r->router_id == router_id) && (r->seqno == seqno))
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no entries found */
|
/* no entries found */
|
||||||
r = sl_alloc(p->seqno_slab);
|
r = sl_alloc(p->seqno_slab);
|
||||||
r->prefix = prefix;
|
net_copy(&r->net, n);
|
||||||
r->plen = plen;
|
|
||||||
r->router_id = router_id;
|
r->router_id = router_id;
|
||||||
r->seqno = seqno;
|
r->seqno = seqno;
|
||||||
r->updated = now;
|
r->updated = now;
|
||||||
|
@ -973,8 +956,8 @@ babel_forward_seqno_request(struct babel_entry *e,
|
||||||
struct babel_proto *p = e->proto;
|
struct babel_proto *p = e->proto;
|
||||||
struct babel_route *r;
|
struct babel_route *r;
|
||||||
|
|
||||||
TRACE(D_PACKETS, "Forwarding seqno request for %I/%d router-id %lR seqno %d",
|
TRACE(D_PACKETS, "Forwarding seqno request for %N router-id %lR seqno %d",
|
||||||
e->n.prefix, e->n.pxlen, in->router_id, in->seqno);
|
e->n.addr, in->router_id, in->seqno);
|
||||||
|
|
||||||
WALK_LIST(r, e->routes)
|
WALK_LIST(r, e->routes)
|
||||||
{
|
{
|
||||||
|
@ -982,16 +965,15 @@ babel_forward_seqno_request(struct babel_entry *e,
|
||||||
!OUR_ROUTE(r) &&
|
!OUR_ROUTE(r) &&
|
||||||
!ipa_equal(r->neigh->addr, sender))
|
!ipa_equal(r->neigh->addr, sender))
|
||||||
{
|
{
|
||||||
if (!babel_cache_seqno_request(p, e->n.prefix, e->n.pxlen, in->router_id, in->seqno))
|
if (!babel_cache_seqno_request(p, e->n.addr, in->router_id, in->seqno))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
union babel_msg msg = {};
|
union babel_msg msg = {};
|
||||||
msg.type = BABEL_TLV_SEQNO_REQUEST;
|
msg.type = BABEL_TLV_SEQNO_REQUEST;
|
||||||
msg.seqno_request.plen = in->plen;
|
|
||||||
msg.seqno_request.seqno = in->seqno;
|
|
||||||
msg.seqno_request.hop_count = in->hop_count-1;
|
msg.seqno_request.hop_count = in->hop_count-1;
|
||||||
|
msg.seqno_request.seqno = in->seqno;
|
||||||
msg.seqno_request.router_id = in->router_id;
|
msg.seqno_request.router_id = in->router_id;
|
||||||
msg.seqno_request.prefix = e->n.prefix;
|
net_copy(&msg.seqno_request.net, e->n.addr);
|
||||||
|
|
||||||
babel_send_unicast(&msg, r->neigh->ifa, r->neigh->addr);
|
babel_send_unicast(&msg, r->neigh->ifa, r->neigh->addr);
|
||||||
return;
|
return;
|
||||||
|
@ -1073,8 +1055,11 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
|
||||||
node *n;
|
node *n;
|
||||||
int feasible;
|
int feasible;
|
||||||
|
|
||||||
TRACE(D_PACKETS, "Handling update for %I/%d with seqno %d metric %d",
|
if (msg->wildcard)
|
||||||
msg->prefix, msg->plen, msg->seqno, msg->metric);
|
TRACE(D_PACKETS, "Handling wildcard retraction", msg->seqno);
|
||||||
|
else
|
||||||
|
TRACE(D_PACKETS, "Handling update for %N with seqno %d metric %d",
|
||||||
|
&msg->net, msg->seqno, msg->metric);
|
||||||
|
|
||||||
nbr = babel_find_neighbor(ifa, msg->sender);
|
nbr = babel_find_neighbor(ifa, msg->sender);
|
||||||
if (!nbr)
|
if (!nbr)
|
||||||
|
@ -1140,7 +1125,7 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
e = babel_find_entry(p, msg->prefix, msg->plen);
|
e = babel_find_entry(p, &msg->net);
|
||||||
|
|
||||||
if (!e)
|
if (!e)
|
||||||
return;
|
return;
|
||||||
|
@ -1159,7 +1144,7 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e = babel_get_entry(p, msg->prefix, msg->plen);
|
e = babel_get_entry(p, &msg->net);
|
||||||
r = babel_find_route(e, nbr); /* the route entry indexed by neighbour */
|
r = babel_find_route(e, nbr); /* the route entry indexed by neighbour */
|
||||||
s = babel_find_source(e, msg->router_id); /* for feasibility */
|
s = babel_find_source(e, msg->router_id); /* for feasibility */
|
||||||
feasible = babel_is_feasible(s, msg->seqno, msg->metric);
|
feasible = babel_is_feasible(s, msg->seqno, msg->metric);
|
||||||
|
@ -1231,14 +1216,14 @@ babel_handle_route_request(union babel_msg *m, struct babel_iface *ifa)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE(D_PACKETS, "Handling route request for %I/%d", msg->prefix, msg->plen);
|
TRACE(D_PACKETS, "Handling route request for %N", &msg->net);
|
||||||
|
|
||||||
/* Non-wildcard request - see if we have an entry for the route.
|
/* Non-wildcard request - see if we have an entry for the route.
|
||||||
If not, send a retraction, otherwise send an update. */
|
If not, send a retraction, otherwise send an update. */
|
||||||
struct babel_entry *e = babel_find_entry(p, msg->prefix, msg->plen);
|
struct babel_entry *e = babel_find_entry(p, &msg->net);
|
||||||
if (!e)
|
if (!e)
|
||||||
{
|
{
|
||||||
babel_send_retraction(ifa, msg->prefix, msg->plen);
|
babel_send_retraction(ifa, &msg->net);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1256,11 +1241,11 @@ babel_handle_seqno_request(union babel_msg *m, struct babel_iface *ifa)
|
||||||
|
|
||||||
/* RFC 6126 3.8.1.2 */
|
/* RFC 6126 3.8.1.2 */
|
||||||
|
|
||||||
TRACE(D_PACKETS, "Handling seqno request for %I/%d router-id %lR seqno %d hop count %d",
|
TRACE(D_PACKETS, "Handling seqno request for %N router-id %lR seqno %d hop count %d",
|
||||||
msg->prefix, msg->plen, msg->router_id, msg->seqno, msg->hop_count);
|
&msg->net, msg->router_id, msg->seqno, msg->hop_count);
|
||||||
|
|
||||||
/* Ignore if we have no such entry or entry has infinite metric */
|
/* Ignore if we have no such entry or entry has infinite metric */
|
||||||
struct babel_entry *e = babel_find_entry(p, msg->prefix, msg->plen);
|
struct babel_entry *e = babel_find_entry(p, &msg->net);
|
||||||
if (!e || !e->selected_out || (e->selected_out->metric == BABEL_INFINITY))
|
if (!e || !e->selected_out || (e->selected_out->metric == BABEL_INFINITY))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1668,7 +1653,7 @@ babel_dump_entry(struct babel_entry *e)
|
||||||
struct babel_source *s;
|
struct babel_source *s;
|
||||||
struct babel_route *r;
|
struct babel_route *r;
|
||||||
|
|
||||||
debug("Babel: Entry %I/%d:\n", e->n.prefix, e->n.pxlen);
|
debug("Babel: Entry %N:\n", e->n.addr);
|
||||||
|
|
||||||
WALK_LIST(s,e->sources)
|
WALK_LIST(s,e->sources)
|
||||||
{ debug(" "); babel_dump_source(s); }
|
{ debug(" "); babel_dump_source(s); }
|
||||||
|
@ -1715,9 +1700,9 @@ babel_dump(struct proto *P)
|
||||||
WALK_LIST(ifa, p->interfaces)
|
WALK_LIST(ifa, p->interfaces)
|
||||||
babel_dump_iface(ifa);
|
babel_dump_iface(ifa);
|
||||||
|
|
||||||
FIB_WALK(&p->rtable, n)
|
FIB_WALK(&p->rtable, struct babel_entry, e)
|
||||||
{
|
{
|
||||||
babel_dump_entry((struct babel_entry *) n);
|
babel_dump_entry(e);
|
||||||
}
|
}
|
||||||
FIB_WALK_END;
|
FIB_WALK_END;
|
||||||
}
|
}
|
||||||
|
@ -1828,11 +1813,9 @@ void
|
||||||
babel_show_entries(struct proto *P)
|
babel_show_entries(struct proto *P)
|
||||||
{
|
{
|
||||||
struct babel_proto *p = (void *) P;
|
struct babel_proto *p = (void *) P;
|
||||||
struct babel_entry *e = NULL;
|
|
||||||
struct babel_source *s = NULL;
|
struct babel_source *s = NULL;
|
||||||
struct babel_route *r = NULL;
|
struct babel_route *r = NULL;
|
||||||
|
|
||||||
char ipbuf[STD_ADDRESS_P_LENGTH+5];
|
|
||||||
char ridbuf[ROUTER_ID_64_LENGTH+1];
|
char ridbuf[ROUTER_ID_64_LENGTH+1];
|
||||||
|
|
||||||
if (p->p.proto_state != PS_UP)
|
if (p->p.proto_state != PS_UP)
|
||||||
|
@ -1846,17 +1829,14 @@ babel_show_entries(struct proto *P)
|
||||||
cli_msg(-1025, "%-29s %-23s %6s %5s %7s %7s",
|
cli_msg(-1025, "%-29s %-23s %6s %5s %7s %7s",
|
||||||
"Prefix", "Router ID", "Metric", "Seqno", "Expires", "Sources");
|
"Prefix", "Router ID", "Metric", "Seqno", "Expires", "Sources");
|
||||||
|
|
||||||
FIB_WALK(&p->rtable, n)
|
FIB_WALK(&p->rtable, struct babel_entry, e)
|
||||||
{
|
{
|
||||||
e = (struct babel_entry *) n;
|
|
||||||
r = e->selected_in ? e->selected_in : e->selected_out;
|
r = e->selected_in ? e->selected_in : e->selected_out;
|
||||||
|
|
||||||
int srcs = 0;
|
int srcs = 0;
|
||||||
WALK_LIST(s, e->sources)
|
WALK_LIST(s, e->sources)
|
||||||
srcs++;
|
srcs++;
|
||||||
|
|
||||||
bsprintf(ipbuf, "%I/%u", e->n.prefix, e->n.pxlen);
|
|
||||||
|
|
||||||
if (r)
|
if (r)
|
||||||
{
|
{
|
||||||
if (r->router_id == p->router_id)
|
if (r->router_id == p->router_id)
|
||||||
|
@ -1865,12 +1845,12 @@ babel_show_entries(struct proto *P)
|
||||||
bsprintf(ridbuf, "%lR", r->router_id);
|
bsprintf(ridbuf, "%lR", r->router_id);
|
||||||
|
|
||||||
int time = r->expires ? r->expires - now : 0;
|
int time = r->expires ? r->expires - now : 0;
|
||||||
cli_msg(-1025, "%-29s %-23s %6u %5u %7u %7u",
|
cli_msg(-1025, "%-29N %-23s %6u %5u %7u %7u",
|
||||||
ipbuf, ridbuf, r->metric, r->seqno, MAX(time, 0), srcs);
|
e->n.addr, ridbuf, r->metric, r->seqno, MAX(time, 0), srcs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cli_msg(-1025, "%-29s %-44s %7u", ipbuf, "<pending>", srcs);
|
cli_msg(-1025, "%-29N %-44s %7u", e->n.addr, "<pending>", srcs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FIB_WALK_END;
|
FIB_WALK_END;
|
||||||
|
@ -1964,7 +1944,7 @@ babel_store_tmp_attrs(struct rte *rt, struct ea_list *attrs)
|
||||||
* so store it into our data structures.
|
* so store it into our data structures.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
babel_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *net,
|
babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net,
|
||||||
struct rte *new, struct rte *old UNUSED, struct ea_list *attrs UNUSED)
|
struct rte *new, struct rte *old UNUSED, struct ea_list *attrs UNUSED)
|
||||||
{
|
{
|
||||||
struct babel_proto *p = (void *) P;
|
struct babel_proto *p = (void *) P;
|
||||||
|
@ -1974,7 +1954,7 @@ babel_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *ne
|
||||||
if (new)
|
if (new)
|
||||||
{
|
{
|
||||||
/* Update */
|
/* Update */
|
||||||
e = babel_get_entry(p, net->n.prefix, net->n.pxlen);
|
e = babel_get_entry(p, net->n.addr);
|
||||||
|
|
||||||
if (new->attrs->src->proto != P)
|
if (new->attrs->src->proto != P)
|
||||||
{
|
{
|
||||||
|
@ -1996,7 +1976,7 @@ babel_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *ne
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Withdraw */
|
/* Withdraw */
|
||||||
e = babel_find_entry(p, net->n.prefix, net->n.pxlen);
|
e = babel_find_entry(p, net->n.addr);
|
||||||
if (!e || !e->selected_out)
|
if (!e || !e->selected_out)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -2046,11 +2026,12 @@ babel_rte_same(struct rte *new, struct rte *old)
|
||||||
|
|
||||||
|
|
||||||
static struct proto *
|
static struct proto *
|
||||||
babel_init(struct proto_config *cfg)
|
babel_init(struct proto_config *CF)
|
||||||
{
|
{
|
||||||
struct proto *P = proto_new(cfg, sizeof(struct babel_proto));
|
struct proto *P = proto_new(CF);
|
||||||
|
|
||||||
|
P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
|
||||||
|
|
||||||
P->accept_ra_types = RA_OPTIMAL;
|
|
||||||
P->if_notify = babel_if_notify;
|
P->if_notify = babel_if_notify;
|
||||||
P->rt_notify = babel_rt_notify;
|
P->rt_notify = babel_rt_notify;
|
||||||
P->import_control = babel_import_control;
|
P->import_control = babel_import_control;
|
||||||
|
@ -2068,7 +2049,8 @@ babel_start(struct proto *P)
|
||||||
struct babel_proto *p = (void *) P;
|
struct babel_proto *p = (void *) P;
|
||||||
struct babel_config *cf = (void *) P->cf;
|
struct babel_config *cf = (void *) P->cf;
|
||||||
|
|
||||||
fib_init(&p->rtable, P->pool, sizeof(struct babel_entry), 0, babel_init_entry);
|
fib_init(&p->rtable, P->pool, NET_IP6, sizeof(struct babel_entry),
|
||||||
|
OFFSETOF(struct babel_entry, n), 0, babel_init_entry);
|
||||||
init_list(&p->interfaces);
|
init_list(&p->interfaces);
|
||||||
p->timer = tm_new_set(P->pool, babel_timer, p, 0, 1);
|
p->timer = tm_new_set(P->pool, babel_timer, p, 0, 1);
|
||||||
tm_start(p->timer, 2);
|
tm_start(p->timer, 2);
|
||||||
|
@ -2111,14 +2093,17 @@ babel_shutdown(struct proto *P)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
babel_reconfigure(struct proto *P, struct proto_config *c)
|
babel_reconfigure(struct proto *P, struct proto_config *CF)
|
||||||
{
|
{
|
||||||
struct babel_proto *p = (void *) P;
|
struct babel_proto *p = (void *) P;
|
||||||
struct babel_config *new = (void *) c;
|
struct babel_config *new = (void *) CF;
|
||||||
|
|
||||||
TRACE(D_EVENTS, "Reconfiguring");
|
TRACE(D_EVENTS, "Reconfiguring");
|
||||||
|
|
||||||
p->p.cf = c;
|
if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
p->p.cf = CF;
|
||||||
babel_reconfigure_ifaces(p, new);
|
babel_reconfigure_ifaces(p, new);
|
||||||
|
|
||||||
babel_trigger_update(p);
|
babel_trigger_update(p);
|
||||||
|
@ -2133,6 +2118,8 @@ struct protocol proto_babel = {
|
||||||
.template = "babel%d",
|
.template = "babel%d",
|
||||||
.attr_class = EAP_BABEL,
|
.attr_class = EAP_BABEL,
|
||||||
.preference = DEF_PREF_BABEL,
|
.preference = DEF_PREF_BABEL,
|
||||||
|
.channel_mask = NB_IP6,
|
||||||
|
.proto_size = sizeof(struct babel_proto),
|
||||||
.config_size = sizeof(struct babel_config),
|
.config_size = sizeof(struct babel_config),
|
||||||
.init = babel_init,
|
.init = babel_init,
|
||||||
.dump = babel_dump,
|
.dump = babel_dump,
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
/* Max interval that will not overflow when carried as 16-bit centiseconds */
|
/* Max interval that will not overflow when carried as 16-bit centiseconds */
|
||||||
#define BABEL_MAX_INTERVAL (0xFFFF/BABEL_TIME_UNITS)
|
#define BABEL_MAX_INTERVAL (0xFFFF/BABEL_TIME_UNITS)
|
||||||
|
|
||||||
#define BABEL_OVERHEAD (SIZE_OF_IP_HEADER+UDP_HEADER_LENGTH)
|
#define BABEL_OVERHEAD (IP6_HEADER_LENGTH+UDP_HEADER_LENGTH)
|
||||||
#define BABEL_MIN_MTU (512 + BABEL_OVERHEAD)
|
#define BABEL_MIN_MTU (512 + BABEL_OVERHEAD)
|
||||||
|
|
||||||
|
|
||||||
|
@ -208,7 +208,6 @@ struct babel_route {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct babel_entry {
|
struct babel_entry {
|
||||||
struct fib_node n;
|
|
||||||
struct babel_proto *proto;
|
struct babel_proto *proto;
|
||||||
struct babel_route *selected_in;
|
struct babel_route *selected_in;
|
||||||
struct babel_route *selected_out;
|
struct babel_route *selected_out;
|
||||||
|
@ -217,13 +216,14 @@ struct babel_entry {
|
||||||
|
|
||||||
list sources; /* Source entries for this prefix (struct babel_source). */
|
list sources; /* Source entries for this prefix (struct babel_source). */
|
||||||
list routes; /* Routes for this prefix (struct babel_route) */
|
list routes; /* Routes for this prefix (struct babel_route) */
|
||||||
|
|
||||||
|
struct fib_node n;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Stores forwarded seqno requests for duplicate suppression. */
|
/* Stores forwarded seqno requests for duplicate suppression. */
|
||||||
struct babel_seqno_request {
|
struct babel_seqno_request {
|
||||||
node n;
|
node n;
|
||||||
ip_addr prefix;
|
net_addr net;
|
||||||
u8 plen;
|
|
||||||
u64 router_id;
|
u64 router_id;
|
||||||
u16 seqno;
|
u16 seqno;
|
||||||
bird_clock_t updated;
|
bird_clock_t updated;
|
||||||
|
@ -265,12 +265,11 @@ struct babel_msg_ihu {
|
||||||
struct babel_msg_update {
|
struct babel_msg_update {
|
||||||
u8 type;
|
u8 type;
|
||||||
u8 wildcard;
|
u8 wildcard;
|
||||||
u8 plen;
|
|
||||||
u16 interval;
|
u16 interval;
|
||||||
u16 seqno;
|
u16 seqno;
|
||||||
u16 metric;
|
u16 metric;
|
||||||
ip_addr prefix;
|
|
||||||
u64 router_id;
|
u64 router_id;
|
||||||
|
net_addr net;
|
||||||
ip_addr next_hop;
|
ip_addr next_hop;
|
||||||
ip_addr sender;
|
ip_addr sender;
|
||||||
};
|
};
|
||||||
|
@ -278,17 +277,15 @@ struct babel_msg_update {
|
||||||
struct babel_msg_route_request {
|
struct babel_msg_route_request {
|
||||||
u8 type;
|
u8 type;
|
||||||
u8 full;
|
u8 full;
|
||||||
u8 plen;
|
net_addr net;
|
||||||
ip_addr prefix;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct babel_msg_seqno_request {
|
struct babel_msg_seqno_request {
|
||||||
u8 type;
|
u8 type;
|
||||||
u8 plen;
|
|
||||||
u16 seqno;
|
|
||||||
u8 hop_count;
|
u8 hop_count;
|
||||||
|
u16 seqno;
|
||||||
u64 router_id;
|
u64 router_id;
|
||||||
ip_addr prefix;
|
net_addr net;
|
||||||
ip_addr sender;
|
ip_addr sender;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,11 +30,13 @@ CF_ADDTO(proto, babel_proto)
|
||||||
babel_proto_start: proto_start BABEL
|
babel_proto_start: proto_start BABEL
|
||||||
{
|
{
|
||||||
this_proto = proto_config_new(&proto_babel, $1);
|
this_proto = proto_config_new(&proto_babel, $1);
|
||||||
|
this_proto->net_type = NET_IP6;
|
||||||
init_list(&BABEL_CFG->iface_list);
|
init_list(&BABEL_CFG->iface_list);
|
||||||
};
|
};
|
||||||
|
|
||||||
babel_proto_item:
|
babel_proto_item:
|
||||||
proto_item
|
proto_item
|
||||||
|
| proto_channel
|
||||||
| INTERFACE babel_iface
|
| INTERFACE babel_iface
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,8 @@ struct babel_write_state {
|
||||||
#define TLV_HDR(tlv,t,l) ({ tlv->type = t; tlv->length = l - sizeof(struct babel_tlv); })
|
#define TLV_HDR(tlv,t,l) ({ tlv->type = t; tlv->length = l - sizeof(struct babel_tlv); })
|
||||||
#define TLV_HDR0(tlv,t) TLV_HDR(tlv, t, tlv_data[t].min_length)
|
#define TLV_HDR0(tlv,t) TLV_HDR(tlv, t, tlv_data[t].min_length)
|
||||||
|
|
||||||
#define BYTES(n) ((((uint) n) + 7) / 8)
|
#define NET_SIZE(n) BYTES(net_pxlen(n))
|
||||||
|
|
||||||
|
|
||||||
static inline u16
|
static inline u16
|
||||||
get_time16(const void *p)
|
get_time16(const void *p)
|
||||||
|
@ -161,19 +162,19 @@ put_time16(void *p, u16 v)
|
||||||
put_u16(p, v * BABEL_TIME_UNITS);
|
put_u16(p, v * BABEL_TIME_UNITS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline ip6_addr
|
static inline void
|
||||||
get_ip6_px(const void *p, uint plen)
|
read_ip6_px(net_addr *n, const void *p, uint plen)
|
||||||
{
|
{
|
||||||
ip6_addr addr = IPA_NONE;
|
ip6_addr addr = IPA_NONE;
|
||||||
memcpy(&addr, p, BYTES(plen));
|
memcpy(&addr, p, BYTES(plen));
|
||||||
return ip6_ntoh(addr);
|
net_fill_ip6(n, ip6_ntoh(addr), plen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
put_ip6_px(void *p, ip6_addr addr, uint plen)
|
put_ip6_px(void *p, net_addr *n)
|
||||||
{
|
{
|
||||||
addr = ip6_hton(addr);
|
ip6_addr addr = ip6_hton(net6_prefix(n));
|
||||||
memcpy(p, &addr, BYTES(plen));
|
memcpy(p, &addr, NET_SIZE(n));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline ip6_addr
|
static inline ip6_addr
|
||||||
|
@ -480,6 +481,9 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
|
||||||
if (tlv->plen > 0)
|
if (tlv->plen > 0)
|
||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
|
|
||||||
|
if (msg->metric != 65535)
|
||||||
|
return PARSE_ERROR;
|
||||||
|
|
||||||
msg->wildcard = 1;
|
msg->wildcard = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -488,7 +492,7 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
|
||||||
return PARSE_IGNORE;
|
return PARSE_IGNORE;
|
||||||
|
|
||||||
case BABEL_AE_IP6:
|
case BABEL_AE_IP6:
|
||||||
if (tlv->plen > MAX_PREFIX_LENGTH)
|
if (tlv->plen > IP6_MAX_PREFIX_LENGTH)
|
||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
|
|
||||||
/* Cannot omit data if there is no saved prefix */
|
/* Cannot omit data if there is no saved prefix */
|
||||||
|
@ -499,18 +503,18 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
|
||||||
memcpy(buf, state->def_ip6_prefix, tlv->omitted);
|
memcpy(buf, state->def_ip6_prefix, tlv->omitted);
|
||||||
memcpy(buf + tlv->omitted, tlv->addr, len);
|
memcpy(buf + tlv->omitted, tlv->addr, len);
|
||||||
|
|
||||||
msg->plen = tlv->plen;
|
ip6_addr prefix = get_ip6(buf);
|
||||||
msg->prefix = ipa_from_ip6(get_ip6(buf));
|
net_fill_ip6(&msg->net, prefix, tlv->plen);
|
||||||
|
|
||||||
if (tlv->flags & BABEL_FLAG_DEF_PREFIX)
|
if (tlv->flags & BABEL_FLAG_DEF_PREFIX)
|
||||||
{
|
{
|
||||||
put_ip6(state->def_ip6_prefix, msg->prefix);
|
put_ip6(state->def_ip6_prefix, prefix);
|
||||||
state->def_ip6_prefix_seen = 1;
|
state->def_ip6_prefix_seen = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tlv->flags & BABEL_FLAG_ROUTER_ID)
|
if (tlv->flags & BABEL_FLAG_ROUTER_ID)
|
||||||
{
|
{
|
||||||
state->router_id = ((u64) _I2(msg->prefix)) << 32 | _I3(msg->prefix);
|
state->router_id = ((u64) _I2(prefix)) << 32 | _I3(prefix);
|
||||||
state->router_id_seen = 1;
|
state->router_id_seen = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -559,7 +563,7 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
|
||||||
tlv = (struct babel_tlv_update *) NEXT_TLV(tlv);
|
tlv = (struct babel_tlv_update *) NEXT_TLV(tlv);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint len = sizeof(struct babel_tlv_update) + BYTES(msg->plen);
|
uint len = sizeof(struct babel_tlv_update) + NET_SIZE(&msg->net);
|
||||||
|
|
||||||
if (len0 + len > max_len)
|
if (len0 + len > max_len)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -575,8 +579,8 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tlv->ae = BABEL_AE_IP6;
|
tlv->ae = BABEL_AE_IP6;
|
||||||
tlv->plen = msg->plen;
|
tlv->plen = net6_pxlen(&msg->net);
|
||||||
put_ip6_px(tlv->addr, msg->prefix, msg->plen);
|
put_ip6_px(tlv->addr, &msg->net);
|
||||||
}
|
}
|
||||||
|
|
||||||
put_time16(&tlv->interval, msg->interval);
|
put_time16(&tlv->interval, msg->interval);
|
||||||
|
@ -610,14 +614,13 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
|
||||||
return PARSE_IGNORE;
|
return PARSE_IGNORE;
|
||||||
|
|
||||||
case BABEL_AE_IP6:
|
case BABEL_AE_IP6:
|
||||||
if (tlv->plen > MAX_PREFIX_LENGTH)
|
if (tlv->plen > IP6_MAX_PREFIX_LENGTH)
|
||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
|
|
||||||
if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen))
|
if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen))
|
||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
|
|
||||||
msg->plen = tlv->plen;
|
read_ip6_px(&msg->net, tlv->addr, tlv->plen);
|
||||||
msg->prefix = get_ip6_px(tlv->addr, tlv->plen);
|
|
||||||
return PARSE_SUCCESS;
|
return PARSE_SUCCESS;
|
||||||
|
|
||||||
case BABEL_AE_IP6_LL:
|
case BABEL_AE_IP6_LL:
|
||||||
|
@ -637,7 +640,7 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m,
|
||||||
struct babel_tlv_route_request *tlv = (void *) hdr;
|
struct babel_tlv_route_request *tlv = (void *) hdr;
|
||||||
struct babel_msg_route_request *msg = &m->route_request;
|
struct babel_msg_route_request *msg = &m->route_request;
|
||||||
|
|
||||||
uint len = sizeof(struct babel_tlv_route_request) + BYTES(msg->plen);
|
uint len = sizeof(struct babel_tlv_route_request) + NET_SIZE(&msg->net);
|
||||||
|
|
||||||
if (len > max_len)
|
if (len > max_len)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -652,8 +655,8 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tlv->ae = BABEL_AE_IP6;
|
tlv->ae = BABEL_AE_IP6;
|
||||||
tlv->plen = msg->plen;
|
tlv->plen = net6_pxlen(&msg->net);
|
||||||
put_ip6_px(tlv->addr, msg->prefix, msg->plen);
|
put_ip6_px(tlv->addr, &msg->net);
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
|
@ -685,14 +688,13 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
|
||||||
return PARSE_IGNORE;
|
return PARSE_IGNORE;
|
||||||
|
|
||||||
case BABEL_AE_IP6:
|
case BABEL_AE_IP6:
|
||||||
if (tlv->plen > MAX_PREFIX_LENGTH)
|
if (tlv->plen > IP6_MAX_PREFIX_LENGTH)
|
||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
|
|
||||||
if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen))
|
if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen))
|
||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
|
|
||||||
msg->plen = tlv->plen;
|
read_ip6_px(&msg->net, tlv->addr, tlv->plen);
|
||||||
msg->prefix = get_ip6_px(tlv->addr, tlv->plen);
|
|
||||||
return PARSE_SUCCESS;
|
return PARSE_SUCCESS;
|
||||||
|
|
||||||
case BABEL_AE_IP6_LL:
|
case BABEL_AE_IP6_LL:
|
||||||
|
@ -712,18 +714,18 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
|
||||||
struct babel_tlv_seqno_request *tlv = (void *) hdr;
|
struct babel_tlv_seqno_request *tlv = (void *) hdr;
|
||||||
struct babel_msg_seqno_request *msg = &m->seqno_request;
|
struct babel_msg_seqno_request *msg = &m->seqno_request;
|
||||||
|
|
||||||
uint len = sizeof(struct babel_tlv_seqno_request) + BYTES(msg->plen);
|
uint len = sizeof(struct babel_tlv_seqno_request) + NET_SIZE(&msg->net);
|
||||||
|
|
||||||
if (len > max_len)
|
if (len > max_len)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
TLV_HDR(tlv, BABEL_TLV_SEQNO_REQUEST, len);
|
TLV_HDR(tlv, BABEL_TLV_SEQNO_REQUEST, len);
|
||||||
tlv->ae = BABEL_AE_IP6;
|
tlv->ae = BABEL_AE_IP6;
|
||||||
tlv->plen = msg->plen;
|
tlv->plen = net6_pxlen(&msg->net);
|
||||||
put_u16(&tlv->seqno, msg->seqno);
|
put_u16(&tlv->seqno, msg->seqno);
|
||||||
tlv->hop_count = msg->hop_count;
|
tlv->hop_count = msg->hop_count;
|
||||||
put_u64(&tlv->router_id, msg->router_id);
|
put_u64(&tlv->router_id, msg->router_id);
|
||||||
put_ip6_px(tlv->addr, msg->prefix, msg->plen);
|
put_ip6_px(tlv->addr, &msg->net);
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,24 +41,6 @@
|
||||||
* specifies that such updates should be ignored, but that is generally
|
* specifies that such updates should be ignored, but that is generally
|
||||||
* a bad idea.
|
* a bad idea.
|
||||||
*
|
*
|
||||||
* Error checking of optional transitive attributes is done according to
|
|
||||||
* draft-ietf-idr-optional-transitive-03, but errors are handled always
|
|
||||||
* as withdraws.
|
|
||||||
*
|
|
||||||
* Unexpected AS_CONFED_* segments in AS_PATH are logged and removed,
|
|
||||||
* but unknown segments cause a session drop with Malformed AS_PATH
|
|
||||||
* error (see validate_path()). The behavior in such case is not
|
|
||||||
* explicitly specified by RFC 4271. RFC 5065 specifies that
|
|
||||||
* inconsistent AS_CONFED_* segments should cause a session drop, but
|
|
||||||
* implementations that pass invalid AS_CONFED_* segments are
|
|
||||||
* widespread.
|
|
||||||
*
|
|
||||||
* Error handling of AS4_* attributes is done as specified by
|
|
||||||
* draft-ietf-idr-rfc4893bis-03. There are several possible
|
|
||||||
* inconsistencies between AGGREGATOR and AS4_AGGREGATOR that are not
|
|
||||||
* handled by that draft, these are logged and ignored (see
|
|
||||||
* bgp_reconstruct_4b_attrs()).
|
|
||||||
*
|
|
||||||
* BGP attribute table has several hooks:
|
* BGP attribute table has several hooks:
|
||||||
*
|
*
|
||||||
* export - Hook that validates and normalizes attribute during export phase.
|
* export - Hook that validates and normalizes attribute during export phase.
|
||||||
|
@ -281,11 +263,19 @@ bgp_encode_as_path(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
|
||||||
static void
|
static void
|
||||||
bgp_decode_as_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
|
bgp_decode_as_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
|
||||||
{
|
{
|
||||||
|
struct bgp_proto *p = s->proto;
|
||||||
|
int as_length = s->as4_session ? 4 : 2;
|
||||||
|
int as_confed = p->cf->confederation && p->is_interior;
|
||||||
char err[128];
|
char err[128];
|
||||||
|
|
||||||
if (!as_path_valid(data, len, (s->as4_session ? 4 : 2), err, sizeof(err)))
|
if (!as_path_valid(data, len, as_length, as_confed, err, sizeof(err)))
|
||||||
WITHDRAW("Malformed AS_PATH attribute - %s", err);
|
WITHDRAW("Malformed AS_PATH attribute - %s", err);
|
||||||
|
|
||||||
|
/* In some circumstances check for initial AS_CONFED_SEQUENCE; RFC 5065 5.0 */
|
||||||
|
if (p->is_interior && !p->is_internal &&
|
||||||
|
((len < 2) || (data[0] != AS_PATH_CONFED_SEQUENCE)))
|
||||||
|
WITHDRAW("Malformed AS_PATH attribute - %s", "missing initial AS_CONFED_SEQUENCE");
|
||||||
|
|
||||||
if (!s->as4_session)
|
if (!s->as4_session)
|
||||||
{
|
{
|
||||||
/* Prepare 32-bit AS_PATH (from 16-bit one) in a temporary buffer */
|
/* Prepare 32-bit AS_PATH (from 16-bit one) in a temporary buffer */
|
||||||
|
@ -603,11 +593,20 @@ bgp_decode_as4_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byt
|
||||||
if (len < 6)
|
if (len < 6)
|
||||||
DISCARD(BAD_LENGTH, "AS4_PATH", len);
|
DISCARD(BAD_LENGTH, "AS4_PATH", len);
|
||||||
|
|
||||||
if (!as_path_valid(data, len, 4, err, sizeof(err)))
|
if (!as_path_valid(data, len, 4, 1, err, sizeof(err)))
|
||||||
DISCARD("Malformed AS4_PATH attribute - %s", err);
|
DISCARD("Malformed AS4_PATH attribute - %s", err);
|
||||||
|
|
||||||
/* XXXX remove CONFED segments */
|
struct adata *a = lp_alloc_adata(s->pool, len);
|
||||||
bgp_set_attr_data(to, s->pool, BA_AS4_PATH, flags, data, len);
|
memcpy(a->data, data, len);
|
||||||
|
|
||||||
|
/* AS_CONFED* segments are invalid in AS4_PATH; RFC 6793 6 */
|
||||||
|
if (as_path_contains_confed(a))
|
||||||
|
{
|
||||||
|
REPORT("Discarding AS_CONFED* segment from AS4_PATH attribute");
|
||||||
|
a = as_path_strip_confed(s->pool, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
bgp_set_attr_ptr(to, s->pool, BA_AS4_PATH, flags, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1042,7 +1041,7 @@ bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len)
|
||||||
if (bgp_as_path_loopy(p, attrs, p->local_as))
|
if (bgp_as_path_loopy(p, attrs, p->local_as))
|
||||||
goto withdraw;
|
goto withdraw;
|
||||||
|
|
||||||
/* Reject routes with our Confederation ID in AS_PATH attribute; RFC 5065 4 */
|
/* Reject routes with our Confederation ID in AS_PATH attribute; RFC 5065 4.0 */
|
||||||
if ((p->public_as != p->local_as) && bgp_as_path_loopy(p, attrs, p->public_as))
|
if ((p->public_as != p->local_as) && bgp_as_path_loopy(p, attrs, p->public_as))
|
||||||
goto withdraw;
|
goto withdraw;
|
||||||
|
|
||||||
|
@ -1221,8 +1220,17 @@ bgp_init_prefix_table(struct bgp_channel *c)
|
||||||
{
|
{
|
||||||
HASH_INIT(c->prefix_hash, c->pool, 8);
|
HASH_INIT(c->prefix_hash, c->pool, 8);
|
||||||
|
|
||||||
c->prefix_slab = sl_new(c->pool, sizeof(struct bgp_prefix) +
|
uint alen = net_addr_length[c->c.net_type];
|
||||||
net_addr_length[c->c.net_type]);
|
c->prefix_slab = alen ? sl_new(c->pool, sizeof(struct bgp_prefix) + alen) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bgp_free_prefix_table(struct bgp_channel *c)
|
||||||
|
{
|
||||||
|
HASH_FREE(c->prefix_hash);
|
||||||
|
|
||||||
|
rfree(c->prefix_slab);
|
||||||
|
c->prefix_slab = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bgp_prefix *
|
static struct bgp_prefix *
|
||||||
|
@ -1237,7 +1245,11 @@ bgp_get_prefix(struct bgp_channel *c, net_addr *net, u32 path_id)
|
||||||
return px;
|
return px;
|
||||||
}
|
}
|
||||||
|
|
||||||
px = sl_alloc(c->prefix_slab);
|
if (c->prefix_slab)
|
||||||
|
px = sl_alloc(c->prefix_slab);
|
||||||
|
else
|
||||||
|
px = mb_alloc(c->pool, sizeof(struct bgp_prefix) + net->length);
|
||||||
|
|
||||||
px->buck_node.next = NULL;
|
px->buck_node.next = NULL;
|
||||||
px->buck_node.prev = NULL;
|
px->buck_node.prev = NULL;
|
||||||
px->hash = hash;
|
px->hash = hash;
|
||||||
|
@ -1254,7 +1266,11 @@ bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *px)
|
||||||
{
|
{
|
||||||
rem_node(&px->buck_node);
|
rem_node(&px->buck_node);
|
||||||
HASH_REMOVE2(c->prefix_hash, PXH, c->pool, px);
|
HASH_REMOVE2(c->prefix_hash, PXH, c->pool, px);
|
||||||
sl_free(c->prefix_slab, px);
|
|
||||||
|
if (c->prefix_slab)
|
||||||
|
sl_free(c->prefix_slab, px);
|
||||||
|
else
|
||||||
|
mb_free(px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1278,6 +1294,8 @@ bgp_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct li
|
||||||
if (src == NULL)
|
if (src == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// XXXX: Check next hop AF
|
||||||
|
|
||||||
/* IBGP route reflection, RFC 4456 */
|
/* IBGP route reflection, RFC 4456 */
|
||||||
if (p->is_internal && src->is_internal && (p->local_as == src->local_as))
|
if (p->is_internal && src->is_internal && (p->local_as == src->local_as))
|
||||||
{
|
{
|
||||||
|
@ -1314,82 +1332,86 @@ bgp_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct li
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const adata null_adata; /* adata of length 0 */
|
|
||||||
|
|
||||||
static inline void
|
static adata null_adata; /* adata of length 0 */
|
||||||
bgp_path_prepend(ea_list **attrs, struct linpool *pool, int seg, u32 as, int strip)
|
|
||||||
{
|
|
||||||
eattr *a = bgp_find_attr(*attrs, BA_AS_PATH);
|
|
||||||
adata *d = as_path_prepend2(pool, a ? a->u.ptr : &null_adata, seg, as, strip);
|
|
||||||
bgp_set_attr_ptr(attrs, pool, BA_AS_PATH, 0, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
bgp_cluster_list_prepend(ea_list **attrs, struct linpool *pool, u32 id)
|
|
||||||
{
|
|
||||||
eattr *a = bgp_find_attr(*attrs, BA_CLUSTER_LIST);
|
|
||||||
adata *d = int_set_add(pool, a ? a->u.ptr : NULL, id);
|
|
||||||
bgp_set_attr_ptr(attrs, pool, BA_CLUSTER_LIST, 0, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ea_list *
|
static ea_list *
|
||||||
bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *attrs, struct linpool *pool)
|
bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *attrs0, struct linpool *pool)
|
||||||
{
|
{
|
||||||
struct proto *SRC = e->attrs->src->proto;
|
struct proto *SRC = e->attrs->src->proto;
|
||||||
struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (void *) SRC : NULL;
|
struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (void *) SRC : NULL;
|
||||||
struct bgp_export_state s = { .proto = p, .channel =c, .pool = pool, .src = src, .route = e };
|
struct bgp_export_state s = { .proto = p, .channel =c, .pool = pool, .src = src, .route = e };
|
||||||
|
ea_list *attrs = attrs0;
|
||||||
eattr *a;
|
eattr *a;
|
||||||
|
adata *ad;
|
||||||
|
|
||||||
/* ORIGIN attribute - mandatory, attach if missing */
|
/* ORIGIN attribute - mandatory, attach if missing */
|
||||||
if (! bgp_find_attr(attrs, BA_ORIGIN))
|
if (! bgp_find_attr(attrs0, BA_ORIGIN))
|
||||||
bgp_set_attr_u32(&attrs, pool, BA_ORIGIN, 0, src ? ORIGIN_INCOMPLETE : ORIGIN_IGP);
|
bgp_set_attr_u32(&attrs, pool, BA_ORIGIN, 0, src ? ORIGIN_INCOMPLETE : ORIGIN_IGP);
|
||||||
|
|
||||||
|
/* AS_PATH attribute - mandatory */
|
||||||
|
a = bgp_find_attr(attrs0, BA_AS_PATH);
|
||||||
|
ad = a ? a->u.ptr : &null_adata;
|
||||||
|
|
||||||
|
/* AS_PATH attribute - strip AS_CONFED* segments outside confederation */
|
||||||
|
if ((!p->cf->confederation || !p->is_interior) && as_path_contains_confed(ad))
|
||||||
|
ad = as_path_strip_confed(pool, ad);
|
||||||
|
|
||||||
/* AS_PATH attribute - keep or prepend ASN */
|
/* AS_PATH attribute - keep or prepend ASN */
|
||||||
if (p->is_internal ||
|
if (p->is_internal ||
|
||||||
(p->rs_client && src && src->rs_client))
|
(p->rs_client && src && src->rs_client))
|
||||||
{
|
{
|
||||||
/* IBGP or route server -> just ensure there is one */
|
/* IBGP or route server -> just ensure there is one */
|
||||||
if (! bgp_find_attr(attrs, BA_AS_PATH))
|
if (!a)
|
||||||
bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, lp_alloc_adata(pool, 0));
|
bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, &null_adata);
|
||||||
}
|
}
|
||||||
else if (p->is_interior)
|
else if (p->is_interior)
|
||||||
{
|
{
|
||||||
/* Confederation -> prepend ASN as CONFED_SEQUENCE, keep CONFED_* segments */
|
/* Confederation -> prepend ASN as AS_CONFED_SEQUENCE */
|
||||||
bgp_path_prepend(&attrs, pool, AS_PATH_CONFED_SEQUENCE, p->public_as, 0);
|
ad = as_path_prepend2(pool, ad, AS_PATH_CONFED_SEQUENCE, p->public_as);
|
||||||
|
bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, ad);
|
||||||
}
|
}
|
||||||
else /* Regular EBGP (no RS, no confederation) */
|
else /* Regular EBGP (no RS, no confederation) */
|
||||||
{
|
{
|
||||||
/* Regular EBGP -> prepend ASN as regular segment, strip CONFED_* segments */
|
/* Regular EBGP -> prepend ASN as regular sequence */
|
||||||
bgp_path_prepend(&attrs, pool, AS_PATH_SEQUENCE, p->public_as, 1);
|
ad = as_path_prepend2(pool, ad, AS_PATH_SEQUENCE, p->public_as);
|
||||||
|
bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, ad);
|
||||||
|
|
||||||
/* MULTI_EXIT_DESC attribute - accept only if set in export filter */
|
/* MULTI_EXIT_DESC attribute - accept only if set in export filter */
|
||||||
a = bgp_find_attr(attrs, BA_MULTI_EXIT_DISC);
|
a = bgp_find_attr(attrs0, BA_MULTI_EXIT_DISC);
|
||||||
if (a && !(a->type & EAF_FRESH))
|
if (a && !(a->type & EAF_FRESH))
|
||||||
bgp_unset_attr(&attrs, pool, BA_MULTI_EXIT_DISC);
|
bgp_unset_attr(&attrs, pool, BA_MULTI_EXIT_DISC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NEXT_HOP attribute - delegated to AF-specific hook */
|
/* NEXT_HOP attribute - delegated to AF-specific hook */
|
||||||
a = bgp_find_attr(attrs, BA_NEXT_HOP);
|
a = bgp_find_attr(attrs0, BA_NEXT_HOP);
|
||||||
bgp_update_next_hop(&s, a, &attrs);
|
bgp_update_next_hop(&s, a, &attrs);
|
||||||
|
|
||||||
/* LOCAL_PREF attribute - required for IBGP, attach if missing */
|
/* LOCAL_PREF attribute - required for IBGP, attach if missing */
|
||||||
if (p->is_interior && ! bgp_find_attr(attrs, BA_LOCAL_PREF))
|
if (p->is_interior && ! bgp_find_attr(attrs0, BA_LOCAL_PREF))
|
||||||
bgp_set_attr_u32(&attrs, pool, BA_LOCAL_PREF, 0, p->cf->default_local_pref);
|
bgp_set_attr_u32(&attrs, pool, BA_LOCAL_PREF, 0, p->cf->default_local_pref);
|
||||||
|
|
||||||
/* IBGP route reflection, RFC 4456 */
|
/* IBGP route reflection, RFC 4456 */
|
||||||
if (src && src->is_internal && p->is_internal && (src->local_as == p->local_as))
|
if (src && src->is_internal && p->is_internal && (src->local_as == p->local_as))
|
||||||
{
|
{
|
||||||
/* ORIGINATOR_ID attribute - attach if not already set */
|
/* ORIGINATOR_ID attribute - attach if not already set */
|
||||||
if (! bgp_find_attr(attrs, BA_ORIGINATOR_ID))
|
if (! bgp_find_attr(attrs0, BA_ORIGINATOR_ID))
|
||||||
bgp_set_attr_u32(&attrs, pool, BA_ORIGINATOR_ID, 0, src->remote_id);
|
bgp_set_attr_u32(&attrs, pool, BA_ORIGINATOR_ID, 0, src->remote_id);
|
||||||
|
|
||||||
/* CLUSTER_LIST attribute - prepend cluster ID */
|
/* CLUSTER_LIST attribute - prepend cluster ID */
|
||||||
if (src->rr_cluster_id)
|
a = bgp_find_attr(attrs0, BA_CLUSTER_LIST);
|
||||||
bgp_cluster_list_prepend(&attrs, pool, src->rr_cluster_id);
|
ad = a ? a->u.ptr : NULL;
|
||||||
|
|
||||||
/* Handle different src and dst cluster ID - prepend both ones */
|
/* Prepend src cluster ID */
|
||||||
|
if (src->rr_cluster_id)
|
||||||
|
ad = int_set_prepend(pool, ad, src->rr_cluster_id);
|
||||||
|
|
||||||
|
/* Prepend dst cluster ID if src and dst clusters are different */
|
||||||
if (p->rr_cluster_id && (src->rr_cluster_id != p->rr_cluster_id))
|
if (p->rr_cluster_id && (src->rr_cluster_id != p->rr_cluster_id))
|
||||||
bgp_cluster_list_prepend(&attrs, pool, p->rr_cluster_id);
|
ad = int_set_prepend(pool, ad, p->rr_cluster_id);
|
||||||
|
|
||||||
|
/* Should be at least one prepended cluster ID */
|
||||||
|
bgp_set_attr_ptr(&attrs, pool, BA_CLUSTER_LIST, 0, ad);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* AS4_* transition attributes, RFC 6793 4.2.2 */
|
/* AS4_* transition attributes, RFC 6793 4.2.2 */
|
||||||
|
@ -1410,6 +1432,12 @@ bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *at
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Presence of mandatory attributes ORIGIN and AS_PATH is ensured by above
|
||||||
|
* conditions. Presence and validity of quasi-mandatory NEXT_HOP attribute
|
||||||
|
* should be checked in AF-specific hooks.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Apply per-attribute export hooks for validatation and normalization */
|
/* Apply per-attribute export hooks for validatation and normalization */
|
||||||
return bgp_export_attrs(&s, attrs);
|
return bgp_export_attrs(&s, attrs);
|
||||||
}
|
}
|
||||||
|
@ -1452,10 +1480,12 @@ bgp_get_neighbor(rte *r)
|
||||||
eattr *e = ea_find(r->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
|
eattr *e = ea_find(r->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
|
||||||
u32 as;
|
u32 as;
|
||||||
|
|
||||||
if (e && as_path_get_first(e->u.ptr, &as))
|
if (e && as_path_get_first_regular(e->u.ptr, &as))
|
||||||
return as;
|
return as;
|
||||||
else
|
|
||||||
return ((struct bgp_proto *) r->attrs->src->proto)->remote_as;
|
/* If AS_PATH is not defined, we treat rte as locally originated */
|
||||||
|
struct bgp_proto *p = (void *) r->attrs->src->proto;
|
||||||
|
return p->cf->confederation ?: p->local_as;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
|
@ -1653,7 +1683,7 @@ bgp_rte_mergable(rte *pri, rte *sec)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RFC 4271 9.1.2.2. d) Prefer external peers */
|
/* RFC 4271 9.1.2.2. d) Prefer external peers */
|
||||||
if (pri_bgp->is_internal != sec_bgp->is_internal)
|
if (pri_bgp->is_interior != sec_bgp->is_interior)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* RFC 4271 9.1.2.2. e) Compare IGP metrics */
|
/* RFC 4271 9.1.2.2. e) Compare IGP metrics */
|
||||||
|
@ -1843,6 +1873,7 @@ bgp_process_as4_attrs(ea_list **attrs, struct linpool *pool)
|
||||||
/* Handle AS_PATH attribute */
|
/* Handle AS_PATH attribute */
|
||||||
if (p2 && p4)
|
if (p2 && p4)
|
||||||
{
|
{
|
||||||
|
/* Both as_path_getlen() and as_path_cut() take AS_CONFED* as zero length */
|
||||||
int p2_len = as_path_getlen(p2->u.ptr);
|
int p2_len = as_path_getlen(p2->u.ptr);
|
||||||
int p4_len = as_path_getlen(p4->u.ptr);
|
int p4_len = as_path_getlen(p4->u.ptr);
|
||||||
|
|
||||||
|
|
154
proto/bgp/bgp.c
154
proto/bgp/bgp.c
|
@ -521,12 +521,17 @@ bgp_conn_enter_established_state(struct bgp_conn *conn)
|
||||||
if (peer->gr_aware)
|
if (peer->gr_aware)
|
||||||
c->load_state = BFS_LOADING;
|
c->load_state = BFS_LOADING;
|
||||||
|
|
||||||
|
c->ext_next_hop = c->cf->ext_next_hop && (bgp_channel_is_ipv6(c) || rem->ext_next_hop);
|
||||||
c->add_path_rx = (loc->add_path & BGP_ADD_PATH_RX) && (rem->add_path & BGP_ADD_PATH_TX);
|
c->add_path_rx = (loc->add_path & BGP_ADD_PATH_RX) && (rem->add_path & BGP_ADD_PATH_TX);
|
||||||
c->add_path_tx = (loc->add_path & BGP_ADD_PATH_TX) && (rem->add_path & BGP_ADD_PATH_RX);
|
c->add_path_tx = (loc->add_path & BGP_ADD_PATH_TX) && (rem->add_path & BGP_ADD_PATH_RX);
|
||||||
|
|
||||||
// XXXX reset back to non-ANY?
|
/* Update RA mode */
|
||||||
if (c->add_path_tx)
|
if (c->add_path_tx)
|
||||||
c->c.ra_mode = RA_ANY;
|
c->c.ra_mode = RA_ANY;
|
||||||
|
else if (c->cf->secondary)
|
||||||
|
c->c.ra_mode = RA_ACCEPTED;
|
||||||
|
else
|
||||||
|
c->c.ra_mode = RA_OPTIMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
p->afi_map = mb_alloc(p->p.pool, num * sizeof(u32));
|
p->afi_map = mb_alloc(p->p.pool, num * sizeof(u32));
|
||||||
|
@ -554,6 +559,10 @@ bgp_conn_leave_established_state(struct bgp_proto *p)
|
||||||
BGP_TRACE(D_EVENTS, "BGP session closed");
|
BGP_TRACE(D_EVENTS, "BGP session closed");
|
||||||
p->conn = NULL;
|
p->conn = NULL;
|
||||||
|
|
||||||
|
// XXXX free these tables to avoid memory leak during graceful restart
|
||||||
|
// bgp_free_prefix_table(p);
|
||||||
|
// bgp_free_bucket_table(p);
|
||||||
|
|
||||||
if (p->p.proto_state == PS_UP)
|
if (p->p.proto_state == PS_UP)
|
||||||
bgp_stop(p, 0);
|
bgp_stop(p, 0);
|
||||||
}
|
}
|
||||||
|
@ -1411,8 +1420,6 @@ bgp_channel_init(struct channel *C, struct channel_config *CF)
|
||||||
struct bgp_channel *c = (void *) C;
|
struct bgp_channel *c = (void *) C;
|
||||||
struct bgp_channel_config *cf = (void *) CF;
|
struct bgp_channel_config *cf = (void *) CF;
|
||||||
|
|
||||||
C->ra_mode = cf->secondary ? RA_ACCEPTED : RA_OPTIMAL;
|
|
||||||
|
|
||||||
c->cf = cf;
|
c->cf = cf;
|
||||||
c->afi = cf->afi;
|
c->afi = cf->afi;
|
||||||
c->desc = bgp_get_af_desc(c->afi);
|
c->desc = bgp_get_af_desc(c->afi);
|
||||||
|
@ -1756,11 +1763,132 @@ bgp_get_status(struct proto *P, byte *buf)
|
||||||
bsprintf(buf, "%-14s%s%s", bgp_state_dsc(p), err1, err2);
|
bsprintf(buf, "%-14s%s%s", bgp_state_dsc(p), err1, err2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bgp_show_afis(int code, char *s, u32 *afis, uint count)
|
||||||
|
{
|
||||||
|
buffer b;
|
||||||
|
LOG_BUFFER_INIT(b);
|
||||||
|
|
||||||
|
buffer_puts(&b, s);
|
||||||
|
|
||||||
|
for (u32 *af = afis; af < (afis + count); af++)
|
||||||
|
{
|
||||||
|
const struct bgp_af_desc *desc = bgp_get_af_desc(*af);
|
||||||
|
if (desc)
|
||||||
|
buffer_print(&b, " %s", desc->name);
|
||||||
|
else
|
||||||
|
buffer_print(&b, " <%u/%u>", BGP_AFI(*af), BGP_SAFI(*af));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.pos == b.end)
|
||||||
|
strcpy(b.end - 32, " ... <too long>");
|
||||||
|
|
||||||
|
cli_msg(code, b.start);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bgp_show_capabilities(struct bgp_proto *p UNUSED, struct bgp_caps *caps)
|
||||||
|
{
|
||||||
|
struct bgp_af_caps *ac;
|
||||||
|
uint any_mp_bgp = 0;
|
||||||
|
uint any_gr_able = 0;
|
||||||
|
uint any_add_path = 0;
|
||||||
|
uint any_ext_next_hop = 0;
|
||||||
|
u32 *afl1 = alloca(caps->af_count * sizeof(u32));
|
||||||
|
u32 *afl2 = alloca(caps->af_count * sizeof(u32));
|
||||||
|
uint afn1, afn2;
|
||||||
|
|
||||||
|
WALK_AF_CAPS(caps, ac)
|
||||||
|
{
|
||||||
|
any_mp_bgp |= ac->ready;
|
||||||
|
any_gr_able |= ac->gr_able;
|
||||||
|
any_add_path |= ac->add_path;
|
||||||
|
any_ext_next_hop |= ac->ext_next_hop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (any_mp_bgp)
|
||||||
|
{
|
||||||
|
cli_msg(-1006, " Multiprotocol");
|
||||||
|
|
||||||
|
afn1 = 0;
|
||||||
|
WALK_AF_CAPS(caps, ac)
|
||||||
|
if (ac->ready)
|
||||||
|
afl1[afn1++] = ac->afi;
|
||||||
|
|
||||||
|
bgp_show_afis(-1006, " AF announced:", afl1, afn1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caps->route_refresh)
|
||||||
|
cli_msg(-1006, " Route refresh");
|
||||||
|
|
||||||
|
if (any_ext_next_hop)
|
||||||
|
{
|
||||||
|
cli_msg(-1006, " Extended next hop");
|
||||||
|
|
||||||
|
afn1 = 0;
|
||||||
|
WALK_AF_CAPS(caps, ac)
|
||||||
|
if (ac->ext_next_hop)
|
||||||
|
afl1[afn1++] = ac->afi;
|
||||||
|
|
||||||
|
bgp_show_afis(-1006, " IPv6 nexthop:", afl1, afn1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caps->ext_messages)
|
||||||
|
cli_msg(-1006, " Extended message");
|
||||||
|
|
||||||
|
if (caps->gr_aware)
|
||||||
|
cli_msg(-1006, " Graceful restart");
|
||||||
|
|
||||||
|
if (any_gr_able)
|
||||||
|
{
|
||||||
|
/* Continues from gr_aware */
|
||||||
|
cli_msg(-1006, " Restart time: %u", caps->gr_time);
|
||||||
|
if (caps->gr_flags & BGP_GRF_RESTART)
|
||||||
|
cli_msg(-1006, " Restart recovery");
|
||||||
|
|
||||||
|
afn1 = afn2 = 0;
|
||||||
|
WALK_AF_CAPS(caps, ac)
|
||||||
|
{
|
||||||
|
if (ac->gr_able)
|
||||||
|
afl1[afn1++] = ac->afi;
|
||||||
|
|
||||||
|
if (ac->gr_af_flags & BGP_GRF_FORWARDING)
|
||||||
|
afl2[afn2++] = ac->afi;
|
||||||
|
}
|
||||||
|
|
||||||
|
bgp_show_afis(-1006, " AF supported:", afl1, afn1);
|
||||||
|
bgp_show_afis(-1006, " AF preserved:", afl2, afn2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caps->as4_support)
|
||||||
|
cli_msg(-1006, " 4-octet AS numbers");
|
||||||
|
|
||||||
|
if (any_add_path)
|
||||||
|
{
|
||||||
|
cli_msg(-1006, " ADD-PATH");
|
||||||
|
|
||||||
|
afn1 = afn2 = 0;
|
||||||
|
WALK_AF_CAPS(caps, ac)
|
||||||
|
{
|
||||||
|
if (ac->add_path & BGP_ADD_PATH_RX)
|
||||||
|
afl1[afn1++] = ac->afi;
|
||||||
|
|
||||||
|
if (ac->add_path & BGP_ADD_PATH_TX)
|
||||||
|
afl2[afn2++] = ac->afi;
|
||||||
|
}
|
||||||
|
|
||||||
|
bgp_show_afis(-1006, " RX:", afl1, afn1);
|
||||||
|
bgp_show_afis(-1006, " TX:", afl2, afn2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caps->enhanced_refresh)
|
||||||
|
cli_msg(-1006, " Enhanced refresh");
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bgp_show_proto_info(struct proto *P)
|
bgp_show_proto_info(struct proto *P)
|
||||||
{
|
{
|
||||||
struct bgp_proto *p = (struct bgp_proto *) P;
|
struct bgp_proto *p = (struct bgp_proto *) P;
|
||||||
struct bgp_conn *c = p->conn;
|
|
||||||
|
|
||||||
cli_msg(-1006, " BGP state: %s", bgp_state_dsc(p));
|
cli_msg(-1006, " BGP state: %s", bgp_state_dsc(p));
|
||||||
cli_msg(-1006, " Neighbor address: %I%J", p->cf->remote_ip, p->cf->iface);
|
cli_msg(-1006, " Neighbor address: %I%J", p->cf->remote_ip, p->cf->iface);
|
||||||
|
@ -1789,15 +1917,11 @@ bgp_show_proto_info(struct proto *P)
|
||||||
else if (P->proto_state == PS_UP)
|
else if (P->proto_state == PS_UP)
|
||||||
{
|
{
|
||||||
cli_msg(-1006, " Neighbor ID: %R", p->remote_id);
|
cli_msg(-1006, " Neighbor ID: %R", p->remote_id);
|
||||||
|
cli_msg(-1006, " Local capabilities");
|
||||||
|
bgp_show_capabilities(p, p->conn->local_caps);
|
||||||
|
cli_msg(-1006, " Neighbor capabilities");
|
||||||
|
bgp_show_capabilities(p, p->conn->remote_caps);
|
||||||
/* XXXX
|
/* XXXX
|
||||||
cli_msg(-1006, " Neighbor caps: %s%s%s%s%s%s%s",
|
|
||||||
c->peer_refresh_support ? " refresh" : "",
|
|
||||||
c->peer_enhanced_refresh_support ? " enhanced-refresh" : "",
|
|
||||||
c->peer_gr_able ? " restart-able" : (c->peer_gr_aware ? " restart-aware" : ""),
|
|
||||||
c->peer_as4_support ? " AS4" : "",
|
|
||||||
(c->peer_add_path & ADD_PATH_RX) ? " add-path-rx" : "",
|
|
||||||
(c->peer_add_path & ADD_PATH_TX) ? " add-path-tx" : "",
|
|
||||||
c->peer_ext_messages_support ? " ext-messages" : "");
|
|
||||||
cli_msg(-1006, " Session: %s%s%s%s%s%s%s%s",
|
cli_msg(-1006, " Session: %s%s%s%s%s%s%s%s",
|
||||||
p->is_internal ? "internal" : "external",
|
p->is_internal ? "internal" : "external",
|
||||||
p->cf->multihop ? " multihop" : "",
|
p->cf->multihop ? " multihop" : "",
|
||||||
|
@ -1810,9 +1934,9 @@ bgp_show_proto_info(struct proto *P)
|
||||||
*/
|
*/
|
||||||
cli_msg(-1006, " Source address: %I", p->source_addr);
|
cli_msg(-1006, " Source address: %I", p->source_addr);
|
||||||
cli_msg(-1006, " Hold timer: %d/%d",
|
cli_msg(-1006, " Hold timer: %d/%d",
|
||||||
tm_remains(c->hold_timer), c->hold_time);
|
tm_remains(p->conn->hold_timer), p->conn->hold_time);
|
||||||
cli_msg(-1006, " Keepalive timer: %d/%d",
|
cli_msg(-1006, " Keepalive timer: %d/%d",
|
||||||
tm_remains(c->keepalive_timer), c->keepalive_time);
|
tm_remains(p->conn->keepalive_timer), p->conn->keepalive_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((p->last_error_class != BE_NONE) &&
|
if ((p->last_error_class != BE_NONE) &&
|
||||||
|
@ -1846,7 +1970,7 @@ struct protocol proto_bgp = {
|
||||||
.template = "bgp%d",
|
.template = "bgp%d",
|
||||||
.attr_class = EAP_BGP,
|
.attr_class = EAP_BGP,
|
||||||
.preference = DEF_PREF_BGP,
|
.preference = DEF_PREF_BGP,
|
||||||
.channel_mask = NB_IP,
|
.channel_mask = NB_IP | NB_FLOW4 | NB_FLOW6,
|
||||||
.proto_size = sizeof(struct bgp_proto),
|
.proto_size = sizeof(struct bgp_proto),
|
||||||
.config_size = sizeof(struct bgp_config),
|
.config_size = sizeof(struct bgp_config),
|
||||||
.postconfig = bgp_postconfig,
|
.postconfig = bgp_postconfig,
|
||||||
|
|
|
@ -31,6 +31,7 @@ struct eattr;
|
||||||
|
|
||||||
#define BGP_SAFI_UNICAST 1
|
#define BGP_SAFI_UNICAST 1
|
||||||
#define BGP_SAFI_MULTICAST 2
|
#define BGP_SAFI_MULTICAST 2
|
||||||
|
#define BGP_SAFI_FLOW 133
|
||||||
|
|
||||||
/* Internal AF codes */
|
/* Internal AF codes */
|
||||||
|
|
||||||
|
@ -42,6 +43,8 @@ struct eattr;
|
||||||
#define BGP_AF_IPV6 BGP_AF( BGP_AFI_IPV6, BGP_SAFI_UNICAST )
|
#define BGP_AF_IPV6 BGP_AF( BGP_AFI_IPV6, BGP_SAFI_UNICAST )
|
||||||
#define BGP_AF_IPV4_MC BGP_AF( BGP_AFI_IPV4, BGP_SAFI_MULTICAST )
|
#define BGP_AF_IPV4_MC BGP_AF( BGP_AFI_IPV4, BGP_SAFI_MULTICAST )
|
||||||
#define BGP_AF_IPV6_MC BGP_AF( BGP_AFI_IPV6, BGP_SAFI_MULTICAST )
|
#define BGP_AF_IPV6_MC BGP_AF( BGP_AFI_IPV6, BGP_SAFI_MULTICAST )
|
||||||
|
#define BGP_AF_FLOW4 BGP_AF( BGP_AFI_IPV4, BGP_SAFI_FLOW )
|
||||||
|
#define BGP_AF_FLOW6 BGP_AF( BGP_AFI_IPV6, BGP_SAFI_FLOW )
|
||||||
|
|
||||||
|
|
||||||
struct bgp_write_state;
|
struct bgp_write_state;
|
||||||
|
@ -70,7 +73,7 @@ struct bgp_config {
|
||||||
u16 local_port; /* Local listening port */
|
u16 local_port; /* Local listening port */
|
||||||
u16 remote_port; /* Neighbor destination port */
|
u16 remote_port; /* Neighbor destination port */
|
||||||
int multihop; /* Number of hops if multihop */
|
int multihop; /* Number of hops if multihop */
|
||||||
int strict_bind; /* Bind listening socket to local address XXXX */
|
int strict_bind; /* Bind listening socket to local address */
|
||||||
int ttl_security; /* Enable TTL security [RFC 5082] */
|
int ttl_security; /* Enable TTL security [RFC 5082] */
|
||||||
int compare_path_lengths; /* Use path lengths when selecting best route */
|
int compare_path_lengths; /* Use path lengths when selecting best route */
|
||||||
int med_metric; /* Compare MULTI_EXIT_DISC even between routes from differen ASes */
|
int med_metric; /* Compare MULTI_EXIT_DISC even between routes from differen ASes */
|
||||||
|
@ -120,6 +123,7 @@ struct bgp_channel_config {
|
||||||
u8 gw_mode; /* How we compute route gateway from next_hop attr, see GW_* */
|
u8 gw_mode; /* How we compute route gateway from next_hop attr, see GW_* */
|
||||||
u8 secondary; /* Accept also non-best routes (i.e. RA_ACCEPTED) */
|
u8 secondary; /* Accept also non-best routes (i.e. RA_ACCEPTED) */
|
||||||
u8 gr_able; /* Allow full graceful restart for the channel */
|
u8 gr_able; /* Allow full graceful restart for the channel */
|
||||||
|
u8 ext_next_hop; /* Allow both IPv4 and IPv6 next hops */
|
||||||
u8 add_path; /* Use ADD-PATH extension [RFC 7911] */
|
u8 add_path; /* Use ADD-PATH extension [RFC 7911] */
|
||||||
|
|
||||||
struct rtable_config *igp_table; /* Table used for recursive next hop lookups */
|
struct rtable_config *igp_table; /* Table used for recursive next hop lookups */
|
||||||
|
@ -151,6 +155,7 @@ struct bgp_af_caps {
|
||||||
u8 ready; /* Multiprotocol capability, RFC 4760 */
|
u8 ready; /* Multiprotocol capability, RFC 4760 */
|
||||||
u8 gr_able; /* Graceful restart support, RFC 4724 */
|
u8 gr_able; /* Graceful restart support, RFC 4724 */
|
||||||
u8 gr_af_flags; /* Graceful restart per-AF flags */
|
u8 gr_af_flags; /* Graceful restart per-AF flags */
|
||||||
|
u8 ext_next_hop; /* Extended IPv6 next hop, RFC 5549 */
|
||||||
u8 add_path; /* Multiple paths support, RFC 7911 */
|
u8 add_path; /* Multiple paths support, RFC 7911 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -171,6 +176,10 @@ struct bgp_caps {
|
||||||
struct bgp_af_caps af_data[0]; /* Per-AF capability data */
|
struct bgp_af_caps af_data[0]; /* Per-AF capability data */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define WALK_AF_CAPS(caps,ac) \
|
||||||
|
for (ac = caps->af_data; ac < &caps->af_data[caps->af_count]; ac++)
|
||||||
|
|
||||||
|
|
||||||
struct bgp_socket {
|
struct bgp_socket {
|
||||||
node n; /* Node in global bgp_sockets */
|
node n; /* Node in global bgp_sockets */
|
||||||
sock *sk; /* Real listening socket */
|
sock *sk; /* Real listening socket */
|
||||||
|
@ -267,6 +276,8 @@ struct bgp_channel {
|
||||||
u8 gr_ready; /* Neighbor could do GR on this AF */
|
u8 gr_ready; /* Neighbor could do GR on this AF */
|
||||||
u8 gr_active; /* Neighbor is doing GR and keeping fwd state */
|
u8 gr_active; /* Neighbor is doing GR and keeping fwd state */
|
||||||
|
|
||||||
|
u8 ext_next_hop; /* Session allows both IPv4 and IPv6 next hops */
|
||||||
|
|
||||||
u8 add_path_rx; /* Session expects receive of ADD-PATH extended NLRI */
|
u8 add_path_rx; /* Session expects receive of ADD-PATH extended NLRI */
|
||||||
u8 add_path_tx; /* Session expects transmit of ADD-PATH extended NLRI */
|
u8 add_path_tx; /* Session expects transmit of ADD-PATH extended NLRI */
|
||||||
|
|
||||||
|
@ -446,18 +457,6 @@ bgp_unset_attr(ea_list **to, struct linpool *pool, uint code)
|
||||||
{ eattr *e = bgp_set_attr(to, pool, code, 0, 0); e->type = EAF_TYPE_UNDEF; }
|
{ eattr *e = bgp_set_attr(to, pool, code, 0, 0); e->type = EAF_TYPE_UNDEF; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* 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 XXX
|
|
||||||
#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; }
|
|
||||||
#define NEXT_HOP_LENGTH sizeof(ip_addr)
|
|
||||||
static inline void set_next_hop(byte *b, ip_addr addr) { ((ip_addr *) b)[0] = addr; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte *end);
|
int bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte *end);
|
||||||
ea_list * bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len);
|
ea_list * bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len);
|
||||||
|
|
||||||
|
@ -510,26 +509,22 @@ void bgp_update_next_hop(struct bgp_export_state *s, eattr *a, ea_list **to);
|
||||||
#define BAF_PARTIAL 0x20
|
#define BAF_PARTIAL 0x20
|
||||||
#define BAF_EXT_LEN 0x10
|
#define BAF_EXT_LEN 0x10
|
||||||
|
|
||||||
#define BA_ORIGIN 0x01 /* [RFC1771] */ /* WM */
|
#define BA_ORIGIN 0x01 /* RFC 4271 */ /* WM */
|
||||||
#define BA_AS_PATH 0x02 /* WM */
|
#define BA_AS_PATH 0x02 /* WM */
|
||||||
#define BA_NEXT_HOP 0x03 /* WM */
|
#define BA_NEXT_HOP 0x03 /* WM */
|
||||||
#define BA_MULTI_EXIT_DISC 0x04 /* ON */
|
#define BA_MULTI_EXIT_DISC 0x04 /* ON */
|
||||||
#define BA_LOCAL_PREF 0x05 /* WD */
|
#define BA_LOCAL_PREF 0x05 /* WD */
|
||||||
#define BA_ATOMIC_AGGR 0x06 /* WD */
|
#define BA_ATOMIC_AGGR 0x06 /* WD */
|
||||||
#define BA_AGGREGATOR 0x07 /* OT */
|
#define BA_AGGREGATOR 0x07 /* OT */
|
||||||
#define BA_COMMUNITY 0x08 /* [RFC1997] */ /* OT */
|
#define BA_COMMUNITY 0x08 /* RFC 1997 */ /* OT */
|
||||||
#define BA_ORIGINATOR_ID 0x09 /* [RFC1966] */ /* ON */
|
#define BA_ORIGINATOR_ID 0x09 /* RFC 4456 */ /* ON */
|
||||||
#define BA_CLUSTER_LIST 0x0a /* ON */
|
#define BA_CLUSTER_LIST 0x0a /* RFC 4456 */ /* ON */
|
||||||
/* We don't support these: */
|
#define BA_MP_REACH_NLRI 0x0e /* RFC 4760 */
|
||||||
#define BA_DPA 0x0b /* ??? */
|
#define BA_MP_UNREACH_NLRI 0x0f /* RFC 4760 */
|
||||||
#define BA_ADVERTISER 0x0c /* [RFC1863] */
|
|
||||||
#define BA_RCID_PATH 0x0d
|
|
||||||
#define BA_MP_REACH_NLRI 0x0e /* [RFC2283] */
|
|
||||||
#define BA_MP_UNREACH_NLRI 0x0f
|
|
||||||
#define BA_EXT_COMMUNITY 0x10 /* RFC 4360 */
|
#define BA_EXT_COMMUNITY 0x10 /* RFC 4360 */
|
||||||
#define BA_AS4_PATH 0x11 /* RFC 6793 */
|
#define BA_AS4_PATH 0x11 /* RFC 6793 */
|
||||||
#define BA_AS4_AGGREGATOR 0x12 /* RFC 6793 */
|
#define BA_AS4_AGGREGATOR 0x12 /* RFC 6793 */
|
||||||
#define BA_LARGE_COMMUNITY 0x20 /* [draft-ietf-idr-large-community] */
|
#define BA_LARGE_COMMUNITY 0x20 /* RFC 8092 */
|
||||||
|
|
||||||
/* BGP connection states */
|
/* BGP connection states */
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
|
||||||
BGP_CLUSTER_LIST, IGP, TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL,
|
BGP_CLUSTER_LIST, IGP, TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL,
|
||||||
SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX,
|
SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX,
|
||||||
GRACEFUL, RESTART, AWARE, CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY,
|
GRACEFUL, RESTART, AWARE, CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY,
|
||||||
STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST)
|
STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST, FLOW4, FLOW6)
|
||||||
|
|
||||||
%type <i32> bgp_afi
|
%type <i32> bgp_afi
|
||||||
|
|
||||||
|
@ -139,6 +139,8 @@ bgp_afi:
|
||||||
| IPV6 { $$ = BGP_AF_IPV6; }
|
| IPV6 { $$ = BGP_AF_IPV6; }
|
||||||
| IPV4 MULTICAST { $$ = BGP_AF_IPV4_MC; }
|
| IPV4 MULTICAST { $$ = BGP_AF_IPV4_MC; }
|
||||||
| IPV6 MULTICAST { $$ = BGP_AF_IPV6_MC; }
|
| IPV6 MULTICAST { $$ = BGP_AF_IPV6_MC; }
|
||||||
|
| FLOW4 { $$ = BGP_AF_FLOW4; }
|
||||||
|
| FLOW6 { $$ = BGP_AF_FLOW6; }
|
||||||
;
|
;
|
||||||
|
|
||||||
bgp_channel_start: bgp_afi
|
bgp_channel_start: bgp_afi
|
||||||
|
@ -150,6 +152,7 @@ bgp_channel_start: bgp_afi
|
||||||
|
|
||||||
this_channel = channel_config_new(&channel_bgp, desc->net, this_proto);
|
this_channel = channel_config_new(&channel_bgp, desc->net, this_proto);
|
||||||
BGP_CC->c.name = desc->name;
|
BGP_CC->c.name = desc->name;
|
||||||
|
BGP_CC->c.ra_mode = RA_UNDEF;
|
||||||
BGP_CC->afi = $1;
|
BGP_CC->afi = $1;
|
||||||
BGP_CC->gr_able = 0xff; /* undefined */
|
BGP_CC->gr_able = 0xff; /* undefined */
|
||||||
};
|
};
|
||||||
|
@ -166,6 +169,7 @@ bgp_channel_item:
|
||||||
| GATEWAY RECURSIVE { BGP_CC->gw_mode = GW_RECURSIVE; }
|
| GATEWAY RECURSIVE { BGP_CC->gw_mode = GW_RECURSIVE; }
|
||||||
| SECONDARY bool { BGP_CC->secondary = $2; }
|
| SECONDARY bool { BGP_CC->secondary = $2; }
|
||||||
| GRACEFUL RESTART bool { BGP_CC->gr_able = $3; }
|
| GRACEFUL RESTART bool { BGP_CC->gr_able = $3; }
|
||||||
|
| EXTENDED NEXT HOP bool { BGP_CC->ext_next_hop = $4; }
|
||||||
| ADD PATHS RX { BGP_CC->add_path = BGP_ADD_PATH_RX; }
|
| ADD PATHS RX { BGP_CC->add_path = BGP_ADD_PATH_RX; }
|
||||||
| ADD PATHS TX { BGP_CC->add_path = BGP_ADD_PATH_TX; }
|
| ADD PATHS TX { BGP_CC->add_path = BGP_ADD_PATH_TX; }
|
||||||
| ADD PATHS bool { BGP_CC->add_path = $3 ? BGP_ADD_PATH_FULL : 0; }
|
| ADD PATHS bool { BGP_CC->add_path = $3 ? BGP_ADD_PATH_FULL : 0; }
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "nest/mrtdump.h"
|
#include "nest/mrtdump.h"
|
||||||
#include "conf/conf.h"
|
#include "conf/conf.h"
|
||||||
#include "lib/unaligned.h"
|
#include "lib/unaligned.h"
|
||||||
|
#include "lib/flowspec.h"
|
||||||
#include "lib/socket.h"
|
#include "lib/socket.h"
|
||||||
|
|
||||||
#include "nest/cli.h"
|
#include "nest/cli.h"
|
||||||
|
@ -184,9 +185,6 @@ bgp_create_notification(struct bgp_conn *conn, byte *buf)
|
||||||
|
|
||||||
/* Capability negotiation as per RFC 5492 */
|
/* Capability negotiation as per RFC 5492 */
|
||||||
|
|
||||||
#define WALK_AF_CAPS(caps,ac) \
|
|
||||||
for (ac = caps->af_data; ac < &caps->af_data[caps->af_count]; ac++)
|
|
||||||
|
|
||||||
const struct bgp_af_caps *
|
const struct bgp_af_caps *
|
||||||
bgp_find_af_caps(struct bgp_caps *caps, u32 afi)
|
bgp_find_af_caps(struct bgp_caps *caps, u32 afi)
|
||||||
{
|
{
|
||||||
|
@ -230,6 +228,7 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf)
|
||||||
struct bgp_channel *c;
|
struct bgp_channel *c;
|
||||||
struct bgp_caps *caps;
|
struct bgp_caps *caps;
|
||||||
struct bgp_af_caps *ac;
|
struct bgp_af_caps *ac;
|
||||||
|
uint any_ext_next_hop = 0;
|
||||||
uint any_add_path = 0;
|
uint any_add_path = 0;
|
||||||
byte *data;
|
byte *data;
|
||||||
|
|
||||||
|
@ -261,6 +260,9 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf)
|
||||||
ac->afi = c->afi;
|
ac->afi = c->afi;
|
||||||
ac->ready = 1;
|
ac->ready = 1;
|
||||||
|
|
||||||
|
ac->ext_next_hop = bgp_channel_is_ipv4(c) && c->cf->ext_next_hop;
|
||||||
|
any_ext_next_hop |= ac->ext_next_hop;
|
||||||
|
|
||||||
ac->add_path = c->cf->add_path;
|
ac->add_path = c->cf->add_path;
|
||||||
any_add_path |= ac->add_path;
|
any_add_path |= ac->add_path;
|
||||||
|
|
||||||
|
@ -279,6 +281,12 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf)
|
||||||
|
|
||||||
/* Create capability list in buffer */
|
/* Create capability list in buffer */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that max length is ~ 20+14*af_count. With max 6 channels that is
|
||||||
|
* 104. Option limit is 253 and buffer size is 4096, so we cannot overflow
|
||||||
|
* unless we add new capabilities or more AFs.
|
||||||
|
*/
|
||||||
|
|
||||||
WALK_AF_CAPS(caps, ac)
|
WALK_AF_CAPS(caps, ac)
|
||||||
if (ac->ready)
|
if (ac->ready)
|
||||||
{
|
{
|
||||||
|
@ -294,6 +302,23 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf)
|
||||||
*buf++ = 0; /* Capability data length */
|
*buf++ = 0; /* Capability data length */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (any_ext_next_hop)
|
||||||
|
{
|
||||||
|
*buf++ = 5; /* Capability 5: Support for extended next hop */
|
||||||
|
*buf++ = 0; /* Capability data length, will be fixed later */
|
||||||
|
data = buf;
|
||||||
|
|
||||||
|
WALK_AF_CAPS(caps, ac)
|
||||||
|
if (ac->ext_next_hop)
|
||||||
|
{
|
||||||
|
put_af4(buf, ac->afi);
|
||||||
|
put_u16(buf+4, BGP_AFI_IPV6);
|
||||||
|
buf += 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
data[-1] = buf - data;
|
||||||
|
}
|
||||||
|
|
||||||
if (caps->ext_messages)
|
if (caps->ext_messages)
|
||||||
{
|
{
|
||||||
*buf++ = 6; /* Capability 6: Support for extended messages */
|
*buf++ = 6; /* Capability 6: Support for extended messages */
|
||||||
|
@ -352,8 +377,6 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf)
|
||||||
*buf++ = 0; /* Capability data length */
|
*buf++ = 0; /* Capability data length */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: Should not XXXX 255 */
|
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,6 +415,23 @@ bgp_read_capabilities(struct bgp_conn *conn, struct bgp_caps *caps, byte *pos, i
|
||||||
caps->route_refresh = 1;
|
caps->route_refresh = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 5: /* Extended next hop encoding capability, RFC 5549 */
|
||||||
|
if (cl % 6)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
for (i = 0; i < cl; i += 6)
|
||||||
|
{
|
||||||
|
/* Specified only for IPv4 prefixes with IPv6 next hops */
|
||||||
|
if ((get_u16(pos+2+i+0) != BGP_AFI_IPV4) ||
|
||||||
|
(get_u16(pos+2+i+4) != BGP_AFI_IPV6))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
af = get_af4(pos+2+i);
|
||||||
|
ac = bgp_get_af_caps(caps, af);
|
||||||
|
ac->ext_next_hop = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 6: /* Extended message length capability, RFC draft */
|
case 6: /* Extended message length capability, RFC draft */
|
||||||
if (cl != 0)
|
if (cl != 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -673,9 +713,13 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
|
||||||
#define REPORT(msg, args...) \
|
#define REPORT(msg, args...) \
|
||||||
({ log(L_REMOTE "%s: " msg, s->proto->p.name, ## args); })
|
({ log(L_REMOTE "%s: " msg, s->proto->p.name, ## args); })
|
||||||
|
|
||||||
|
#define DISCARD(msg, args...) \
|
||||||
|
({ REPORT(msg, ## args); return; })
|
||||||
|
|
||||||
#define WITHDRAW(msg, args...) \
|
#define WITHDRAW(msg, args...) \
|
||||||
({ REPORT(msg, ## args); s->err_withdraw = 1; return; })
|
({ REPORT(msg, ## args); s->err_withdraw = 1; return; })
|
||||||
|
|
||||||
|
#define BAD_AFI "Unexpected AF <%u/%u> in UPDATE"
|
||||||
#define BAD_NEXT_HOP "Invalid NEXT_HOP attribute"
|
#define BAD_NEXT_HOP "Invalid NEXT_HOP attribute"
|
||||||
#define NO_NEXT_HOP "Missing NEXT_HOP attribute"
|
#define NO_NEXT_HOP "Missing NEXT_HOP attribute"
|
||||||
|
|
||||||
|
@ -792,6 +836,32 @@ bgp_update_next_hop_ip(struct bgp_export_state *s, eattr *a, ea_list **to)
|
||||||
WITHDRAW(BAD_NEXT_HOP);
|
WITHDRAW(BAD_NEXT_HOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint
|
||||||
|
bgp_encode_next_hop_none(struct bgp_write_state *s UNUSED, eattr *a UNUSED, byte *buf UNUSED, uint size UNUSED)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bgp_decode_next_hop_none(struct bgp_parse_state *s UNUSED, byte *data UNUSED, uint len UNUSED, rta *a UNUSED)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Although we expect no next hop and RFC 7606 7.11 states that attribute
|
||||||
|
* MP_REACH_NLRI with unexpected next hop length is considered malformed,
|
||||||
|
* FlowSpec RFC 5575 4 states that next hop shall be ignored on receipt.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bgp_update_next_hop_none(struct bgp_export_state *s, eattr *a, ea_list **to)
|
||||||
|
{
|
||||||
|
/* NEXT_HOP shall not pass */
|
||||||
|
if (a)
|
||||||
|
bgp_unset_attr(to, s->pool, BA_NEXT_HOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* UPDATE
|
* UPDATE
|
||||||
|
@ -1065,6 +1135,190 @@ bgp_decode_next_hop_ip6(struct bgp_parse_state *s, byte *data, uint len, rta *a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint
|
||||||
|
bgp_encode_nlri_flow4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *buf, uint size)
|
||||||
|
{
|
||||||
|
byte *pos = buf;
|
||||||
|
|
||||||
|
while (!EMPTY_LIST(buck->prefixes) && (size >= 4))
|
||||||
|
{
|
||||||
|
struct bgp_prefix *px = HEAD(buck->prefixes);
|
||||||
|
struct net_addr_flow4 *net = (void *) px->net;
|
||||||
|
uint flen = net->length - sizeof(net_addr_flow4);
|
||||||
|
|
||||||
|
/* Encode path ID */
|
||||||
|
if (s->add_path)
|
||||||
|
{
|
||||||
|
put_u32(pos, px->path_id);
|
||||||
|
ADVANCE(pos, size, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flen > size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Copy whole flow data including length */
|
||||||
|
memcpy(pos, net->data, flen);
|
||||||
|
ADVANCE(pos, size, flen);
|
||||||
|
|
||||||
|
bgp_free_prefix(s->channel, px);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos - buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bgp_decode_nlri_flow4(struct bgp_parse_state *s, byte *pos, uint len, rta *a)
|
||||||
|
{
|
||||||
|
while (len)
|
||||||
|
{
|
||||||
|
u32 path_id = 0;
|
||||||
|
|
||||||
|
/* Decode path ID */
|
||||||
|
if (s->add_path)
|
||||||
|
{
|
||||||
|
if (len < 4)
|
||||||
|
bgp_parse_error(s, 1);
|
||||||
|
|
||||||
|
path_id = get_u32(pos);
|
||||||
|
ADVANCE(pos, len, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < 2)
|
||||||
|
bgp_parse_error(s, 1);
|
||||||
|
|
||||||
|
/* Decode flow length */
|
||||||
|
uint hlen = flow_hdr_length(pos);
|
||||||
|
uint dlen = flow_read_length(pos);
|
||||||
|
uint flen = hlen + dlen;
|
||||||
|
byte *data = pos + hlen;
|
||||||
|
|
||||||
|
if (len < flen)
|
||||||
|
bgp_parse_error(s, 1);
|
||||||
|
|
||||||
|
/* Validate flow data */
|
||||||
|
enum flow_validated_state r = flow4_validate(data, dlen);
|
||||||
|
if (r != FLOW_ST_VALID)
|
||||||
|
{
|
||||||
|
log(L_REMOTE "%s: Invalid flow route: %s", s->proto->p.name, flow_validated_state_str(r));
|
||||||
|
bgp_parse_error(s, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[0] != FLOW_TYPE_DST_PREFIX)
|
||||||
|
{
|
||||||
|
log(L_REMOTE "%s: No dst prefix at first pos", s->proto->p.name);
|
||||||
|
bgp_parse_error(s, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode dst prefix */
|
||||||
|
ip4_addr px = IP4_NONE;
|
||||||
|
uint pxlen = data[1];
|
||||||
|
|
||||||
|
// FIXME: Use some generic function
|
||||||
|
memcpy(&px, data, BYTES(pxlen));
|
||||||
|
px = ip4_and(px, ip4_mkmask(pxlen));
|
||||||
|
|
||||||
|
/* Prepare the flow */
|
||||||
|
net_addr *n = alloca(sizeof(struct net_addr_flow4) + flen);
|
||||||
|
net_fill_flow4(n, px, pxlen, pos, flen);
|
||||||
|
ADVANCE(pos, len, flen);
|
||||||
|
|
||||||
|
bgp_rte_update(s, n, path_id, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint
|
||||||
|
bgp_encode_nlri_flow6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *buf, uint size)
|
||||||
|
{
|
||||||
|
byte *pos = buf;
|
||||||
|
|
||||||
|
while (!EMPTY_LIST(buck->prefixes) && (size >= 4))
|
||||||
|
{
|
||||||
|
struct bgp_prefix *px = HEAD(buck->prefixes);
|
||||||
|
struct net_addr_flow6 *net = (void *) px->net;
|
||||||
|
uint flen = net->length - sizeof(net_addr_flow6);
|
||||||
|
|
||||||
|
/* Encode path ID */
|
||||||
|
if (s->add_path)
|
||||||
|
{
|
||||||
|
put_u32(pos, px->path_id);
|
||||||
|
ADVANCE(pos, size, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flen > size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Copy whole flow data including length */
|
||||||
|
memcpy(pos, net->data, flen);
|
||||||
|
ADVANCE(pos, size, flen);
|
||||||
|
|
||||||
|
bgp_free_prefix(s->channel, px);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos - buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bgp_decode_nlri_flow6(struct bgp_parse_state *s, byte *pos, uint len, rta *a)
|
||||||
|
{
|
||||||
|
while (len)
|
||||||
|
{
|
||||||
|
u32 path_id = 0;
|
||||||
|
|
||||||
|
/* Decode path ID */
|
||||||
|
if (s->add_path)
|
||||||
|
{
|
||||||
|
if (len < 4)
|
||||||
|
bgp_parse_error(s, 1);
|
||||||
|
|
||||||
|
path_id = get_u32(pos);
|
||||||
|
ADVANCE(pos, len, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < 2)
|
||||||
|
bgp_parse_error(s, 1);
|
||||||
|
|
||||||
|
/* Decode flow length */
|
||||||
|
uint hlen = flow_hdr_length(pos);
|
||||||
|
uint dlen = flow_read_length(pos);
|
||||||
|
uint flen = hlen + dlen;
|
||||||
|
byte *data = pos + hlen;
|
||||||
|
|
||||||
|
if (len < flen)
|
||||||
|
bgp_parse_error(s, 1);
|
||||||
|
|
||||||
|
/* Validate flow data */
|
||||||
|
enum flow_validated_state r = flow6_validate(data, dlen);
|
||||||
|
if (r != FLOW_ST_VALID)
|
||||||
|
{
|
||||||
|
log(L_REMOTE "%s: Invalid flow route: %s", s->proto->p.name, flow_validated_state_str(r));
|
||||||
|
bgp_parse_error(s, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[0] != FLOW_TYPE_DST_PREFIX)
|
||||||
|
{
|
||||||
|
log(L_REMOTE "%s: No dst prefix at first pos", s->proto->p.name);
|
||||||
|
bgp_parse_error(s, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode dst prefix */
|
||||||
|
ip6_addr px = IP6_NONE;
|
||||||
|
uint pxlen = data[1];
|
||||||
|
|
||||||
|
// FIXME: Use some generic function
|
||||||
|
memcpy(&px, data, BYTES(pxlen));
|
||||||
|
px = ip6_and(px, ip6_mkmask(pxlen));
|
||||||
|
|
||||||
|
/* Prepare the flow */
|
||||||
|
net_addr *n = alloca(sizeof(struct net_addr_flow6) + flen);
|
||||||
|
net_fill_flow6(n, px, pxlen, pos, flen);
|
||||||
|
ADVANCE(pos, len, flen);
|
||||||
|
|
||||||
|
bgp_rte_update(s, n, path_id, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const struct bgp_af_desc bgp_af_table[] = {
|
static const struct bgp_af_desc bgp_af_table[] = {
|
||||||
{
|
{
|
||||||
.afi = BGP_AF_IPV4,
|
.afi = BGP_AF_IPV4,
|
||||||
|
@ -1086,6 +1340,16 @@ static const struct bgp_af_desc bgp_af_table[] = {
|
||||||
.decode_next_hop = bgp_decode_next_hop_ip4,
|
.decode_next_hop = bgp_decode_next_hop_ip4,
|
||||||
.update_next_hop = bgp_update_next_hop_ip,
|
.update_next_hop = bgp_update_next_hop_ip,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.afi = BGP_AF_FLOW4,
|
||||||
|
.net = NET_FLOW4,
|
||||||
|
.name = "flow4",
|
||||||
|
.encode_nlri = bgp_encode_nlri_flow4,
|
||||||
|
.decode_nlri = bgp_decode_nlri_flow4,
|
||||||
|
.encode_next_hop = bgp_encode_next_hop_none,
|
||||||
|
.decode_next_hop = bgp_decode_next_hop_none,
|
||||||
|
.update_next_hop = bgp_update_next_hop_none,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.afi = BGP_AF_IPV6,
|
.afi = BGP_AF_IPV6,
|
||||||
.net = NET_IP6,
|
.net = NET_IP6,
|
||||||
|
@ -1106,6 +1370,16 @@ static const struct bgp_af_desc bgp_af_table[] = {
|
||||||
.decode_next_hop = bgp_decode_next_hop_ip6,
|
.decode_next_hop = bgp_decode_next_hop_ip6,
|
||||||
.update_next_hop = bgp_update_next_hop_ip,
|
.update_next_hop = bgp_update_next_hop_ip,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.afi = BGP_AF_FLOW6,
|
||||||
|
.net = NET_FLOW6,
|
||||||
|
.name = "flow6",
|
||||||
|
.encode_nlri = bgp_encode_nlri_flow6,
|
||||||
|
.decode_nlri = bgp_decode_nlri_flow6,
|
||||||
|
.encode_next_hop = bgp_encode_next_hop_none,
|
||||||
|
.decode_next_hop = bgp_decode_next_hop_none,
|
||||||
|
.update_next_hop = bgp_update_next_hop_none,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct bgp_af_desc *
|
const struct bgp_af_desc *
|
||||||
|
@ -1387,15 +1661,15 @@ bgp_create_end_mark(struct bgp_channel *c, byte *buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
bgp_rx_end_mark(struct bgp_proto *p, u32 afi)
|
bgp_rx_end_mark(struct bgp_parse_state *s, u32 afi)
|
||||||
{
|
{
|
||||||
|
struct bgp_proto *p = s->proto;
|
||||||
struct bgp_channel *c = bgp_get_channel(p, afi);
|
struct bgp_channel *c = bgp_get_channel(p, afi);
|
||||||
|
|
||||||
BGP_TRACE(D_PACKETS, "Got END-OF-RIB");
|
BGP_TRACE(D_PACKETS, "Got END-OF-RIB");
|
||||||
|
|
||||||
/* XXXX handle unknown AF in MP_*_NLRI */
|
|
||||||
if (!c)
|
if (!c)
|
||||||
return;
|
DISCARD(BAD_AFI, BGP_AFI(afi), BGP_SAFI(afi));
|
||||||
|
|
||||||
if (c->load_state == BFS_LOADING)
|
if (c->load_state == BFS_LOADING)
|
||||||
c->load_state = BFS_NONE;
|
c->load_state = BFS_NONE;
|
||||||
|
@ -1413,9 +1687,8 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis
|
||||||
struct bgp_channel *c = bgp_get_channel(s->proto, afi);
|
struct bgp_channel *c = bgp_get_channel(s->proto, afi);
|
||||||
rta *a = NULL;
|
rta *a = NULL;
|
||||||
|
|
||||||
/* XXXX handle unknown AF in MP_*_NLRI */
|
|
||||||
if (!c)
|
if (!c)
|
||||||
return;
|
DISCARD(BAD_AFI, BGP_AFI(afi), BGP_SAFI(afi));
|
||||||
|
|
||||||
s->channel = c;
|
s->channel = c;
|
||||||
s->add_path = c->add_path_rx;
|
s->add_path = c->add_path_rx;
|
||||||
|
@ -1523,12 +1796,12 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len)
|
||||||
|
|
||||||
/* Check for End-of-RIB marker */
|
/* Check for End-of-RIB marker */
|
||||||
if (!s.attr_len && !s.ip_unreach_len && !s.ip_reach_len)
|
if (!s.attr_len && !s.ip_unreach_len && !s.ip_reach_len)
|
||||||
{ bgp_rx_end_mark(p, BGP_AF_IPV4); goto done; }
|
{ bgp_rx_end_mark(&s, BGP_AF_IPV4); goto done; }
|
||||||
|
|
||||||
/* Check for MP End-of-RIB marker */
|
/* Check for MP End-of-RIB marker */
|
||||||
if ((s.attr_len < 8) && !s.ip_unreach_len && !s.ip_reach_len &&
|
if ((s.attr_len < 8) && !s.ip_unreach_len && !s.ip_reach_len &&
|
||||||
!s.mp_reach_len && !s.mp_unreach_len && s.mp_unreach_af) /* XXXX See RFC 7606 5.2 */
|
!s.mp_reach_len && !s.mp_unreach_len && s.mp_unreach_af)
|
||||||
{ bgp_rx_end_mark(p, s.mp_unreach_af); goto done; }
|
{ bgp_rx_end_mark(&s, s.mp_unreach_af); goto done; }
|
||||||
|
|
||||||
if (s.ip_unreach_len)
|
if (s.ip_unreach_len)
|
||||||
bgp_decode_nlri(&s, BGP_AF_IPV4, s.ip_unreach_nlri, s.ip_unreach_len, NULL, NULL, 0);
|
bgp_decode_nlri(&s, BGP_AF_IPV4, s.ip_unreach_nlri, s.ip_unreach_len, NULL, NULL, 0);
|
||||||
|
|
|
@ -421,10 +421,9 @@ add_network(struct ospf_area *oa, net_addr *net, int metric, struct top_hash_ent
|
||||||
if (en == oa->rt)
|
if (en == oa->rt)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Local stub networks does not have proper iface in en->nhi
|
* Local stub networks do not have proper iface in en->nhi (because they all
|
||||||
* (because they all have common top_hash_entry en).
|
* have common top_hash_entry en). We have to find iface responsible for
|
||||||
* We have to find iface responsible for that stub network.
|
* that stub network. Configured stubnets do not have any iface. They will
|
||||||
* Configured stubnets does not have any iface. They will
|
|
||||||
* be removed in rt_sync().
|
* be removed in rt_sync().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -1428,7 +1427,6 @@ ospf_ext_spf(struct ospf_proto *p)
|
||||||
struct top_hash_entry *en;
|
struct top_hash_entry *en;
|
||||||
struct ospf_lsa_ext_local rt;
|
struct ospf_lsa_ext_local rt;
|
||||||
ort *nf1, *nf2;
|
ort *nf1, *nf2;
|
||||||
orta nfa = {};
|
|
||||||
u32 br_metric;
|
u32 br_metric;
|
||||||
struct ospf_area *atmp;
|
struct ospf_area *atmp;
|
||||||
|
|
||||||
|
@ -1436,6 +1434,8 @@ ospf_ext_spf(struct ospf_proto *p)
|
||||||
|
|
||||||
WALK_SLIST(en, p->lsal)
|
WALK_SLIST(en, p->lsal)
|
||||||
{
|
{
|
||||||
|
orta nfa = {};
|
||||||
|
|
||||||
/* 16.4. (1) */
|
/* 16.4. (1) */
|
||||||
if ((en->lsa_type != LSA_T_EXT) && (en->lsa_type != LSA_T_NSSA))
|
if ((en->lsa_type != LSA_T_EXT) && (en->lsa_type != LSA_T_NSSA))
|
||||||
continue;
|
continue;
|
||||||
|
@ -1577,6 +1577,7 @@ ospf_rt_reset(struct ospf_proto *p)
|
||||||
FIB_WALK(&p->rtf, ort, ri)
|
FIB_WALK(&p->rtf, ort, ri)
|
||||||
{
|
{
|
||||||
ri->area_net = 0;
|
ri->area_net = 0;
|
||||||
|
ri->keep = 0;
|
||||||
reset_ri(ri);
|
reset_ri(ri);
|
||||||
}
|
}
|
||||||
FIB_WALK_END;
|
FIB_WALK_END;
|
||||||
|
@ -1939,9 +1940,12 @@ again1:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove configured stubnets */
|
/* Remove configured stubnets but keep the entries */
|
||||||
if (!nf->n.nhs)
|
if (nf->n.type && !nf->n.nhs)
|
||||||
|
{
|
||||||
reset_ri(nf);
|
reset_ri(nf);
|
||||||
|
nf->keep = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (nf->n.type) /* Add the route */
|
if (nf->n.type) /* Add the route */
|
||||||
{
|
{
|
||||||
|
@ -1981,7 +1985,7 @@ again1:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove unused rt entry, some special entries are persistent */
|
/* Remove unused rt entry, some special entries are persistent */
|
||||||
if (!nf->n.type && !nf->external_rte && !nf->area_net)
|
if (!nf->n.type && !nf->external_rte && !nf->area_net && !nf->keep)
|
||||||
{
|
{
|
||||||
if (nf->lsa_id)
|
if (nf->lsa_id)
|
||||||
idm_free(&p->idm, nf->lsa_id);
|
idm_free(&p->idm, nf->lsa_id);
|
||||||
|
|
|
@ -84,6 +84,7 @@ typedef struct ort
|
||||||
u32 lsa_id;
|
u32 lsa_id;
|
||||||
u8 external_rte;
|
u8 external_rte;
|
||||||
u8 area_net;
|
u8 area_net;
|
||||||
|
u8 keep;
|
||||||
|
|
||||||
struct fib_node fn;
|
struct fib_node fn;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,3 +2,5 @@ src := rpki.c packets.c tcp_transport.c ssh_transport.c transport.c
|
||||||
obj := $(src-o-files)
|
obj := $(src-o-files)
|
||||||
$(all-daemon)
|
$(all-daemon)
|
||||||
$(cf-local)
|
$(cf-local)
|
||||||
|
|
||||||
|
tests_objs := $(tests_objs) $(src-o-files)
|
|
@ -531,8 +531,6 @@ rpki_send_pdu(struct rpki_cache *cache, const void *pdu, const uint len)
|
||||||
static int
|
static int
|
||||||
rpki_check_receive_packet(struct rpki_cache *cache, const struct pdu_header *pdu)
|
rpki_check_receive_packet(struct rpki_cache *cache, const struct pdu_header *pdu)
|
||||||
{
|
{
|
||||||
struct rpki_proto *p = cache->p;
|
|
||||||
int error = RPKI_SUCCESS;
|
|
||||||
u32 pdu_len = ntohl(pdu->len);
|
u32 pdu_len = ntohl(pdu->len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -557,7 +555,6 @@ rpki_check_receive_packet(struct rpki_cache *cache, const struct pdu_header *pdu
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
else if (cache->last_update == 0
|
else if (cache->last_update == 0
|
||||||
&& pdu->ver >= RPKI_MIN_VERSION
|
|
||||||
&& pdu->ver <= RPKI_MAX_VERSION
|
&& pdu->ver <= RPKI_MAX_VERSION
|
||||||
&& pdu->ver < cache->version)
|
&& pdu->ver < cache->version)
|
||||||
{
|
{
|
||||||
|
@ -608,7 +605,6 @@ rpki_handle_error_pdu(struct rpki_cache *cache, const struct pdu_error *pdu)
|
||||||
case UNSUPPORTED_PROTOCOL_VER:
|
case UNSUPPORTED_PROTOCOL_VER:
|
||||||
CACHE_TRACE(D_PACKETS, cache, "Client uses unsupported protocol version");
|
CACHE_TRACE(D_PACKETS, cache, "Client uses unsupported protocol version");
|
||||||
if (pdu->ver <= RPKI_MAX_VERSION &&
|
if (pdu->ver <= RPKI_MAX_VERSION &&
|
||||||
pdu->ver >= RPKI_MIN_VERSION &&
|
|
||||||
pdu->ver < cache->version)
|
pdu->ver < cache->version)
|
||||||
{
|
{
|
||||||
CACHE_TRACE(D_EVENTS, cache, "Downgrading from protocol version %d to version %d", cache->version, pdu->ver);
|
CACHE_TRACE(D_EVENTS, cache, "Downgrading from protocol version %d to version %d", cache->version, pdu->ver);
|
||||||
|
|
|
@ -357,7 +357,7 @@ rpki_stop_retry_timer_event(struct rpki_cache *cache)
|
||||||
tm_stop(cache->retry_timer);
|
tm_stop(cache->retry_timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void UNUSED
|
||||||
rpki_stop_expire_timer_event(struct rpki_cache *cache)
|
rpki_stop_expire_timer_event(struct rpki_cache *cache)
|
||||||
{
|
{
|
||||||
CACHE_DBG(cache, "Stop");
|
CACHE_DBG(cache, "Stop");
|
||||||
|
@ -636,7 +636,7 @@ rpki_shutdown(struct proto *P)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
rpki_try_fast_reconnect(struct rpki_cache *cache, struct rpki_config *new, struct rpki_config *old)
|
rpki_try_fast_reconnect(struct rpki_cache *cache)
|
||||||
{
|
{
|
||||||
if (cache->state == RPKI_CS_ESTABLISHED)
|
if (cache->state == RPKI_CS_ESTABLISHED)
|
||||||
{
|
{
|
||||||
|
@ -660,11 +660,10 @@ rpki_try_fast_reconnect(struct rpki_cache *cache, struct rpki_config *new, struc
|
||||||
* protocol. Returns |NEED_TO_RESTART| or |SUCCESSFUL_RECONF|.
|
* protocol. Returns |NEED_TO_RESTART| or |SUCCESSFUL_RECONF|.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
rpki_reconfigure_cache(struct rpki_proto *p, struct rpki_cache *cache, struct rpki_config *new, struct rpki_config *old)
|
rpki_reconfigure_cache(struct rpki_proto *p UNUSED, struct rpki_cache *cache, struct rpki_config *new, struct rpki_config *old)
|
||||||
{
|
{
|
||||||
u8 try_fast_reconnect = 0;
|
u8 try_fast_reconnect = 0;
|
||||||
|
|
||||||
|
|
||||||
if (strcmp(old->hostname, new->hostname) != 0)
|
if (strcmp(old->hostname, new->hostname) != 0)
|
||||||
{
|
{
|
||||||
CACHE_TRACE(D_EVENTS, cache, "Cache server address changed to %s", new->hostname);
|
CACHE_TRACE(D_EVENTS, cache, "Cache server address changed to %s", new->hostname);
|
||||||
|
@ -709,7 +708,7 @@ rpki_reconfigure_cache(struct rpki_proto *p, struct rpki_cache *cache, struct rp
|
||||||
#undef TEST_INTERVAL
|
#undef TEST_INTERVAL
|
||||||
|
|
||||||
if (try_fast_reconnect)
|
if (try_fast_reconnect)
|
||||||
return rpki_try_fast_reconnect(cache, new, old);
|
return rpki_try_fast_reconnect(cache);
|
||||||
|
|
||||||
return SUCCESSFUL_RECONF;
|
return SUCCESSFUL_RECONF;
|
||||||
}
|
}
|
||||||
|
@ -906,7 +905,7 @@ rpki_postconfig(struct proto_config *CF)
|
||||||
static void
|
static void
|
||||||
rpki_copy_config(struct proto_config *dest, struct proto_config *src)
|
rpki_copy_config(struct proto_config *dest, struct proto_config *src)
|
||||||
{
|
{
|
||||||
/* Just a shallow copy */
|
/* FIXME: Should copy transport */
|
||||||
}
|
}
|
||||||
|
|
||||||
struct protocol proto_rpki = {
|
struct protocol proto_rpki = {
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
|
|
||||||
#define RPKI_VERSION_0 0
|
#define RPKI_VERSION_0 0
|
||||||
#define RPKI_VERSION_1 1
|
#define RPKI_VERSION_1 1
|
||||||
#define RPKI_MIN_VERSION RPKI_VERSION_0
|
|
||||||
#define RPKI_MAX_VERSION RPKI_VERSION_1
|
#define RPKI_MAX_VERSION RPKI_VERSION_1
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <net/if_dl.h>
|
#include <net/if_dl.h>
|
||||||
#include <netinet/in_systm.h> // Workaround for some BSDs
|
#include <netinet/in_systm.h> // Workaround for some BSDs
|
||||||
#include <netinet/ip.h>
|
#include <netinet/ip.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
|
||||||
#ifdef __NetBSD__
|
#ifdef __NetBSD__
|
||||||
|
@ -179,8 +180,8 @@ sk_prepare_ip_header(sock *s, void *hdr, int dlen)
|
||||||
ip->ip_src = ipa_to_in4(s->saddr);
|
ip->ip_src = ipa_to_in4(s->saddr);
|
||||||
ip->ip_dst = ipa_to_in4(s->daddr);
|
ip->ip_dst = ipa_to_in4(s->daddr);
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
#if (defined __OpenBSD__) || (defined __DragonFly__) || (defined __FreeBSD__ && (__FreeBSD_version >= 1100030))
|
||||||
/* OpenBSD expects ip_len in network order, other BSDs expect host order */
|
/* Different BSDs have different expectations of ip_len endianity */
|
||||||
ip->ip_len = htons(ip->ip_len);
|
ip->ip_len = htons(ip->ip_len);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#define _BIRD_CONFIG_H_
|
#define _BIRD_CONFIG_H_
|
||||||
|
|
||||||
/* BIRD version */
|
/* BIRD version */
|
||||||
#define BIRD_VERSION "1.6.2"
|
#define BIRD_VERSION "2.0.0-pre0"
|
||||||
|
|
||||||
/* Include parameters determined by configure script */
|
/* Include parameters determined by configure script */
|
||||||
#include "sysdep/autoconf.h"
|
#include "sysdep/autoconf.h"
|
||||||
|
|
|
@ -1809,6 +1809,7 @@ nl_async_hook(sock *sk, uint size UNUSED)
|
||||||
* One day we might react to it by asking for route table
|
* One day we might react to it by asking for route table
|
||||||
* scan in near future.
|
* scan in near future.
|
||||||
*/
|
*/
|
||||||
|
log(L_WARN "Kernel dropped some netlink messages, will resync on next scan.");
|
||||||
return 1; /* More data are likely to be ready */
|
return 1; /* More data are likely to be ready */
|
||||||
}
|
}
|
||||||
else if (errno != EWOULDBLOCK)
|
else if (errno != EWOULDBLOCK)
|
||||||
|
|
|
@ -2631,7 +2631,8 @@ io_loop(void)
|
||||||
if (pfd[s->index].revents & (POLLHUP | POLLERR))
|
if (pfd[s->index].revents & (POLLHUP | POLLERR))
|
||||||
{
|
{
|
||||||
sk_err(s, pfd[s->index].revents);
|
sk_err(s, pfd[s->index].revents);
|
||||||
goto next2;
|
if (s != current_sock)
|
||||||
|
goto next2;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_sock = sk_next(s);
|
current_sock = sk_next(s);
|
||||||
|
|
|
@ -200,7 +200,7 @@ bt_log_result(int result, const char *fmt, va_list argptr)
|
||||||
vsnprintf(pos, sizeof(msg_buf) - (pos - msg_buf), fmt, argptr);
|
vsnprintf(pos, sizeof(msg_buf) - (pos - msg_buf), fmt, argptr);
|
||||||
|
|
||||||
int chrs = 0;
|
int chrs = 0;
|
||||||
for (int i = 0; i < strlen(msg_buf); i += get_num_terminal_cols())
|
for (uint i = 0; i < strlen(msg_buf); i += get_num_terminal_cols())
|
||||||
{
|
{
|
||||||
if (i)
|
if (i)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
|
@ -8,10 +8,10 @@ set -e
|
||||||
AC=`if [ -x /usr/bin/autoconf2.50 ] ; then echo autoconf2.50 ; else echo autoconf ; fi`
|
AC=`if [ -x /usr/bin/autoconf2.50 ] ; then echo autoconf2.50 ; else echo autoconf ; fi`
|
||||||
$AC
|
$AC
|
||||||
./configure
|
./configure
|
||||||
|
make docs
|
||||||
make distclean
|
make distclean
|
||||||
$AC
|
$AC
|
||||||
rm -rf autom4te*cache
|
rm -rf autom4te*cache
|
||||||
( cd doc ; make docs ; make clean )
|
|
||||||
VERSION=`sed <sysdep/config.h '/BIRD_VERSION/!d;s/^.*"\(.*\)"$/\1/'`
|
VERSION=`sed <sysdep/config.h '/BIRD_VERSION/!d;s/^.*"\(.*\)"$/\1/'`
|
||||||
REL=bird-$VERSION
|
REL=bird-$VERSION
|
||||||
DREL=bird-doc-$VERSION
|
DREL=bird-doc-$VERSION
|
||||||
|
@ -23,9 +23,10 @@ cp -a . $T/$REL
|
||||||
echo Generating ChangeLog
|
echo Generating ChangeLog
|
||||||
git log >$T/$REL/ChangeLog
|
git log >$T/$REL/ChangeLog
|
||||||
mv $T/$REL/doc/*.ps $T/$DREL/doc
|
mv $T/$REL/doc/*.ps $T/$DREL/doc
|
||||||
|
mv $T/$REL/doc/*.pdf $T/$DREL/doc
|
||||||
rm -f $T/$REL/bird.conf*
|
rm -f $T/$REL/bird.conf*
|
||||||
rm -rf $T/$REL/.git/
|
rm -rf $T/$REL/.git/
|
||||||
rm -rf `find $T/$REL -name CVS -o -name tmp` $T/$REL/{misc,rfc,doc/slides}
|
rm -rf `find $T/$REL -name CVS -o -name tmp` $T/$REL/{misc,rfc,doc/slides,doc/slt2001,doc/old,doc/*.out}
|
||||||
( cd $T ; tar czvvf $REL.tar.gz $REL )
|
( cd $T ; tar czvvf $REL.tar.gz $REL )
|
||||||
( cd $T ; tar czvvf $DREL.tar.gz $DREL )
|
( cd $T ; tar czvvf $DREL.tar.gz $DREL )
|
||||||
rm -rf $T/$REL $T/$DREL
|
rm -rf $T/$REL $T/$DREL
|
||||||
|
|
Loading…
Reference in a new issue