Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
B
babeld
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
babeld
Commits
4a4d66da
Commit
4a4d66da
authored
Mar 16, 2015
by
Juliusz Chroboczek
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'ss-tables-merge'
parents
b68c481d
f074d209
Changes
28
Show whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
2049 additions
and
293 deletions
+2049
-293
Makefile
Makefile
+4
-2
babeld.c
babeld.c
+14
-7
babeld.h
babeld.h
+6
-0
babeld.man
babeld.man
+35
-0
configuration.c
configuration.c
+107
-15
configuration.h
configuration.h
+18
-4
disambiguation.c
disambiguation.c
+449
-0
disambiguation.h
disambiguation.h
+27
-0
interface.c
interface.c
+41
-31
interface.h
interface.h
+4
-1
kernel.c
kernel.c
+3
-0
kernel.h
kernel.h
+7
-0
kernel_netlink.c
kernel_netlink.c
+528
-26
kernel_socket.c
kernel_socket.c
+10
-4
local.c
local.c
+14
-9
message.c
message.c
+439
-91
message.h
message.h
+23
-5
neighbour.c
neighbour.c
+1
-1
resend.c
resend.c
+29
-12
resend.h
resend.h
+10
-3
route.c
route.c
+162
-64
route.h
route.h
+13
-2
source.c
source.c
+11
-3
source.h
source.h
+5
-1
util.c
util.c
+28
-0
util.h
util.h
+11
-0
xroute.c
xroute.c
+45
-11
xroute.h
xroute.h
+5
-1
No files found.
Makefile
View file @
4a4d66da
...
...
@@ -10,10 +10,12 @@ CFLAGS = $(CDEBUGFLAGS) $(DEFINES) $(EXTRA_DEFINES)
LDLIBS
=
-lrt
SRCS
=
babeld.c net.c kernel.c util.c interface.c source.c neighbour.c
\
route.c xroute.c message.c resend.c configuration.c local.c
route.c xroute.c message.c resend.c configuration.c local.c
\
disambiguation.c
OBJS
=
babeld.o net.o kernel.o util.o interface.o source.o neighbour.o
\
route.o xroute.o message.o resend.o configuration.o local.o
route.o xroute.o message.o resend.o configuration.o local.o
\
disambiguation.o
babeld
:
$(OBJS)
$(CC)
$(CFLAGS)
$(LDFLAGS)
-o
babeld
$(OBJS)
$(LDLIBS)
...
...
babeld.c
View file @
4a4d66da
...
...
@@ -82,6 +82,7 @@ unsigned char protocol_group[16];
int
protocol_socket
=
-
1
;
int
kernel_socket
=
-
1
;
static
int
kernel_routes_changed
=
0
;
static
int
kernel_rules_changed
=
0
;
static
int
kernel_link_changed
=
0
;
static
int
kernel_addr_changed
=
0
;
...
...
@@ -512,6 +513,7 @@ main(int argc, char **argv)
fprintf
(
stderr
,
"Warning: couldn't check exported routes.
\n
"
);
kernel_routes_changed
=
0
;
kernel_rules_changed
=
0
;
kernel_link_changed
=
0
;
kernel_addr_changed
=
0
;
kernel_dump_time
=
now
.
tv_sec
+
roughly
(
30
);
...
...
@@ -540,7 +542,7 @@ main(int argc, char **argv)
send_hello
(
ifp
);
send_wildcard_retraction
(
ifp
);
send_self_update
(
ifp
);
send_request
(
ifp
,
NULL
,
0
);
send_request
(
ifp
,
NULL
,
0
,
NULL
,
0
);
flushupdates
(
ifp
);
flushbuf
(
ifp
);
}
...
...
@@ -673,11 +675,12 @@ main(int argc, char **argv)
}
if
(
kernel_routes_changed
||
kernel_addr_changed
||
now
.
tv_sec
>=
kernel_dump_time
)
{
kernel_rules_changed
||
now
.
tv_sec
>=
kernel_dump_time
)
{
rc
=
check_xroutes
(
1
);
if
(
rc
<
0
)
fprintf
(
stderr
,
"Warning: couldn't check exported routes.
\n
"
);
kernel_routes_changed
=
kernel_addr_changed
=
0
;
kernel_routes_changed
=
kernel_rules_changed
=
kernel_addr_changed
=
0
;
if
(
kernel_socket
>=
0
)
kernel_dump_time
=
now
.
tv_sec
+
roughly
(
300
);
else
...
...
@@ -714,7 +717,7 @@ main(int argc, char **argv)
if
(
timeval_compare
(
&
now
,
&
ifp
->
hello_timeout
)
>=
0
)
send_hello
(
ifp
);
if
(
timeval_compare
(
&
now
,
&
ifp
->
update_timeout
)
>=
0
)
send_update
(
ifp
,
0
,
NULL
,
0
);
send_update
(
ifp
,
0
,
NULL
,
0
,
NULL
,
0
);
if
(
timeval_compare
(
&
now
,
&
ifp
->
update_flush_timeout
)
>=
0
)
flushupdates
(
ifp
);
}
...
...
@@ -1028,9 +1031,10 @@ dump_route(FILE *out, struct babel_route *route)
channels
[
0
]
=
'\0'
;
}
fprintf
(
out
,
"%s
metric %d (%d) refmetric %d id %s seqno %d%s age %d
"
"via %s neigh %s%s%s%s
\n
"
,
fprintf
(
out
,
"%s
from %s metric %d (%d) refmetric %d id %s
"
"
seqno %d%s age %d
via %s neigh %s%s%s%s
\n
"
,
format_prefix
(
route
->
src
->
prefix
,
route
->
src
->
plen
),
format_prefix
(
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
),
route_metric
(
route
),
route_smoothed_metric
(
route
),
route
->
refmetric
,
format_eui64
(
route
->
src
->
id
),
(
int
)
route
->
seqno
,
...
...
@@ -1047,8 +1051,9 @@ dump_route(FILE *out, struct babel_route *route)
static
void
dump_xroute
(
FILE
*
out
,
struct
xroute
*
xroute
)
{
fprintf
(
out
,
"%s metric %d (exported)
\n
"
,
fprintf
(
out
,
"%s
from %s
metric %d (exported)
\n
"
,
format_prefix
(
xroute
->
prefix
,
xroute
->
plen
),
format_prefix
(
xroute
->
src_prefix
,
xroute
->
src_plen
),
xroute
->
metric
);
}
...
...
@@ -1138,5 +1143,7 @@ kernel_routes_callback(int changed, void *closure)
kernel_addr_changed
=
1
;
if
(
changed
&
CHANGE_ROUTE
)
kernel_routes_changed
=
1
;
if
(
changed
&
CHANGE_RULE
)
kernel_rules_changed
=
1
;
return
1
;
}
babeld.h
View file @
4a4d66da
...
...
@@ -80,6 +80,12 @@ THE SOFTWARE.
#endif
#endif
#ifdef IPV6_SUBTREES
#define has_ipv6_subtrees 1
#else
#define has_ipv6_subtrees 0
#endif
extern
struct
timeval
now
;
extern
int
debug
;
extern
time_t
reboot_time
;
...
...
babeld.man
View file @
4a4d66da
...
...
@@ -260,6 +260,14 @@ This specifies the name of the file to which
.B babeld
writes out its process id, and is equivalent to the command-line option
.BR \-I .
.TP
.BI first-table-number " table"
This specifies the index of the first routing table to use for
source-specific routes. The default is 10.
.TP
.BI first-rule-priority " priority"
This specifies smallest (highest) rule priority used with source-specific
routes. The default is 100.
.SS Interface configuration
An interface is configured by a line with the following format:
.IP
...
...
@@ -410,6 +418,23 @@ This entry only applies to routes with a prefix length less or equal to
This entry only applies to routes with a prefix length greater or equal to
.BR plen .
.TP
.BI src-ip " prefix"
This entry only applies to routes with a source prefix in the given prefix.
.TP
.BI src-eq " plen"
This entry only applies to routes with a source prefix length equal to
.BR plen .
.TP
.BI src-le " plen"
This entry only applies to routes with a source prefix length less or
equal to
.BR plen .
.TP
.BI src-ge " plen"
This entry only applies to routes with a source prefix length greater
or equal to
.BR plen .
.TP
.BI neigh " address"
This entry only applies to routes learned from a neighbour with
link-local address
...
...
@@ -454,6 +479,10 @@ For an input or output filter, allow this route after increasing its metric by
.IR value .
For a redistribute filter, redistribute this route with metric
.IR value .
.TP
.BI src-prefix " prefix"
For a redistribute filter, set the source prefix of this route to
.IR prefix .
.PP
If
.I action
...
...
@@ -496,6 +525,12 @@ or, if you want to constrain the routes that you redistribute,
\-C 'redistribute proto 11 ip ::/0 le 64 metric 256' \\
\-C 'redistribute proto 11 ip 0.0.0.0/0 le 24 metric 256' \\
wlan0
.SS Source-sensitive routing
.PP
If your want to redistribute kernel routes as source-specific to the network,
with the 2001:DB8:0:1::/64 prefix:
.IP
redistribute src-prefix 2001:DB8:0:1::/64
.SH FILES
.TP
.B /etc/babeld.conf
...
...
configuration.c
View file @
4a4d66da
...
...
@@ -283,6 +283,7 @@ parse_filter(int c, gnc_t gnc, void *closure, struct filter **filter_return)
if
(
filter
==
NULL
)
goto
error
;
filter
->
plen_le
=
128
;
filter
->
src_plen_le
=
128
;
while
(
1
)
{
c
=
skip_whitespace
(
c
,
gnc
,
closure
);
...
...
@@ -295,10 +296,25 @@ parse_filter(int c, gnc_t gnc, void *closure, struct filter **filter_return)
goto
error
;
if
(
strcmp
(
token
,
"ip"
)
==
0
)
{
c
=
getnet
(
c
,
&
filter
->
prefix
,
&
filter
->
plen
,
&
filter
->
af
,
int
af
;
c
=
getnet
(
c
,
&
filter
->
prefix
,
&
filter
->
plen
,
&
af
,
gnc
,
closure
);
if
(
c
<
-
1
)
goto
error
;
if
(
filter
->
af
==
AF_UNSPEC
)
filter
->
af
=
af
;
else
if
(
filter
->
af
!=
af
)
goto
error
;
}
else
if
(
strcmp
(
token
,
"src-ip"
)
==
0
)
{
int
af
;
c
=
getnet
(
c
,
&
filter
->
src_prefix
,
&
filter
->
src_plen
,
&
af
,
gnc
,
closure
);
if
(
c
<
-
1
)
goto
error
;
if
(
filter
->
af
==
AF_UNSPEC
)
filter
->
af
=
af
;
else
if
(
filter
->
af
!=
af
)
goto
error
;
}
else
if
(
strcmp
(
token
,
"eq"
)
==
0
)
{
int
p
;
c
=
getint
(
c
,
&
p
,
gnc
,
closure
);
...
...
@@ -318,6 +334,25 @@ parse_filter(int c, gnc_t gnc, void *closure, struct filter **filter_return)
if
(
c
<
-
1
)
goto
error
;
filter
->
plen_ge
=
MAX
(
filter
->
plen_ge
,
p
);
}
else
if
(
strcmp
(
token
,
"src-eq"
)
==
0
)
{
int
p
;
c
=
getint
(
c
,
&
p
,
gnc
,
closure
);
if
(
c
<
-
1
)
goto
error
;
filter
->
src_plen_ge
=
MAX
(
filter
->
src_plen_ge
,
p
);
filter
->
src_plen_le
=
MIN
(
filter
->
src_plen_le
,
p
);
}
else
if
(
strcmp
(
token
,
"src-le"
)
==
0
)
{
int
p
;
c
=
getint
(
c
,
&
p
,
gnc
,
closure
);
if
(
c
<
-
1
)
goto
error
;
filter
->
src_plen_le
=
MIN
(
filter
->
src_plen_le
,
p
);
}
else
if
(
strcmp
(
token
,
"src-ge"
)
==
0
)
{
int
p
;
c
=
getint
(
c
,
&
p
,
gnc
,
closure
);
if
(
c
<
-
1
)
goto
error
;
filter
->
src_plen_ge
=
MAX
(
filter
->
src_plen_ge
,
p
);
}
else
if
(
strcmp
(
token
,
"neigh"
)
==
0
)
{
unsigned
char
*
neigh
=
NULL
;
c
=
getip
(
c
,
&
neigh
,
NULL
,
gnc
,
closure
);
...
...
@@ -346,23 +381,36 @@ parse_filter(int c, gnc_t gnc, void *closure, struct filter **filter_return)
filter
->
ifname
=
interface
;
filter
->
ifindex
=
if_nametoindex
(
interface
);
}
else
if
(
strcmp
(
token
,
"allow"
)
==
0
)
{
filter
->
result
=
0
;
filter
->
action
.
add_metric
=
0
;
}
else
if
(
strcmp
(
token
,
"deny"
)
==
0
)
{
filter
->
result
=
INFINITY
;
filter
->
action
.
add_metric
=
INFINITY
;
}
else
if
(
strcmp
(
token
,
"metric"
)
==
0
)
{
int
metric
;
c
=
getint
(
c
,
&
metric
,
gnc
,
closure
);
if
(
c
<
-
1
)
goto
error
;
if
(
metric
<=
0
||
metric
>
INFINITY
)
goto
error
;
filter
->
result
=
metric
;
filter
->
action
.
add_metric
=
metric
;
}
else
if
(
strcmp
(
token
,
"src-prefix"
)
==
0
)
{
int
af
;
c
=
getnet
(
c
,
&
filter
->
action
.
src_prefix
,
&
filter
->
action
.
src_plen
,
&
af
,
gnc
,
closure
);
if
(
c
<
-
1
)
goto
error
;
if
(
filter
->
af
==
AF_UNSPEC
)
filter
->
af
=
af
;
else
if
(
filter
->
af
!=
af
)
goto
error
;
if
(
af
==
AF_INET
&&
filter
->
action
.
src_plen
==
96
)
memset
(
&
filter
->
action
.
src_prefix
,
0
,
16
);
}
else
{
goto
error
;
}
free
(
token
);
}
if
(
filter
->
af
==
0
)
{
if
(
filter
->
plen_le
<
128
||
filter
->
plen_ge
>
0
)
if
(
filter
->
plen_le
<
128
||
filter
->
plen_ge
>
0
||
filter
->
src_plen_le
<
128
||
filter
->
src_plen_ge
>
0
)
filter
->
af
=
AF_INET6
;
}
else
if
(
filter
->
af
==
AF_INET
)
{
filter
->
plen_le
+=
96
;
...
...
@@ -716,6 +764,18 @@ parse_option(int c, gnc_t gnc, void *closure, char *token)
if
(
c
<
-
1
||
h
<
0
)
goto
error
;
change_smoothing_half_life
(
h
);
}
else
if
(
strcmp
(
token
,
"first-table-number"
)
==
0
)
{
int
n
;
c
=
getint
(
c
,
&
n
,
gnc
,
closure
);
if
(
c
<
-
1
||
n
<=
0
||
n
+
SRC_TABLE_NUM
>=
254
)
goto
error
;
src_table_idx
=
n
;
}
else
if
(
strcmp
(
token
,
"first-rule-priority"
)
==
0
)
{
int
n
;
c
=
getint
(
c
,
&
n
,
gnc
,
closure
);
if
(
c
<
-
1
||
n
<=
0
||
n
+
SRC_TABLE_NUM
>=
32765
)
goto
error
;
src_table_prio
=
n
;
}
else
{
goto
error
;
}
...
...
@@ -876,6 +936,7 @@ renumber_filters()
static
int
filter_match
(
struct
filter
*
f
,
const
unsigned
char
*
id
,
const
unsigned
char
*
prefix
,
unsigned
short
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
short
src_plen
,
const
unsigned
char
*
neigh
,
unsigned
int
ifindex
,
int
proto
)
{
if
(
f
->
af
)
{
...
...
@@ -893,6 +954,11 @@ filter_match(struct filter *f, const unsigned char *id,
if
(
!
prefix
||
plen
<
f
->
plen
||
!
in_prefix
(
prefix
,
f
->
prefix
,
f
->
plen
))
return
0
;
}
if
(
f
->
src_prefix
)
{
if
(
!
src_prefix
||
src_plen
<
f
->
src_plen
||
!
in_prefix
(
src_prefix
,
f
->
src_prefix
,
f
->
src_plen
))
return
0
;
}
if
(
f
->
plen_ge
>
0
||
f
->
plen_le
<
128
)
{
if
(
!
prefix
)
return
0
;
...
...
@@ -901,6 +967,14 @@ filter_match(struct filter *f, const unsigned char *id,
if
(
plen
<
f
->
plen_ge
)
return
0
;
}
if
(
f
->
src_plen_ge
>
0
||
f
->
src_plen_le
<
128
)
{
if
(
!
src_prefix
)
return
0
;
if
(
src_plen
>
f
->
src_plen_le
)
return
0
;
if
(
src_plen
<
f
->
src_plen_ge
)
return
0
;
}
if
(
f
->
neigh
)
{
if
(
!
neigh
||
memcmp
(
f
->
neigh
,
neigh
,
16
)
!=
0
)
return
0
;
...
...
@@ -928,34 +1002,49 @@ filter_match(struct filter *f, const unsigned char *id,
static
int
do_filter
(
struct
filter
*
f
,
const
unsigned
char
*
id
,
const
unsigned
char
*
prefix
,
unsigned
short
plen
,
const
unsigned
char
*
neigh
,
unsigned
int
ifindex
,
int
proto
)
const
unsigned
char
*
src_prefix
,
unsigned
short
src_plen
,
const
unsigned
char
*
neigh
,
unsigned
int
ifindex
,
int
proto
,
struct
filter_result
*
result
)
{
if
(
result
)
memset
(
result
,
0
,
sizeof
(
struct
filter_result
));
while
(
f
)
{
if
(
filter_match
(
f
,
id
,
prefix
,
plen
,
neigh
,
ifindex
,
proto
))
return
f
->
result
;
if
(
filter_match
(
f
,
id
,
prefix
,
plen
,
src_prefix
,
src_plen
,
neigh
,
ifindex
,
proto
))
{
if
(
result
)
memcpy
(
result
,
&
f
->
action
,
sizeof
(
struct
filter_result
));
return
f
->
action
.
add_metric
;
}
f
=
f
->
next
;
}
return
-
1
;
}
int
input_filter
(
const
unsigned
char
*
id
,
const
unsigned
char
*
prefix
,
unsigned
short
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
short
src_plen
,
const
unsigned
char
*
neigh
,
unsigned
int
ifindex
)
{
int
res
;
res
=
do_filter
(
input_filters
,
id
,
prefix
,
plen
,
neigh
,
ifindex
,
0
);
res
=
do_filter
(
input_filters
,
id
,
prefix
,
plen
,
src_prefix
,
src_plen
,
neigh
,
ifindex
,
0
,
NULL
);
if
(
res
<
0
)
res
=
0
;
return
res
;
}
int
output_filter
(
const
unsigned
char
*
id
,
const
unsigned
char
*
prefix
,
unsigned
short
plen
,
unsigned
int
ifindex
)
output_filter
(
const
unsigned
char
*
id
,
const
unsigned
char
*
prefix
,
unsigned
short
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
short
src_plen
,
unsigned
int
ifindex
)
{
int
res
;
res
=
do_filter
(
output_filters
,
id
,
prefix
,
plen
,
NULL
,
ifindex
,
0
);
res
=
do_filter
(
output_filters
,
id
,
prefix
,
plen
,
src_prefix
,
src_plen
,
NULL
,
ifindex
,
0
,
NULL
);
if
(
res
<
0
)
res
=
0
;
return
res
;
...
...
@@ -963,11 +1052,13 @@ output_filter(const unsigned char *id, const unsigned char *prefix,
int
redistribute_filter
(
const
unsigned
char
*
prefix
,
unsigned
short
plen
,
unsigned
int
ifindex
,
int
proto
)
const
unsigned
char
*
src_prefix
,
unsigned
short
src_plen
,
unsigned
int
ifindex
,
int
proto
,
struct
filter_result
*
result
)
{
int
res
;
res
=
do_filter
(
redistribute_filters
,
NULL
,
prefix
,
plen
,
NULL
,
ifindex
,
proto
);
res
=
do_filter
(
redistribute_filters
,
NULL
,
prefix
,
plen
,
src_prefix
,
src_plen
,
NULL
,
ifindex
,
proto
,
result
);
if
(
res
<
0
)
res
=
INFINITY
;
return
res
;
...
...
@@ -982,6 +1073,7 @@ finalise_config()
filter
->
proto
=
RTPROT_BABEL_LOCAL
;
filter
->
plen_le
=
128
;
filter
->
src_plen_le
=
128
;
add_filter
(
filter
,
&
redistribute_filters
);
while
(
interface_confs
)
{
...
...
configuration.h
View file @
4a4d66da
...
...
@@ -20,6 +20,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
struct
filter_result
{
unsigned
int
add_metric
;
/* allow = 0, deny = INF, metric = <0..INF> */
unsigned
char
*
src_prefix
;
unsigned
char
src_plen
;
};
struct
filter
{
int
af
;
char
*
ifname
;
...
...
@@ -28,9 +34,12 @@ struct filter {
unsigned
char
*
prefix
;
unsigned
char
plen
;
unsigned
char
plen_ge
,
plen_le
;
unsigned
char
*
src_prefix
;
unsigned
char
src_plen
;
unsigned
char
src_plen_ge
,
src_plen_le
;
unsigned
char
*
neigh
;
int
proto
;
/* May be negative */
unsigned
int
result
;
struct
filter_result
action
;
struct
filter
*
next
;
};
...
...
@@ -42,9 +51,14 @@ void renumber_filters(void);
int
input_filter
(
const
unsigned
char
*
id
,
const
unsigned
char
*
prefix
,
unsigned
short
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
short
src_plen
,
const
unsigned
char
*
neigh
,
unsigned
int
ifindex
);
int
output_filter
(
const
unsigned
char
*
id
,
const
unsigned
char
*
prefix
,
unsigned
short
plen
,
unsigned
int
ifindex
);
int
output_filter
(
const
unsigned
char
*
id
,
const
unsigned
char
*
prefix
,
unsigned
short
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
short
src_plen
,
unsigned
int
ifindex
);
int
redistribute_filter
(
const
unsigned
char
*
prefix
,
unsigned
short
plen
,
unsigned
int
ifindex
,
int
proto
);
const
unsigned
char
*
src_prefix
,
unsigned
short
src_plen
,
unsigned
int
ifindex
,
int
proto
,
struct
filter_result
*
result
);
int
finalise_config
(
void
);
disambiguation.c
0 → 100644
View file @
4a4d66da
/*
Copyright (c) 2014 by Matthieu Boutier and Juliusz Chroboczek.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <sys/time.h>
#include "babeld.h"
#include "util.h"
#include "interface.h"
#include "kernel.h"
#include "route.h"
#include "source.h"
#include "neighbour.h"
struct
zone
{
const
unsigned
char
*
dst_prefix
;
unsigned
char
dst_plen
;
const
unsigned
char
*
src_prefix
;
unsigned
char
src_plen
;
};
/* This function assumes rt1 and rt2 non disjoint. */
static
int
rt_cmp
(
const
struct
babel_route
*
rt1
,
const
struct
babel_route
*
rt2
)
{
enum
prefix_status
dst_st
,
src_st
;
const
struct
source
*
r1
=
rt1
->
src
,
*
r2
=
rt2
->
src
;
dst_st
=
prefix_cmp
(
r1
->
prefix
,
r1
->
plen
,
r2
->
prefix
,
r2
->
plen
);
if
(
dst_st
&
PST_MORE_SPECIFIC
)
return
-
1
;
else
if
(
dst_st
&
PST_LESS_SPECIFIC
)
return
1
;
src_st
=
prefix_cmp
(
r1
->
src_prefix
,
r1
->
src_plen
,
r2
->
src_prefix
,
r2
->
src_plen
);
if
(
src_st
&
PST_MORE_SPECIFIC
)
return
-
1
;
else
if
(
src_st
&
PST_LESS_SPECIFIC
)
return
1
;
return
0
;
}
static
const
struct
babel_route
*
min_route
(
const
struct
babel_route
*
r1
,
const
struct
babel_route
*
r2
)
{
if
(
!
r1
)
return
r2
;
if
(
!
r2
)
return
r1
;
int
rc
=
rt_cmp
(
r1
,
r2
);
return
rc
<=
0
?
r1
:
r2
;
}
static
int
conflicts
(
const
struct
babel_route
*
rt
,
const
struct
babel_route
*
rt1
)
{
enum
prefix_status
dst_st
,
src_st
;
const
struct
source
*
r
=
rt
->
src
,
*
r1
=
rt1
->
src
;
dst_st
=
prefix_cmp
(
r
->
prefix
,
r
->
plen
,
r1
->
prefix
,
r1
->
plen
);
if
(
dst_st
&
(
PST_DISJOINT
|
PST_EQUALS
))
return
0
;
src_st
=
prefix_cmp
(
r
->
src_prefix
,
r
->
src_plen
,
r1
->
src_prefix
,
r1
->
src_plen
);
return
((
dst_st
==
PST_LESS_SPECIFIC
&&
src_st
==
PST_MORE_SPECIFIC
)
||
(
dst_st
==
PST_MORE_SPECIFIC
&&
src_st
==
PST_LESS_SPECIFIC
));
}
static
const
struct
zone
*
to_zone
(
const
struct
babel_route
*
rt
,
struct
zone
*
zone
)
{
zone
->
dst_prefix
=
rt
->
src
->
prefix
;
zone
->
dst_plen
=
rt
->
src
->
plen
;
zone
->
src_prefix
=
rt
->
src
->
src_prefix
;
zone
->
src_plen
=
rt
->
src
->
src_plen
;
return
zone
;
}
/* fill zone with rt cap rt1, and returns a pointer to zone, or NULL if the
intersection is empty. */
static
const
struct
zone
*
inter
(
const
struct
babel_route
*
rt
,
const
struct
babel_route
*
rt1
,
struct
zone
*
zone
)
{
enum
prefix_status
dst_st
,
src_st
;
const
struct
source
*
r
=
rt
->
src
,
*
r1
=
rt1
->
src
;
dst_st
=
prefix_cmp
(
r
->
prefix
,
r
->
plen
,
r1
->
prefix
,
r1
->
plen
);
if
(
dst_st
&
PST_DISJOINT
)
return
NULL
;
src_st
=
prefix_cmp
(
r
->
src_prefix
,
r
->
src_plen
,
r1
->
src_prefix
,
r1
->
src_plen
);
if
(
src_st
&
PST_DISJOINT
)
return
NULL
;
if
(
dst_st
&
(
PST_MORE_SPECIFIC
|
PST_EQUALS
))
{
zone
->
dst_prefix
=
r
->
prefix
;
zone
->
dst_plen
=
r
->
plen
;
}
else
{
zone
->
dst_prefix
=
r1
->
prefix
;
zone
->
dst_plen
=
r1
->
plen
;
}
if
(
src_st
&
(
PST_MORE_SPECIFIC
|
PST_EQUALS
))
{
zone
->
src_prefix
=
r
->
src_prefix
;
zone
->
src_plen
=
r
->
src_plen
;
}
else
{
zone
->
src_prefix
=
r1
->
src_prefix
;
zone
->
src_plen
=
r1
->
src_plen
;
}
return
zone
;
}
static
int
zone_equal
(
const
struct
zone
*
z1
,
const
struct
zone
*
z2
)
{
return
z1
&&
z2
&&
z1
->
dst_plen
==
z2
->
dst_plen
&&
memcmp
(
z1
->
dst_prefix
,
z2
->
dst_prefix
,
z1
->
dst_plen
)
==
0
&&
z1
->
src_plen
==
z2
->
src_plen
&&
memcmp
(
z1
->
src_prefix
,
z2
->
src_prefix
,
z1
->
src_plen
)
==
0
;
}
static
const
struct
babel_route
*
min_conflict
(
const
struct
zone
*
zone
,
const
struct
babel_route
*
rt
)
{
struct
babel_route
*
rt1
=
NULL
;
const
struct
babel_route
*
min
=
NULL
;
struct
route_stream
*
stream
=
NULL
;
struct
zone
curr_zone
;
stream
=
route_stream
(
1
);
if
(
!
stream
)
{
fprintf
(
stderr
,
"Couldn't allocate route stream.
\n
"
);
return
NULL
;
}
while
(
1
)
{
rt1
=
route_stream_next
(
stream
);
if
(
rt1
==
NULL
)
break
;
if
(
!
(
conflicts
(
rt
,
rt1
)
&&
zone_equal
(
inter
(
rt
,
rt1
,
&
curr_zone
),
zone
)))
continue
;
min
=
min_route
(
rt1
,
min
);
}
route_stream_done
(
stream
);
return
min
;
}
static
const
struct
babel_route
*
conflict_solution
(
const
struct
babel_route
*
rt
)
{
const
struct
babel_route
*
rt1
=
NULL
,
*
rt2
=
NULL
;
struct
route_stream
*
stream1
=
NULL
;
struct
route_stream
*
stream2
=
NULL
;
const
struct
babel_route
*
min
=
NULL
;
/* == solution */
struct
zone
zone
;
struct
zone
tmp
;
stream1
=
route_stream
(
1
);
if
(
!
stream1
)
{
return
NULL
;
}
while
(
1
)
{
rt1
=
route_stream_next
(
stream1
);
if
(
rt1
==
NULL
)
break
;
stream2
=
route_stream
(
1
);
if
(
!
stream2
)
{
route_stream_done
(
stream1
);
fprintf
(
stderr
,
"Couldn't allocate route stream.
\n
"
);
return
NULL
;
}
while
(
1
)
{
rt2
=
route_stream_next
(
stream2
);
if
(
rt2
==
NULL
)
break
;
if
(
!
(
conflicts
(
rt1
,
rt2
)
&&
zone_equal
(
inter
(
rt1
,
rt2
,
&
tmp
),
to_zone
(
rt
,
&
zone
))
&&
rt_cmp
(
rt1
,
rt2
)
<
0
))
continue
;
min
=
min_route
(
rt1
,
min
);
}
route_stream_done
(
stream2
);
}
route_stream_done
(
stream1
);
return
min
;
}
static
int
is_installed
(
struct
zone
*
zone
)
{
return
zone
!=
NULL
&&
find_installed_route
(
zone
->
dst_prefix
,
zone
->
dst_plen
,
zone
->
src_prefix
,
zone
->
src_plen
)
!=
NULL
;
}
static
int
add_route
(
const
struct
zone
*
zone
,
const
struct
babel_route
*
route
)
{
return
kernel_route
(
ROUTE_ADD
,
zone
->
dst_prefix
,
zone
->
dst_plen
,
zone
->
src_prefix
,
zone
->
src_plen
,
route
->
nexthop
,
route
->
neigh
->
ifp
->
ifindex
,
metric_to_kernel
(
route_metric
(
route
)),
NULL
,
0
,
0
);
}
static
int
del_route
(
const
struct
zone
*
zone
,
const
struct
babel_route
*
route
)
{
return
kernel_route
(
ROUTE_FLUSH
,
zone
->
dst_prefix
,
zone
->
dst_plen
,
zone
->
src_prefix
,
zone
->
src_plen
,
route
->
nexthop
,
route
->
neigh
->
ifp
->
ifindex
,
metric_to_kernel
(
route_metric
(
route
)),
NULL
,
0
,
0
);
}
static
int
chg_route
(
const
struct
zone
*
zone
,
const
struct
babel_route
*
old
,
const
struct
babel_route
*
new
)
{
return
kernel_route
(
ROUTE_MODIFY
,
zone
->
dst_prefix
,
zone
->
dst_plen
,
zone
->
src_prefix
,
zone
->
src_plen
,
old
->
nexthop
,
old
->
neigh
->
ifp
->
ifindex
,
metric_to_kernel
(
route_metric
(
old
)),
new
->
nexthop
,
new
->
neigh
->
ifp
->
ifindex
,
metric_to_kernel
(
route_metric
(
new
)));
}
static
int
chg_route_metric
(
const
struct
zone
*
zone
,
const
struct
babel_route
*
route
,
int
old_metric
,
int
new_metric
)
{
return
kernel_route
(
ROUTE_MODIFY
,
zone
->
dst_prefix
,
zone
->
dst_plen
,
zone
->
src_prefix
,
zone
->
src_plen
,
route
->
nexthop
,
route
->
neigh
->
ifp
->
ifindex
,
old_metric
,
route
->
nexthop
,
route
->
neigh
->
ifp
->
ifindex
,
new_metric
);
}
int
kinstall_route
(
const
struct
babel_route
*
route
)
{
int
rc
;
struct
zone
zone
;
const
struct
babel_route
*
rt1
=
NULL
;
const
struct
babel_route
*
rt2
=
NULL
;
struct
route_stream
*
stream
=
NULL
;
int
v4
=
v4mapped
(
route
->
nexthop
);
debugf
(
"install_route(%s from %s)
\n
"
,
format_prefix
(
route
->
src
->
prefix
,
route
->
src
->
plen
),
format_prefix
(
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
));
/* Install source-specific conflicting routes */
if
(
!
has_ipv6_subtrees
||
v4
)
{
stream
=
route_stream
(
1
);
if
(
!
stream
)
{
fprintf
(
stderr
,
"Couldn't allocate route stream.
\n
"
);
return
-
1
;
}
/* Install source-specific conflicting routes */
while
(
1
)
{
rt1
=
route_stream_next
(
stream
);
if
(
rt1
==
NULL
)
break
;
inter
(
route
,
rt1
,
&
zone
);
if
(
!
(
conflicts
(
route
,
rt1
)
&&
!
is_installed
(
&
zone
)
&&
rt_cmp
(
rt1
,
min_conflict
(
&
zone
,
route
))
==
0
))
continue
;
rt2
=
min_conflict
(
&
zone
,
rt1
);
if
(
rt2
==
NULL
)
add_route
(
&
zone
,
min_route
(
route
,
rt1
));
else
if
(
rt_cmp
(
route
,
rt2
)
<
0
&&
rt_cmp
(
route
,
rt1
)
<
0
)
chg_route
(
&
zone
,
rt2
,
route
);
}
route_stream_done
(
stream
);
}
/* Non conflicting case */
to_zone
(
route
,
&
zone
);
rt1
=
conflict_solution
(
route
);
if
(
rt1
==
NULL
)
rc
=
add_route
(
&
zone
,
route
);
else
rc
=
chg_route
(
&
zone
,
rt1
,
route
);
if
(
rc
<
0
)
{
int
save
=
errno
;
perror
(
"kernel_route(ADD)"
);
if
(
save
!=
EEXIST
)
return
-
1
;
}
return
0
;
}
int
kuninstall_route
(
const
struct
babel_route
*
route
)
{
int
rc
;
struct
zone
zone
;
const
struct
babel_route
*
rt1
=
NULL
,
*
rt2
=
NULL
;
struct
route_stream
*
stream
=
NULL
;
int
v4
=
v4mapped
(
route
->
nexthop
);
debugf
(
"uninstall_route(%s from %s)
\n
"
,
format_prefix
(
route
->
src
->
prefix
,
route
->
src
->
plen
),
format_prefix
(
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
));
/* Remove the route, or change if the route was solving a conflict. */
to_zone
(
route
,
&
zone
);
rt1
=
conflict_solution
(
route
);
if
(
rt1
==
NULL
)
rc
=
del_route
(
&
zone
,
route
);
else
rc
=
chg_route
(
&
zone
,
route
,
rt1
);
if
(
rc
<
0
)
perror
(
"kernel_route(FLUSH)"
);
/* Remove source-specific conflicting routes */
if
(
!
has_ipv6_subtrees
||
v4
)
{
stream
=
route_stream
(
1
);
if
(
!
stream
)
{
fprintf
(
stderr
,
"Couldn't allocate route stream.
\n
"
);
return
-
1
;
}
while
(
1
)
{
rt1
=
route_stream_next
(
stream
);
if
(
rt1
==
NULL
)
break
;
inter
(
route
,
rt1
,
&
zone
);
if
(
!
(
conflicts
(
route
,
rt1
)
&&
!
is_installed
(
&
zone
)
&&
rt_cmp
(
rt1
,
min_conflict
(
&
zone
,
route
))
==
0
))
continue
;
rt2
=
min_conflict
(
&
zone
,
rt1
);
if
(
rt2
==
NULL
)
del_route
(
&
zone
,
min_route
(
route
,
rt1
));
else
if
(
rt_cmp
(
route
,
rt2
)
<
0
&&
rt_cmp
(
route
,
rt1
)
<
0
)
chg_route
(
&
zone
,
route
,
rt2
);
}
route_stream_done
(
stream
);
}
return
rc
;
}
int
kswitch_routes
(
const
struct
babel_route
*
old
,
const
struct
babel_route
*
new
)
{
int
rc
;
struct
zone
zone
;
struct
babel_route
*
rt1
=
NULL
;
struct
route_stream
*
stream
=
NULL
;
debugf
(
"switch_routes(%s from %s)
\n
"
,
format_prefix
(
old
->
src
->
prefix
,
old
->
src
->
plen
),
format_prefix
(
old
->
src
->
src_prefix
,
old
->
src
->
src_plen
));
to_zone
(
old
,
&
zone
);
rc
=
chg_route
(
&
zone
,
old
,
new
);
if
(
rc
<
0
)
{
perror
(
"kernel_route(MODIFY)"
);
return
-
1
;
}
/* Remove source-specific conflicting routes */
if
(
!
has_ipv6_subtrees
||
v4mapped
(
old
->
nexthop
))
{
stream
=
route_stream
(
1
);
if
(
!
stream
)
{
fprintf
(
stderr
,
"Couldn't allocate route stream.
\n
"
);
return
-
1
;
}
while
(
1
)
{
rt1
=
route_stream_next
(
stream
);
if
(
rt1
==
NULL
)
break
;
inter
(
old
,
rt1
,
&
zone
);
if
(
!
(
conflicts
(
old
,
rt1
)
&&
!
is_installed
(
&
zone
)
&&
rt_cmp
(
rt1
,
min_conflict
(
&
zone
,
old
))
==
0
&&
rt_cmp
(
old
,
rt1
)
<
0
&&
rt_cmp
(
old
,
min_conflict
(
&
zone
,
rt1
))
==
0
))
continue
;
chg_route
(
&
zone
,
old
,
new
);
}
route_stream_done
(
stream
);
}
return
rc
;
}
int
kchange_route_metric
(
const
struct
babel_route
*
route
,
unsigned
refmetric
,
unsigned
cost
,
unsigned
add
)
{
int
old_metric
=
metric_to_kernel
(
route_metric
(
route
));
int
new_metric
=
metric_to_kernel
(
MIN
(
refmetric
+
cost
+
add
,
INFINITY
));
int
rc
;
struct
babel_route
*
rt1
=
NULL
;
struct
route_stream
*
stream
=
NULL
;
struct
zone
zone
;
debugf
(
"change_route_metric(%s from %s, %d -> %d)
\n
"
,
format_prefix
(
route
->
src
->
prefix
,
route
->
src
->
plen
),
format_prefix
(
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
),
old_metric
,
new_metric
);
to_zone
(
route
,
&
zone
);
rc
=
chg_route_metric
(
&
zone
,
route
,
old_metric
,
new_metric
);
if
(
rc
<
0
)
{
perror
(
"kernel_route(MODIFY metric)"
);
return
-
1
;
}
if
(
!
has_ipv6_subtrees
||
v4mapped
(
route
->
nexthop
))
{
stream
=
route_stream
(
1
);
if
(
!
stream
)
{
fprintf
(
stderr
,
"Couldn't allocate route stream.
\n
"
);
return
-
1
;
}
while
(
1
)
{
rt1
=
route_stream_next
(
stream
);
if
(
rt1
==
NULL
)
break
;
inter
(
route
,
rt1
,
&
zone
);
if
(
!
(
conflicts
(
route
,
rt1
)
&&
!
is_installed
(
&
zone
)
&&
rt_cmp
(
rt1
,
min_conflict
(
&
zone
,
route
))
==
0
&&
rt_cmp
(
route
,
rt1
)
<
0
&&
rt_cmp
(
route
,
min_conflict
(
&
zone
,
rt1
))
==
0
))
continue
;
chg_route_metric
(
&
zone
,
route
,
old_metric
,
new_metric
);
}
route_stream_done
(
stream
);
}
return
rc
;
}
disambiguation.h
0 → 100644
View file @
4a4d66da
/*
Copyright (c) 2014 by Matthieu Boutier and Juliusz Chroboczek.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
int
kinstall_route
(
struct
babel_route
*
route
);
int
kuninstall_route
(
struct
babel_route
*
route
);
int
kswitch_routes
(
struct
babel_route
*
old
,
struct
babel_route
*
new
);
int
kchange_route_metric
(
struct
babel_route
*
route
,
unsigned
refmetric
,
unsigned
cost
,
unsigned
add
);
interface.c
View file @
4a4d66da
...
...
@@ -177,6 +177,40 @@ check_interface_channel(struct interface *ifp)
return
0
;
}
static
int
check_link_local_addresses
(
struct
interface
*
ifp
)
{
struct
kernel_route
ll
[
32
];
int
rc
,
i
;
if
(
ifp
->
ll
)
free
(
ifp
->
ll
);
ifp
->
numll
=
0
;
ifp
->
ll
=
NULL
;
rc
=
kernel_addresses
(
ifp
->
name
,
ifp
->
ifindex
,
1
,
ll
,
32
);
if
(
rc
<
0
)
{
perror
(
"kernel_addresses(link local)"
);
return
-
1
;
}
else
if
(
rc
==
0
)
{
fprintf
(
stderr
,
"Interface %s has no link-local address.
\n
"
,
ifp
->
name
);
/* Most probably DAD hasn't finished yet. Reschedule us
real soon. */
schedule_interfaces_check
(
2000
,
0
);
return
-
1
;
}
else
{
ifp
->
ll
=
malloc
(
16
*
rc
);
if
(
ifp
->
ll
==
NULL
)
{
perror
(
"malloc(ll)"
);
}
else
{
for
(
i
=
0
;
i
<
rc
;
i
++
)
memcpy
(
ifp
->
ll
[
i
],
ll
[
i
].
prefix
,
16
);
ifp
->
numll
=
rc
;
}
}
return
0
;
}
int
interface_up
(
struct
interface
*
ifp
,
int
up
)
{
...
...
@@ -192,7 +226,6 @@ interface_up(struct interface *ifp, int up)
ifp
->
flags
&=
~
IF_UP
;
if
(
up
)
{
struct
kernel_route
ll
[
32
];
if
(
ifp
->
ifindex
<=
0
)
{
fprintf
(
stderr
,
"Upping unknown interface %s.
\n
"
,
ifp
->
name
);
...
...
@@ -329,32 +362,10 @@ interface_up(struct interface *ifp, int up)
ifp
->
max_rtt_penalty
>
0
))
ifp
->
flags
|=
IF_TIMESTAMPS
;
if
(
ifp
->
ll
)
free
(
ifp
->
ll
);
ifp
->
numll
=
0
;
ifp
->
ll
=
NULL
;
rc
=
kernel_addresses
(
ifp
->
name
,
ifp
->
ifindex
,
1
,
ll
,
32
);
rc
=
check_link_local_addresses
(
ifp
);
if
(
rc
<
0
)
{
perror
(
"kernel_addresses(link local)"
);
goto
fail
;
}
else
if
(
rc
==
0
)
{
fprintf
(
stderr
,
"Interface %s has no link-local address.
\n
"
,
ifp
->
name
);
/* Most probably DAD hasn't finished yet. Reschedule us
real soon. */
goto
fail_retry
;
}
else
{
ifp
->
ll
=
malloc
(
16
*
rc
);
if
(
ifp
->
ll
==
NULL
)
{
perror
(
"malloc(ll)"
);
}
else
{
int
i
;
for
(
i
=
0
;
i
<
rc
;
i
++
)
memcpy
(
ifp
->
ll
[
i
],
ll
[
i
].
prefix
,
16
);
ifp
->
numll
=
rc
;
}
}
memset
(
&
mreq
,
0
,
sizeof
(
mreq
));
memcpy
(
&
mreq
.
ipv6mr_multiaddr
,
protocol_group
,
16
);
mreq
.
ipv6mr_interface
=
ifp
->
ifindex
;
...
...
@@ -380,8 +391,8 @@ interface_up(struct interface *ifp, int up)
set_timeout
(
&
ifp
->
update_timeout
,
ifp
->
update_interval
);
send_hello
(
ifp
);
if
(
rc
>
0
)
send_update
(
ifp
,
0
,
NULL
,
0
);
send_request
(
ifp
,
NULL
,
0
);
send_update
(
ifp
,
0
,
NULL
,
0
,
NULL
,
0
);
send_request
(
ifp
,
NULL
,
0
,
NULL
,
0
);
}
else
{
flush_interface_routes
(
ifp
,
0
);
ifp
->
buffered
=
0
;
...
...
@@ -411,8 +422,6 @@ interface_up(struct interface *ifp, int up)
return
1
;
fail_retry:
schedule_interfaces_check
(
2000
,
0
);
fail:
assert
(
up
);
interface_up
(
ifp
,
0
);
...
...
@@ -462,12 +471,13 @@ check_interfaces(void)
if
(
if_up
(
ifp
))
{
/* Bother, said Pooh. We should probably check for a change
in link-local and IPv4 addresses at this point. */
in IPv4 addresses at this point. */
check_link_local_addresses
(
ifp
);
check_interface_channel
(
ifp
);
rc
=
check_interface_ipv4
(
ifp
);
if
(
rc
>
0
)
{
send_request
(
ifp
,
NULL
,
0
);
send_update
(
ifp
,
0
,
NULL
,
0
);
send_request
(
ifp
,
NULL
,
0
,
NULL
,
0
);
send_update
(
ifp
,
0
,
NULL
,
0
,
NULL
,
0
);
}
}
}
...
...
interface.h
View file @
4a4d66da
...
...
@@ -23,8 +23,10 @@ THE SOFTWARE.
struct
buffered_update
{
unsigned
char
id
[
8
];
unsigned
char
prefix
[
16
];
unsigned
char
src_prefix
[
16
];
unsigned
char
plen
;
unsigned
char
pad
[
3
];
unsigned
char
src_plen
;
/* 0 <=> no src prefix */
unsigned
char
pad
[
2
];
};
struct
interface_conf
{
...
...
@@ -94,6 +96,7 @@ struct interface {
time_t
bucket_time
;
unsigned
int
bucket
;
time_t
last_update_time
;
time_t
last_specific_update_time
;
unsigned
short
hello_seqno
;
unsigned
hello_interval
;
unsigned
update_interval
;
...
...
kernel.c
View file @
4a4d66da
...
...
@@ -32,6 +32,9 @@ THE SOFTWARE.
#include "kernel_socket.c"
#endif
int
src_table_idx
=
10
;
int
src_table_prio
=
100
;
/* Like gettimeofday, but returns monotonic time. If POSIX clocks are not
available, falls back to gettimeofday but enforces monotonicity. */
int
...
...
kernel.h
View file @
4a4d66da
...
...
@@ -28,6 +28,8 @@ THE SOFTWARE.
struct
kernel_route
{
unsigned
char
prefix
[
16
];
int
plen
;
unsigned
char
src_prefix
[
16
];
int
src_plen
;
/* no source prefix <=> src_plen == 0 */
int
metric
;
unsigned
int
ifindex
;
int
proto
;
...
...
@@ -41,6 +43,7 @@ struct kernel_route {
#define CHANGE_LINK (1 << 0)
#define CHANGE_ROUTE (1 << 1)
#define CHANGE_ADDR (1 << 2)
#define CHANGE_RULE (1 << 3)
#ifndef MAX_IMPORT_TABLES
#define MAX_IMPORT_TABLES 10
...
...
@@ -49,6 +52,9 @@ struct kernel_route {
extern
int
export_table
,
import_tables
[
MAX_IMPORT_TABLES
],
import_table_count
;
int
add_import_table
(
int
table
);
#define SRC_TABLE_NUM 10
extern
int
src_table_idx
;
/* number of the first table */
extern
int
src_table_prio
;
/* first prio range */
int
kernel_setup
(
int
setup
);
int
kernel_setup_socket
(
int
setup
);
...
...
@@ -60,6 +66,7 @@ int kernel_interface_mtu(const char *ifname, int ifindex);
int
kernel_interface_wireless
(
const
char
*
ifname
,
int
ifindex
);
int
kernel_interface_channel
(
const
char
*
ifname
,
int
ifindex
);
int
kernel_route
(
int
operation
,
const
unsigned
char
*
dest
,
unsigned
short
plen
,
const
unsigned
char
*
src
,
unsigned
short
src_plen
,
const
unsigned
char
*
gate
,
int
ifindex
,
unsigned
int
metric
,
const
unsigned
char
*
newgate
,
int
newifindex
,
unsigned
int
newmetric
);
...
...
kernel_netlink.c
View file @
4a4d66da
...
...
@@ -40,6 +40,7 @@ THE SOFTWARE.
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if_bridge.h>
#include <linux/fib_rules.h>
#include <netinet/ether.h>
#if(__GLIBC__ < 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 5)
...
...
@@ -77,6 +78,13 @@ static int dgram_socket = -1;
#define NO_ARPHRD
#endif
static
int
find_table
(
const
unsigned
char
*
src
,
unsigned
short
src_plen
);
static
void
release_tables
(
void
);
static
int
filter_kernel_rules
(
struct
nlmsghdr
*
nh
,
void
*
data
);
static
void
install_missing_rules
(
char
rule_exists
[
SRC_TABLE_NUM
],
int
v4
);
/* Determine an interface's hardware address, in modified EUI-64 format */
int
if_eui64
(
char
*
ifname
,
int
ifindex
,
unsigned
char
*
eui
)
...
...
@@ -548,6 +556,7 @@ kernel_setup(int setup)
return
1
;
}
else
{
release_tables
();
close
(
dgram_socket
);
dgram_socket
=
-
1
;
...
...
@@ -613,9 +622,13 @@ kernel_setup_socket(int setup)
|
rtnlgrp_to_mask
(
RTNLGRP_IPV4_ROUTE
)
|
rtnlgrp_to_mask
(
RTNLGRP_LINK
)
|
rtnlgrp_to_mask
(
RTNLGRP_IPV4_IFADDR
)
|
rtnlgrp_to_mask
(
RTNLGRP_IPV6_IFADDR
));
|
rtnlgrp_to_mask
(
RTNLGRP_IPV6_IFADDR
)
/* We monitor rules, because it can be change by third parties. For example
a /etc/init.d/network restart on OpenWRT flush the rules. */
|
rtnlgrp_to_mask
(
RTNLGRP_IPV4_RULE
)
|
rtnlgrp_to_mask
(
RTNLGRP_IPV6_RULE
));
if
(
rc
<
0
)
{
perror
(
"netlink_socket(_ROUTE | _LINK | _IFADDR)"
);
perror
(
"netlink_socket(_ROUTE | _LINK | _IFADDR
| _RULE
)"
);
kernel_socket
=
-
1
;
return
-
1
;
}
...
...
@@ -906,16 +919,16 @@ kernel_interface_channel(const char *ifname, int ifindex)
int
kernel_route
(
int
operation
,
const
unsigned
char
*
dest
,
unsigned
short
plen
,
const
unsigned
char
*
src
,
unsigned
short
src_plen
,
const
unsigned
char
*
gate
,
int
ifindex
,
unsigned
int
metric
,
const
unsigned
char
*
newgate
,
int
newifindex
,
unsigned
int
newmetric
)
{
union
{
char
raw
[
1024
];
struct
nlmsghdr
nh
;
}
buf
;
struct
rtmsg
*
rtm
;
struct
rtattr
*
rta
;
int
len
=
sizeof
(
buf
.
raw
);
int
rc
,
ipv4
;
int
rc
,
ipv4
,
table
,
use_src
=
0
;
if
(
!
nl_setup
)
{
fprintf
(
stderr
,
"kernel_route: netlink not initialized.
\n
"
);
...
...
@@ -937,19 +950,18 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
/* Check that the protocol family is consistent. */
if
(
plen
>=
96
&&
v4mapped
(
dest
))
{
if
(
!
v4mapped
(
gate
))
{
if
(
!
v4mapped
(
gate
)
||
(
src_plen
>
0
&&
(
!
v4mapped
(
src
)
||
src_plen
<
96
)))
{
errno
=
EINVAL
;
return
-
1
;
}
}
else
{
if
(
v4mapped
(
gate
))
{
if
(
v4mapped
(
gate
)
||
(
src_plen
>
0
&&
v4mapped
(
src
))
)
{
errno
=
EINVAL
;
return
-
1
;
}
}
ipv4
=
v4mapped
(
gate
);
if
(
operation
==
ROUTE_MODIFY
)
{
if
(
newmetric
==
metric
&&
memcmp
(
newgate
,
gate
,
16
)
==
0
&&
newifindex
==
ifindex
)
...
...
@@ -961,9 +973,11 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
stick with the naive approach, and hope that the window is
small enough to be negligible. */
kernel_route
(
ROUTE_FLUSH
,
dest
,
plen
,
src
,
src_plen
,
gate
,
ifindex
,
metric
,
NULL
,
0
,
0
);
rc
=
kernel_route
(
ROUTE_ADD
,
dest
,
plen
,
src
,
src_plen
,
newgate
,
newifindex
,
newmetric
,
NULL
,
0
,
0
);
if
(
rc
<
0
)
{
...
...
@@ -975,11 +989,26 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
return
rc
;
}
kdebugf
(
"kernel_route: %s %s/%d metric %d dev %d nexthop %s
\n
"
,
ipv4
=
v4mapped
(
gate
);
if
(
src_plen
==
0
)
{
table
=
export_table
;
}
else
if
(
has_ipv6_subtrees
&&
!
ipv4
)
{
table
=
export_table
;
use_src
=
1
;
}
else
{
table
=
find_table
(
src
,
src_plen
);
if
(
table
<
0
)
return
-
1
;
}
kdebugf
(
"kernel_route: %s %s from %s "
"table %d metric %d dev %d nexthop %s
\n
"
,
operation
==
ROUTE_ADD
?
"add"
:
operation
==
ROUTE_FLUSH
?
"flush"
:
"???"
,
format_address
(
dest
),
plen
,
metric
,
ifindex
,
format_address
(
gate
));
format_prefix
(
dest
,
plen
),
format_prefix
(
src
,
src_plen
)
,
table
,
metric
,
ifindex
,
format_address
(
gate
));
/* Unreachable default routes cause all sort of weird interactions;
ignore them. */
...
...
@@ -998,7 +1027,9 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
rtm
=
NLMSG_DATA
(
&
buf
.
nh
);
rtm
->
rtm_family
=
ipv4
?
AF_INET
:
AF_INET6
;
rtm
->
rtm_dst_len
=
ipv4
?
plen
-
96
:
plen
;
rtm
->
rtm_table
=
export_table
;
if
(
use_src
)
rtm
->
rtm_src_len
=
src_plen
;
rtm
->
rtm_table
=
table
;
rtm
->
rtm_scope
=
RT_SCOPE_UNIVERSE
;
if
(
metric
<
KERNEL_INFINITY
)
rtm
->
rtm_type
=
RTN_UNICAST
;
...
...
@@ -1019,6 +1050,12 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
rta
->
rta_len
=
RTA_LENGTH
(
sizeof
(
struct
in6_addr
));
rta
->
rta_type
=
RTA_DST
;
memcpy
(
RTA_DATA
(
rta
),
dest
,
sizeof
(
struct
in6_addr
));
if
(
use_src
)
{
rta
=
RTA_NEXT
(
rta
,
len
);
rta
->
rta_len
=
RTA_LENGTH
(
sizeof
(
struct
in6_addr
));
rta
->
rta_type
=
RTA_SRC
;
memcpy
(
RTA_DATA
(
rta
),
src
,
sizeof
(
struct
in6_addr
));
}
}
rta
=
RTA_NEXT
(
rta
,
len
);
...
...
@@ -1058,19 +1095,16 @@ parse_kernel_route_rta(struct rtmsg *rtm, int len, struct kernel_route *route)
struct
rtattr
*
rta
=
RTM_RTA
(
rtm
);;
len
-=
NLMSG_ALIGN
(
sizeof
(
*
rtm
));
memset
(
&
route
->
prefix
,
0
,
sizeof
(
struct
in6_addr
));
memset
(
&
route
->
gw
,
0
,
sizeof
(
struct
in6_addr
));
route
->
plen
=
rtm
->
rtm_dst_len
;
memset
(
route
,
0
,
sizeof
(
struct
kernel_route
));
if
(
rtm
->
rtm_family
==
AF_INET
)
{
/* if RTA_DST is not a TLV, that's a default destination */
const
unsigned
char
zeroes
[
4
]
=
{
0
,
0
,
0
,
0
};
v4tov6
(
route
->
prefix
,
zeroes
);
route
->
plen
+
=
96
;
route
->
plen
=
96
;
}
route
->
metric
=
0
;
route
->
ifindex
=
0
;
route
->
proto
=
rtm
->
rtm_protocol
;
#define GET_PLEN(p) (rtm->rtm_family == AF_INET) ? p + 96 : p
#define COPY_ADDR(d, s) \
do { \
if(rtm->rtm_family == AF_INET6) \
...
...
@@ -1084,8 +1118,13 @@ parse_kernel_route_rta(struct rtmsg *rtm, int len, struct kernel_route *route)
while
(
RTA_OK
(
rta
,
len
))
{
switch
(
rta
->
rta_type
)
{
case
RTA_DST
:
route
->
plen
=
GET_PLEN
(
rtm
->
rtm_dst_len
);
COPY_ADDR
(
route
->
prefix
,
RTA_DATA
(
rta
));
break
;
case
RTA_SRC
:
route
->
src_plen
=
GET_PLEN
(
rtm
->
rtm_src_len
);
COPY_ADDR
(
route
->
src_prefix
,
RTA_DATA
(
rta
));
break
;
case
RTA_GATEWAY
:
COPY_ADDR
(
route
->
gw
,
RTA_DATA
(
rta
));
break
;
...
...
@@ -1106,6 +1145,7 @@ parse_kernel_route_rta(struct rtmsg *rtm, int len, struct kernel_route *route)
rta
=
RTA_NEXT
(
rta
,
len
);
}
#undef COPY_ADDR
#undef GET_PLEN
int
i
;
for
(
i
=
0
;
i
<
import_table_count
;
i
++
)
...
...
@@ -1120,6 +1160,7 @@ print_kernel_route(int add, int protocol, int type,
{
char
ifname
[
IFNAMSIZ
];
char
addr_prefix
[
INET6_ADDRSTRLEN
];
char
src_addr_prefix
[
INET6_ADDRSTRLEN
];
char
addr_gw
[
INET6_ADDRSTRLEN
];
if
(
!
inet_ntop
(
AF_INET6
,
route
->
prefix
,
...
...
@@ -1130,6 +1171,21 @@ print_kernel_route(int add, int protocol, int type,
return
;
}
if
(
route
->
src_plen
>=
0
)
{
if
(
!
inet_ntop
(
AF_INET6
,
route
->
src_prefix
,
src_addr_prefix
,
sizeof
(
src_addr_prefix
)))
{
kdebugf
(
"Couldn't format kernel route for printing."
);
return
;
}
kdebugf
(
"%s kernel route: dest: %s/%d gw: %s metric: %d if: %s "
"(proto: %d, type: %d, from: %s/%d)"
,
add
==
RTM_NEWROUTE
?
"Add"
:
"Delete"
,
addr_prefix
,
route
->
plen
,
addr_gw
,
route
->
metric
,
ifname
,
protocol
,
type
,
src_addr_prefix
,
route
->
src_plen
);
return
;
}
kdebugf
(
"%s kernel route: dest: %s/%d gw: %s metric: %d if: %s "
"(proto: %d, type: %d)"
,
add
==
RTM_NEWROUTE
?
"Add"
:
"Delete"
,
...
...
@@ -1174,9 +1230,6 @@ filter_kernel_routes(struct nlmsghdr *nh, void *data)
if
(
rtm
->
rtm_protocol
==
RTPROT_BABEL
)
return
0
;
if
(
rtm
->
rtm_src_len
!=
0
)
return
0
;
/* Ignore cached routes, advertised by some kernels (linux 3.x). */
if
(
rtm
->
rtm_flags
&
RTM_F_CLONED
)
return
0
;
...
...
@@ -1190,7 +1243,8 @@ filter_kernel_routes(struct nlmsghdr *nh, void *data)
if
(
rc
<
0
)
return
0
;
if
(
martian_prefix
(
current_route
->
prefix
,
current_route
->
plen
))
if
(
martian_prefix
(
current_route
->
prefix
,
current_route
->
plen
)
||
martian_prefix
(
current_route
->
src_prefix
,
current_route
->
src_plen
))
return
0
;
/* Ignore default unreachable routes; no idea where they come from. */
...
...
@@ -1219,6 +1273,7 @@ kernel_routes(struct kernel_route *routes, int maxroutes)
int
found
=
0
;
void
*
data
[
3
]
=
{
&
maxr
,
routes
,
&
found
};
int
families
[
2
]
=
{
AF_INET6
,
AF_INET
};
char
rule_exists
[
SRC_TABLE_NUM
]
=
{
0
};
struct
rtgenmsg
g
;
if
(
!
nl_setup
)
{
...
...
@@ -1244,9 +1299,19 @@ kernel_routes(struct kernel_route *routes, int maxroutes)
rc
=
netlink_read
(
&
nl_command
,
NULL
,
1
,
filter_kernel_routes
,
(
void
*
)
data
);
if
(
rc
<
0
)
return
-
1
;
rc
=
netlink_send_dump
(
RTM_GETRULE
,
&
g
,
sizeof
(
g
));
if
(
rc
<
0
)
return
-
1
;
rc
=
netlink_read
(
&
nl_command
,
NULL
,
1
,
filter_kernel_rules
,
rule_exists
);
if
(
rc
<
0
)
return
-
1
;
install_missing_rules
(
rule_exists
,
families
[
i
]
==
AF_INET
);
}
return
found
;
...
...
@@ -1341,6 +1406,10 @@ filter_link(struct nlmsghdr *nh, void *data)
return
0
;
}
/* If data is null, takes all addresses. If data is not null, takes
either link-local or global addresses depending of the value of
data[4]. */
static
int
filter_addresses
(
struct
nlmsghdr
*
nh
,
void
*
data
)
{
...
...
@@ -1380,7 +1449,7 @@ filter_addresses(struct nlmsghdr *nh, void *data)
if
(
rc
<
0
)
return
0
;
if
(
ll
==
!
IN6_IS_ADDR_LINKLOCAL
(
&
addr
))
if
(
data
&&
ll
==
!
IN6_IS_ADDR_LINKLOCAL
(
&
addr
))
return
0
;
if
(
ifindex
&&
ifa
->
ifa_index
!=
ifindex
)
...
...
@@ -1429,6 +1498,12 @@ filter_netlink(struct nlmsghdr *nh, void *data)
if
(
changed
&&
rc
>
0
)
*
changed
|=
CHANGE_ADDR
;
return
rc
;
case
RTM_NEWRULE
:
case
RTM_DELRULE
:
rc
=
filter_kernel_rules
(
nh
,
NULL
);
if
(
changed
&&
rc
>
0
)
*
changed
|=
CHANGE_RULE
;
return
rc
;
default:
kdebugf
(
"filter_netlink: unexpected message type %d
\n
"
,
nh
->
nlmsg_type
);
...
...
@@ -1504,3 +1579,430 @@ kernel_callback(int (*fn)(int, void*), void *closure)
return
0
;
}
/* Routing table's rules */
static
int
add_rule
(
int
prio
,
const
unsigned
char
*
src_prefix
,
int
src_plen
,
int
table
)
{
char
buffer
[
64
]
=
{
0
};
/* 56 needed */
struct
nlmsghdr
*
message_header
=
(
void
*
)
buffer
;
struct
rtmsg
*
message
=
NULL
;
struct
rtattr
*
current_attribute
=
NULL
;
int
is_v4
=
v4mapped
(
src_prefix
);
int
addr_size
=
is_v4
?
sizeof
(
struct
in_addr
)
:
sizeof
(
struct
in6_addr
);
kdebugf
(
"Add rule v%c prio %d from %s
\n
"
,
is_v4
?
'4'
:
'6'
,
prio
,
format_prefix
(
src_prefix
,
src_plen
));
if
(
is_v4
)
{
src_prefix
+=
12
;
src_plen
-=
96
;
if
(
src_plen
<
0
)
{
errno
=
EINVAL
;
return
-
1
;
}
}
#if RTA_ALIGNTO != NLMSG_ALIGNTO
#error "RTA_ALIGNTO != NLMSG_ALIGNTO"
#endif
/* Set the header */
message_header
->
nlmsg_flags
=
NLM_F_REQUEST
|
NLM_F_CREATE
|
NLM_F_EXCL
;
message_header
->
nlmsg_type
=
RTM_NEWRULE
;
message_header
->
nlmsg_len
=
NLMSG_ALIGN
(
sizeof
(
struct
nlmsghdr
));
/* Append the message */
message
=
NLMSG_DATA
(
message_header
);
message
->
rtm_family
=
is_v4
?
AF_INET
:
AF_INET6
;
message
->
rtm_dst_len
=
0
;
message
->
rtm_src_len
=
src_plen
;
message
->
rtm_tos
=
0
;
message
->
rtm_table
=
table
;
message
->
rtm_protocol
=
RTPROT_BABEL
;
message
->
rtm_scope
=
RT_SCOPE_UNIVERSE
;
message
->
rtm_type
=
RTN_UNICAST
;
message
->
rtm_flags
=
0
;
message_header
->
nlmsg_len
+=
NLMSG_ALIGN
(
sizeof
(
struct
rtmsg
));
/* Append each attribute */
current_attribute
=
RTM_RTA
(
message
);
/* prio */
current_attribute
->
rta_len
=
RTA_LENGTH
(
sizeof
(
int
));
current_attribute
->
rta_type
=
FRA_PRIORITY
;
*
(
int
*
)
RTA_DATA
(
current_attribute
)
=
prio
;
message_header
->
nlmsg_len
+=
current_attribute
->
rta_len
;
current_attribute
=
(
void
*
)
((
char
*
)
current_attribute
)
+
current_attribute
->
rta_len
;
/* src */
current_attribute
->
rta_len
=
RTA_LENGTH
(
addr_size
);
current_attribute
->
rta_type
=
FRA_SRC
;
memcpy
(
RTA_DATA
(
current_attribute
),
src_prefix
,
addr_size
);
message_header
->
nlmsg_len
+=
current_attribute
->
rta_len
;
current_attribute
=
(
void
*
)
((
char
*
)
current_attribute
)
+
current_attribute
->
rta_len
;
/* send message */
if
(
message_header
->
nlmsg_len
>
64
)
{
errno
=
EINVAL
;
return
-
1
;
}
return
netlink_talk
(
message_header
);
}
static
int
flush_rule
(
int
prio
,
int
family
)
{
char
buffer
[
64
]
=
{
0
};
/* 36 needed */
struct
nlmsghdr
*
message_header
=
(
void
*
)
buffer
;
struct
rtmsg
*
message
=
NULL
;
struct
rtattr
*
current_attribute
=
NULL
;
memset
(
buffer
,
0
,
sizeof
(
buffer
));
kdebugf
(
"Flush rule v%c prio %d
\n
"
,
family
==
AF_INET
?
'4'
:
'6'
,
prio
);
#if RTA_ALIGNTO != NLMSG_ALIGNTO
#error "RTA_ALIGNTO != NLMSG_ALIGNTO"
#endif
/* Set the header */
message_header
->
nlmsg_flags
=
NLM_F_REQUEST
;
message_header
->
nlmsg_type
=
RTM_DELRULE
;
message_header
->
nlmsg_len
=
NLMSG_ALIGN
(
sizeof
(
struct
nlmsghdr
));
/* Append the message */
message
=
NLMSG_DATA
(
message_header
);
message
->
rtm_family
=
family
;
message
->
rtm_dst_len
=
0
;
message
->
rtm_src_len
=
0
;
message
->
rtm_tos
=
0
;
message
->
rtm_table
=
0
;
message
->
rtm_protocol
=
RTPROT_BABEL
;
message
->
rtm_scope
=
RT_SCOPE_UNIVERSE
;
message
->
rtm_type
=
RTN_UNSPEC
;
message
->
rtm_flags
=
0
;
message_header
->
nlmsg_len
+=
NLMSG_ALIGN
(
sizeof
(
struct
rtmsg
));
/* Append each attribute */
current_attribute
=
RTM_RTA
(
message
);
/* prio */
current_attribute
->
rta_len
=
RTA_LENGTH
(
sizeof
(
int
));
current_attribute
->
rta_type
=
FRA_PRIORITY
;
*
(
int
*
)
RTA_DATA
(
current_attribute
)
=
prio
;
message_header
->
nlmsg_len
+=
current_attribute
->
rta_len
;
current_attribute
=
(
void
*
)
((
char
*
)
current_attribute
)
+
current_attribute
->
rta_len
;
/* send message */
if
(
message_header
->
nlmsg_len
>
64
)
{
errno
=
EINVAL
;
return
-
1
;
}
return
netlink_talk
(
message_header
);
}
/* Source specific functions and data structures */
/* The table used for non-specific routes is "export_table", therefore, we can
take the convention of plen == 0 <=> empty table. */
struct
kernel_table
{
unsigned
char
src
[
16
];
unsigned
char
plen
;
unsigned
char
table
;
};
/* kernel_tables contains informations about the rules we installed. It is an
array indexed by: <table priority> - src_table_prio.
(First entries are the most specific, since they have priority.) */
static
struct
kernel_table
kernel_tables
[
SRC_TABLE_NUM
];
/* used tables is indexed by: <table number> - src_table_idx
used_tables[i] == 1 <=> the table number (i + src_table_idx) is used */
static
char
used_tables
[
SRC_TABLE_NUM
]
=
{
0
};
static
unsigned
char
src_table_used
=
0
;
/* number of tables used */
static
inline
int
change_table_priority
(
const
unsigned
char
*
src
,
int
plen
,
int
table
,
int
old_prio
,
int
new_prio
)
{
int
rc
;
kdebugf
(
"/Swap: "
);
rc
=
add_rule
(
new_prio
,
src
,
plen
,
table
);
if
(
rc
<
0
)
return
rc
;
kdebugf
(
"
\\
Swap: "
);
return
flush_rule
(
old_prio
,
v4mapped
(
src
)
?
AF_INET
:
AF_INET6
);
}
/* Return a new table at index [idx] of kernel_tables. If cell at that index is
not free, we need to shift cells (and rules). If it's full, return NULL. */
static
struct
kernel_table
*
insert_table
(
const
unsigned
char
*
src
,
unsigned
short
src_plen
,
int
idx
)
{
int
table
;
int
rc
;
int
i
;
if
(
idx
<
0
||
idx
>=
SRC_TABLE_NUM
)
{
fprintf
(
stderr
,
"Incorrect table number %d
\n
"
,
idx
);
return
NULL
;
}
if
(
src_table_used
>=
SRC_TABLE_NUM
)
{
kdebugf
(
"All allowed routing tables are used!
\n
"
);
return
NULL
;
}
/* find a free table number */
for
(
table
=
0
;
table
<
SRC_TABLE_NUM
;
table
++
)
if
(
!
used_tables
[
table
])
break
;
table
+=
src_table_idx
;
/* Create the table's rule at the right place. Shift rules if necessary. */
if
(
kernel_tables
[
idx
].
plen
!=
0
)
{
/* shift right */
i
=
src_table_used
;
while
(
i
>
idx
)
{
i
--
;
rc
=
change_table_priority
(
kernel_tables
[
i
].
src
,
kernel_tables
[
i
].
plen
,
kernel_tables
[
i
].
table
,
i
+
src_table_prio
,
i
+
1
+
src_table_prio
);
if
(
rc
<
0
)
{
perror
(
"change_table_priority"
);
return
NULL
;
}
kernel_tables
[
i
+
1
]
=
kernel_tables
[
i
];
kernel_tables
[
i
].
plen
=
0
;
}
}
rc
=
add_rule
(
idx
+
src_table_prio
,
src
,
src_plen
,
table
);
if
(
rc
<
0
)
{
perror
(
"add rule"
);
return
NULL
;
}
used_tables
[
table
-
src_table_idx
]
=
1
;
memcpy
(
kernel_tables
[
idx
].
src
,
src
,
16
);
kernel_tables
[
idx
].
plen
=
src_plen
;
kernel_tables
[
idx
].
table
=
table
;
src_table_used
++
;
return
&
kernel_tables
[
idx
];
}
/* Sorting kernel_tables in a well ordered fashion will increase code complexity
and decrease performances, because more rule shifs will be required, so more
system calls invoked. */
static
int
find_table_slot
(
const
unsigned
char
*
src
,
unsigned
short
src_plen
,
int
*
new_return
)
{
struct
kernel_table
*
kt
=
NULL
;
int
i
;
*
new_return
=
-
1
;
for
(
i
=
0
;
i
<
SRC_TABLE_NUM
;
i
++
)
{
kt
=
&
kernel_tables
[
i
];
if
(
kt
->
plen
==
0
)
goto
new_table_here
;
/* empty table here */
switch
(
prefix_cmp
(
src
,
src_plen
,
kt
->
src
,
kt
->
plen
))
{
case
PST_LESS_SPECIFIC
:
case
PST_DISJOINT
:
continue
;
/* try to find a comparable route entry. */
case
PST_MORE_SPECIFIC
:
goto
new_table_here
;
case
PST_EQUALS
:
return
i
;
}
}
return
-
1
;
new_table_here:
*
new_return
=
i
;
return
-
1
;
}
static
int
find_table
(
const
unsigned
char
*
src
,
unsigned
short
src_plen
)
{
struct
kernel_table
*
kt
=
NULL
;
int
i
,
new_i
;
if
(
src_plen
==
0
||
(
has_ipv6_subtrees
&&
(
src_plen
<
96
||
!
v4mapped
(
src
))))
{
fprintf
(
stderr
,
"Find_table called for route handled by kernel "
"(this shouldn't happen)."
);
return
-
1
;
}
i
=
find_table_slot
(
src
,
src_plen
,
&
new_i
);
if
(
i
<
0
)
{
if
(
new_i
<
0
)
return
-
1
;
kt
=
insert_table
(
src
,
src_plen
,
new_i
);
}
else
{
kt
=
&
kernel_tables
[
i
];
}
return
kt
==
NULL
?
-
1
:
kt
->
table
;
}
static
void
release_tables
(
void
)
{
int
i
;
for
(
i
=
0
;
i
<
SRC_TABLE_NUM
;
i
++
)
{
if
(
kernel_tables
[
i
].
plen
!=
0
)
{
flush_rule
(
i
+
src_table_prio
,
v4mapped
(
kernel_tables
[
i
].
src
)
?
AF_INET
:
AF_INET6
);
kernel_tables
[
i
].
plen
=
0
;
}
used_tables
[
i
]
=
0
;
}
src_table_used
=
0
;
}
static
int
filter_kernel_rules
(
struct
nlmsghdr
*
nh
,
void
*
data
)
{
int
i
,
len
,
has_priority
=
0
;
unsigned
int
rta_len
;
struct
rtmsg
*
rtm
=
NULL
;
struct
rtattr
*
rta
=
NULL
;
int
is_v4
=
0
;
char
*
rule_exists
=
data
;
unsigned
char
src
[
16
];
unsigned
char
src_plen
;
unsigned
int
table
,
priority
=
0xFFFFFFFF
;
len
=
nh
->
nlmsg_len
;
rtm
=
(
struct
rtmsg
*
)
NLMSG_DATA
(
nh
);
len
-=
NLMSG_LENGTH
(
0
);
src_plen
=
rtm
->
rtm_src_len
;
table
=
rtm
->
rtm_table
;
if
(
rtm
->
rtm_family
!=
AF_INET
&&
rtm
->
rtm_family
!=
AF_INET6
)
{
kdebugf
(
"filter_rules: Unknown family: %d
\n
"
,
rtm
->
rtm_family
);
return
-
1
;
}
is_v4
=
rtm
->
rtm_family
==
AF_INET
;
rta
=
RTM_RTA
(
rtm
);
len
-=
NLMSG_ALIGN
(
sizeof
(
*
rtm
));
#define GET_PLEN(p) (rtm->rtm_family == AF_INET) ? p + 96 : p
#define COPY_ADDR(d, s) \
do { \
if(!is_v4) { \
if(UNLIKELY(rta_len < 16)) { \
fprintf(stderr, "filter_rules: truncated message."); \
return -1; \
} \
memcpy(d, s, 16); \
}else { \
if(UNLIKELY(rta_len < 4)) { \
fprintf(stderr, "filter_rules: truncated message."); \
return -1; \
} \
v4tov6(d, s); \
} \
} while(0)
for
(;
RTA_OK
(
rta
,
len
);
rta
=
RTA_NEXT
(
rta
,
len
))
{
rta_len
=
RTA_PAYLOAD
(
rta
);
switch
(
rta
->
rta_type
)
{
case
FRA_UNSPEC
:
break
;
case
FRA_SRC
:
src_plen
=
GET_PLEN
(
rtm
->
rtm_src_len
);
COPY_ADDR
(
src
,
RTA_DATA
(
rta
));
break
;
case
FRA_PRIORITY
:
priority
=
*
(
unsigned
int
*
)
RTA_DATA
(
rta
);
has_priority
=
1
;
break
;
case
FRA_TABLE
:
table
=
*
(
int
*
)
RTA_DATA
(
rta
);
break
;
default:
kdebugf
(
"filter_rules: Unknown rule attribute: %d.
\n
"
,
rta
->
rta_type
);
break
;
}
}
#undef COPY_ADDR
#undef GET_PLEN
kdebugf
(
"filter_rules: from %s prio %d table %d
\n
"
,
format_prefix
(
src
,
src_plen
),
priority
,
table
);
if
(
martian_prefix
(
src
,
src_plen
)
||
!
has_priority
)
return
0
;
i
=
priority
-
src_table_prio
;
if
(
i
<
0
||
SRC_TABLE_NUM
<=
i
)
return
0
;
/* There is an unexpected change on one of our rules. */
if
(
!
rule_exists
)
return
1
;
if
(
prefix_cmp
(
src
,
src_plen
,
kernel_tables
[
i
].
src
,
kernel_tables
[
i
].
plen
)
==
PST_EQUALS
&&
table
==
kernel_tables
[
i
].
table
&&
!
rule_exists
[
i
])
{
rule_exists
[
i
]
=
1
;
}
else
{
int
rc
;
do
{
rc
=
flush_rule
(
i
+
src_table_prio
,
is_v4
?
AF_INET
:
AF_INET6
);
}
while
(
rc
>=
0
);
/* flush unexpected rules, but keep information in kernel_tables[i]. It
will be used afterwards to reinstall the rule. */
if
(
errno
!=
ENOENT
&&
errno
!=
EEXIST
)
fprintf
(
stderr
,
"filter_rules: cannot remove from %s prio %d table %d"
"(%s)
\n
"
,
format_prefix
(
src
,
src_plen
),
priority
,
table
,
strerror
(
errno
));
rule_exists
[
i
]
=
0
;
}
return
1
;
}
/* This functions should be executed wrt the code just bellow: [rule_exists]
contains is a boolean array telling whether the rules we should have
installed in the kernel are installed or not. If they aren't, then reinstall
them (this can append when rules are modified by third parties). */
static
void
install_missing_rules
(
char
rule_exists
[
SRC_TABLE_NUM
],
int
v4
)
{
int
i
,
rc
;
for
(
i
=
0
;
i
<
SRC_TABLE_NUM
;
i
++
)
if
(
v4mapped
(
kernel_tables
[
i
].
src
)
==
v4
&&
!
rule_exists
[
i
]
&&
kernel_tables
[
i
].
plen
!=
0
)
{
rc
=
add_rule
(
i
+
src_table_prio
,
kernel_tables
[
i
].
src
,
kernel_tables
[
i
].
plen
,
kernel_tables
[
i
].
table
);
if
(
rc
<
0
)
fprintf
(
stderr
,
"install_missing_rules: "
"Cannot install rule: table %d prio %d from %s
\n
"
,
kernel_tables
[
i
].
table
,
i
+
src_table_prio
,
format_prefix
(
kernel_tables
[
i
].
src
,
kernel_tables
[
i
].
plen
));
}
}
kernel_socket.c
View file @
4a4d66da
...
...
@@ -29,8 +29,6 @@ THE SOFTWARE.
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <strings.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>
...
...
@@ -53,7 +51,6 @@ THE SOFTWARE.
static
int
get_sdl
(
struct
sockaddr_dl
*
sdl
,
char
*
ifname
);
static
const
unsigned
char
v4prefix
[
16
]
=
{
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0xFF
,
0xFF
,
0
,
0
,
0
,
0
};
...
...
@@ -387,6 +384,7 @@ kernel_interface_channel(const char *ifname, int ifindex)
int
kernel_route
(
int
operation
,
const
unsigned
char
*
dest
,
unsigned
short
plen
,
const
unsigned
char
*
src
,
unsigned
short
src_plen
,
const
unsigned
char
*
gate
,
int
ifindex
,
unsigned
int
metric
,
const
unsigned
char
*
newgate
,
int
newifindex
,
unsigned
int
newmetric
)
...
...
@@ -403,6 +401,12 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
{{{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x7f
,
0x00
,
0x00
,
0x01
}}};
/* Source-specific routes are not implemented yet for BSD. */
if
(
src_plen
>
0
)
{
errno
=
ENOSYS
;
return
-
1
;
}
/* Check that the protocol family is consistent. */
if
(
plen
>=
96
&&
v4mapped
(
dest
))
{
if
(
!
v4mapped
(
gate
))
{
...
...
@@ -427,9 +431,11 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
/* Avoid atomic route changes that is buggy on OS X. */
kernel_route
(
ROUTE_FLUSH
,
dest
,
plen
,
src
,
src_plen
,
gate
,
ifindex
,
metric
,
NULL
,
0
,
0
);
return
kernel_route
(
ROUTE_ADD
,
dest
,
plen
,
src
,
src_plen
,
newgate
,
newifindex
,
newmetric
,
NULL
,
0
,
0
);
...
...
local.c
View file @
4a4d66da
...
...
@@ -185,12 +185,14 @@ local_notify_xroute_1(int s, struct xroute *xroute, int kind)
{
char
buf
[
512
];
int
rc
;
const
char
*
dst_prefix
=
format_prefix
(
xroute
->
prefix
,
xroute
->
plen
);
const
char
*
src_prefix
=
format_prefix
(
xroute
->
src_prefix
,
xroute
->
src_plen
);
rc
=
snprintf
(
buf
,
512
,
"%s xroute %s prefix %s metric %d
\n
"
,
local_kind
(
kind
),
format_prefix
(
xroute
->
prefix
,
xroute
->
plen
),
format_prefix
(
xroute
->
prefix
,
xroute
->
plen
),
xroute
->
metric
);
rc
=
snprintf
(
buf
,
512
,
"%s xroute %s-%s prefix %s from %s metric %d
\n
"
,
local_kind
(
kind
),
dst_prefix
,
src_prefix
,
dst_prefix
,
src_prefix
,
xroute
->
metric
);
if
(
rc
<
0
||
rc
>=
512
)
goto
fail
;
...
...
@@ -218,14 +220,17 @@ local_notify_route_1(int s, struct babel_route *route, int kind)
{
char
buf
[
512
];
int
rc
;
const
char
*
dst_prefix
=
format_prefix
(
route
->
src
->
prefix
,
route
->
src
->
plen
);
const
char
*
src_prefix
=
format_prefix
(
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
);
rc
=
snprintf
(
buf
,
512
,
"%s route %s-%lx
prefix
%s installed %s "
"%s route %s-%lx
-%s prefix %s from
%s installed %s "
"id %s metric %d refmetric %d via %s if %s
\n
"
,
local_kind
(
kind
),
format_prefix
(
route
->
src
->
prefix
,
route
->
src
->
plen
),
(
unsigned
long
)
route
->
neigh
,
format_prefix
(
route
->
src
->
prefix
,
route
->
src
->
plen
),
dst_prefix
,
(
unsigned
long
)
route
->
neigh
,
src_prefix
,
dst_prefix
,
src_prefix
,
route
->
installed
?
"yes"
:
"no"
,
format_eui64
(
route
->
src
->
id
),
route_metric
(
route
),
route
->
refmetric
,
...
...
message.c
View file @
4a4d66da
...
...
@@ -541,8 +541,8 @@ parse_packet(const unsigned char *from, struct interface *ifp,
len
-
parsed_len
,
channels
);
}
update_route
(
router_id
,
prefix
,
plen
,
seqno
,
metric
,
interval
,
neigh
,
nh
,
update_route
(
router_id
,
prefix
,
plen
,
zeroes
,
0
,
seqno
,
metric
,
interval
,
neigh
,
nh
,
channels
,
channels_len
(
channels
));
}
else
if
(
type
==
MESSAGE_REQUEST
)
{
unsigned
char
prefix
[
16
],
plen
;
...
...
@@ -565,9 +565,9 @@ parse_packet(const unsigned char *from, struct interface *ifp,
shortly after we sent a full update. */
if
(
neigh
->
ifp
->
last_update_time
<
now
.
tv_sec
-
MAX
(
neigh
->
ifp
->
hello_interval
/
100
,
1
))
send_update
(
neigh
->
ifp
,
0
,
NULL
,
0
);
send_update
(
neigh
->
ifp
,
0
,
NULL
,
0
,
zeroes
,
0
);
}
else
{
send_update
(
neigh
->
ifp
,
0
,
prefix
,
plen
);
send_update
(
neigh
->
ifp
,
0
,
prefix
,
plen
,
zeroes
,
0
);
}
}
else
if
(
type
==
MESSAGE_MH_REQUEST
)
{
unsigned
char
prefix
[
16
],
plen
;
...
...
@@ -584,8 +584,162 @@ parse_packet(const unsigned char *from, struct interface *ifp,
format_prefix
(
prefix
,
plen
),
format_address
(
from
),
ifp
->
name
,
format_eui64
(
message
+
8
),
seqno
);
handle_request
(
neigh
,
prefix
,
plen
,
message
[
6
],
handle_request
(
neigh
,
prefix
,
plen
,
zeroes
,
0
,
message
[
6
],
seqno
,
message
+
8
);
}
else
if
(
type
==
MESSAGE_UPDATE_SRC_SPECIFIC
)
{
unsigned
char
prefix
[
16
],
src_prefix
[
16
],
*
nh
;
unsigned
char
ae
,
plen
,
src_plen
,
omitted
;
unsigned
char
channels
[
DIVERSITY_HOPS
];
unsigned
short
interval
,
seqno
,
metric
;
const
unsigned
char
*
src_prefix_beginning
=
NULL
;
int
rc
,
parsed_len
=
0
;
if
(
len
<
10
)
goto
fail
;
ae
=
message
[
2
];
src_plen
=
message
[
3
];
plen
=
message
[
4
];
omitted
=
message
[
5
];
DO_NTOHS
(
interval
,
message
+
6
);
DO_NTOHS
(
seqno
,
message
+
8
);
DO_NTOHS
(
metric
,
message
+
10
);
if
(
omitted
==
0
||
(
ae
==
1
?
have_v4_prefix
:
have_v6_prefix
))
rc
=
network_prefix
(
ae
,
plen
,
omitted
,
message
+
12
,
ae
==
1
?
v4_prefix
:
v6_prefix
,
len
-
10
,
prefix
);
else
rc
=
-
1
;
if
(
rc
<
0
)
goto
fail
;
parsed_len
=
10
+
rc
;
src_prefix_beginning
=
message
+
2
+
parsed_len
;
rc
=
network_prefix
(
ae
,
src_plen
,
0
,
src_prefix_beginning
,
NULL
,
len
-
parsed_len
,
src_prefix
);
if
(
rc
<
0
)
goto
fail
;
parsed_len
+=
rc
;
if
(
ae
==
1
)
{
plen
+=
96
;
src_plen
+=
96
;
}
if
(
!
have_router_id
)
{
fprintf
(
stderr
,
"Received prefix with no router id.
\n
"
);
goto
fail
;
}
debugf
(
"Received ss-update for (%s from %s) from %s on %s.
\n
"
,
format_prefix
(
prefix
,
plen
),
format_prefix
(
src_prefix
,
src_plen
),
format_address
(
from
),
ifp
->
name
);
if
(
ae
==
0
)
{
debugf
(
"Received invalid Source-Specific wildcard update.
\n
"
);
retract_neighbour_routes
(
neigh
);
goto
done
;
}
else
if
(
ae
==
1
)
{
if
(
!
have_v4_nh
)
goto
fail
;
nh
=
v4_nh
;
}
else
if
(
have_v6_nh
)
{
nh
=
v6_nh
;
}
else
{
nh
=
neigh
->
address
;
}
if
(
ae
==
1
)
{
if
(
!
ifp
->
ipv4
)
goto
done
;
}
if
((
ifp
->
flags
&
IF_FARAWAY
))
{
channels
[
0
]
=
0
;
}
else
{
/* This will be overwritten by parse_update_subtlv below. */
if
(
metric
<
256
)
{
/* Assume non-interfering (wired) link. */
channels
[
0
]
=
0
;
}
else
{
/* Assume interfering. */
channels
[
0
]
=
IF_CHANNEL_INTERFERING
;
channels
[
1
]
=
0
;
}
if
(
parsed_len
<
len
)
parse_update_subtlv
(
message
+
2
+
parsed_len
,
len
-
parsed_len
,
channels
);
}
update_route
(
router_id
,
prefix
,
plen
,
src_prefix
,
src_plen
,
seqno
,
metric
,
interval
,
neigh
,
nh
,
channels
,
channels_len
(
channels
));
}
else
if
(
type
==
MESSAGE_REQUEST_SRC_SPECIFIC
)
{
unsigned
char
prefix
[
16
],
plen
,
ae
,
src_prefix
[
16
],
src_plen
;
int
rc
,
parsed
=
5
;
if
(
len
<
3
)
goto
fail
;
ae
=
message
[
2
];
plen
=
message
[
3
];
src_plen
=
message
[
4
];
rc
=
network_prefix
(
ae
,
plen
,
0
,
message
+
parsed
,
NULL
,
len
+
2
-
parsed
,
prefix
);
if
(
rc
<
0
)
goto
fail
;
if
(
ae
==
1
)
plen
+=
96
;
parsed
+=
rc
;
rc
=
network_prefix
(
ae
,
src_plen
,
0
,
message
+
parsed
,
NULL
,
len
+
2
-
parsed
,
src_prefix
);
if
(
rc
<
0
)
goto
fail
;
if
(
ae
==
1
)
src_plen
+=
96
;
parsed
+=
rc
;
if
(
ae
==
0
)
{
debugf
(
"Received request for any source-specific "
"from %s on %s.
\n
"
,
format_address
(
from
),
ifp
->
name
);
/* See comments for std requests. */
send_ihu
(
neigh
,
NULL
);
if
(
neigh
->
ifp
->
last_specific_update_time
<
now
.
tv_sec
-
MAX
(
neigh
->
ifp
->
hello_interval
/
100
,
1
))
send_update
(
neigh
->
ifp
,
0
,
zeroes
,
0
,
NULL
,
0
);
}
else
{
debugf
(
"Received request for (%s from %s) from %s on %s.
\n
"
,
format_prefix
(
prefix
,
plen
),
format_prefix
(
src_prefix
,
src_plen
),
format_address
(
from
),
ifp
->
name
);
send_update
(
neigh
->
ifp
,
0
,
prefix
,
plen
,
src_prefix
,
src_plen
);
}
}
else
if
(
type
==
MESSAGE_MH_REQUEST_SRC_SPECIFIC
)
{
unsigned
char
prefix
[
16
],
plen
,
ae
,
src_prefix
[
16
],
src_plen
,
hopc
;
const
unsigned
char
*
router_id
;
unsigned
short
seqno
;
int
rc
,
parsed
=
16
;
if
(
len
<
14
)
goto
fail
;
ae
=
message
[
2
];
plen
=
message
[
3
];
DO_NTOHS
(
seqno
,
message
+
4
);
hopc
=
message
[
6
];
src_plen
=
message
[
7
];
router_id
=
message
+
8
;
rc
=
network_prefix
(
ae
,
plen
,
0
,
message
+
parsed
,
NULL
,
len
+
2
-
parsed
,
prefix
);
if
(
rc
<
0
)
goto
fail
;
if
(
ae
==
1
)
plen
+=
96
;
parsed
+=
rc
;
rc
=
network_prefix
(
ae
,
src_plen
,
0
,
message
+
parsed
,
NULL
,
len
+
2
-
parsed
,
src_prefix
);
if
(
rc
<
0
)
goto
fail
;
if
(
ae
==
1
)
src_plen
+=
96
;
debugf
(
"Received request (%d) for (%s, %s)"
" from %s on %s (%s, %d).
\n
"
,
message
[
6
],
format_prefix
(
prefix
,
plen
),
format_prefix
(
src_prefix
,
src_plen
),
format_address
(
from
),
ifp
->
name
,
format_eui64
(
router_id
),
seqno
);
handle_request
(
neigh
,
prefix
,
plen
,
src_prefix
,
src_plen
,
hopc
,
seqno
,
router_id
);
}
else
{
debugf
(
"Received unknown packet type %d from %s on %s.
\n
"
,
type
,
format_address
(
from
),
ifp
->
name
);
...
...
@@ -964,7 +1118,7 @@ flush_unicast(int dofree)
perror
(
"send(unicast)"
);
}
else
{
fprintf
(
stderr
,
"Warning: bucket full, dropping unicast packet"
"Warning: bucket full, dropping unicast packet
"
"to %s if %s.
\n
"
,
format_address
(
unicast_neighbour
->
address
),
unicast_neighbour
->
ifp
->
name
);
...
...
@@ -986,11 +1140,14 @@ static void
really_send_update
(
struct
interface
*
ifp
,
const
unsigned
char
*
id
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
unsigned
short
metric
,
unsigned
char
*
channels
,
int
channels_len
)
{
int
add_metric
,
v4
,
real_plen
,
omit
=
0
;
const
unsigned
char
*
real_prefix
;
const
unsigned
char
*
real_src_prefix
=
NULL
;
int
real_src_plen
=
0
;
unsigned
short
flags
=
0
;
int
channels_size
;
...
...
@@ -1002,13 +1159,14 @@ really_send_update(struct interface *ifp,
if
(
!
if_up
(
ifp
))
return
;
add_metric
=
output_filter
(
id
,
prefix
,
plen
,
ifp
->
ifindex
);
add_metric
=
output_filter
(
id
,
prefix
,
plen
,
src_prefix
,
src_plen
,
ifp
->
ifindex
);
if
(
add_metric
>=
INFINITY
)
return
;
metric
=
MIN
(
metric
+
add_metric
,
INFINITY
);
/* Worst case */
ensure_space
(
ifp
,
20
+
12
+
28
);
ensure_space
(
ifp
,
20
+
12
+
28
+
18
);
v4
=
plen
>=
96
&&
v4mapped
(
prefix
);
...
...
@@ -1028,20 +1186,27 @@ really_send_update(struct interface *ifp,
real_prefix
=
prefix
+
12
;
real_plen
=
plen
-
96
;
if
(
src_plen
!=
0
/* it should never be 96 */
)
{
real_src_prefix
=
src_prefix
+
12
;
real_src_plen
=
src_plen
-
96
;
}
}
else
{
if
(
ifp
->
have_buffered_prefix
)
{
while
(
omit
<
plen
/
8
&&
ifp
->
buffered_prefix
[
omit
]
==
prefix
[
omit
])
omit
++
;
}
if
(
!
ifp
->
have_buffered_prefix
||
plen
>=
48
)
if
(
src_plen
==
0
&&
(
!
ifp
->
have_buffered_prefix
||
plen
>=
48
)
)
flags
|=
0x80
;
real_prefix
=
prefix
;
real_plen
=
plen
;
real_src_prefix
=
src_prefix
;
real_src_plen
=
src_plen
;
}
if
(
!
ifp
->
have_buffered_id
||
memcmp
(
id
,
ifp
->
buffered_id
,
8
)
!=
0
)
{
if
(
real_plen
==
128
&&
memcmp
(
real_prefix
+
8
,
id
,
8
)
==
0
)
{
if
(
src_plen
==
0
&&
real_plen
==
128
&&
memcmp
(
real_prefix
+
8
,
id
,
8
)
==
0
)
{
flags
|=
0x40
;
}
else
{
start_message
(
ifp
,
MESSAGE_ROUTER_ID
,
10
);
...
...
@@ -1053,9 +1218,17 @@ really_send_update(struct interface *ifp,
ifp
->
have_buffered_id
=
1
;
}
if
(
src_plen
==
0
)
start_message
(
ifp
,
MESSAGE_UPDATE
,
10
+
(
real_plen
+
7
)
/
8
-
omit
+
channels_size
);
else
start_message
(
ifp
,
MESSAGE_UPDATE_SRC_SPECIFIC
,
10
+
(
real_plen
+
7
)
/
8
-
omit
+
(
real_src_plen
+
7
)
/
8
+
channels_size
);
accumulate_byte
(
ifp
,
v4
?
1
:
2
);
if
(
src_plen
!=
0
)
accumulate_byte
(
ifp
,
real_src_plen
);
else
accumulate_byte
(
ifp
,
flags
);
accumulate_byte
(
ifp
,
real_plen
);
accumulate_byte
(
ifp
,
omit
);
...
...
@@ -1063,14 +1236,21 @@ really_send_update(struct interface *ifp,
accumulate_short
(
ifp
,
seqno
);
accumulate_short
(
ifp
,
metric
);
accumulate_bytes
(
ifp
,
real_prefix
+
omit
,
(
real_plen
+
7
)
/
8
-
omit
);
if
(
src_plen
!=
0
)
accumulate_bytes
(
ifp
,
real_src_prefix
,
(
real_src_plen
+
7
)
/
8
);
/* Note that an empty channels TLV is different from no such TLV. */
if
(
channels_len
>=
0
)
{
accumulate_byte
(
ifp
,
2
);
accumulate_byte
(
ifp
,
channels_len
);
accumulate_bytes
(
ifp
,
channels
,
channels_len
);
}
if
(
src_plen
==
0
)
end_message
(
ifp
,
MESSAGE_UPDATE
,
10
+
(
real_plen
+
7
)
/
8
-
omit
+
channels_size
);
else
end_message
(
ifp
,
MESSAGE_UPDATE_SRC_SPECIFIC
,
10
+
(
real_plen
+
7
)
/
8
-
omit
+
(
real_src_plen
+
7
)
/
8
+
channels_size
);
if
(
flags
&
0x80
)
{
memcpy
(
ifp
->
buffered_prefix
,
prefix
,
16
);
...
...
@@ -1109,7 +1289,16 @@ compare_buffered_updates(const void *av, const void *bv)
else
if
(
a
->
plen
>
b
->
plen
)
return
-
1
;
return
memcmp
(
a
->
prefix
,
b
->
prefix
,
16
);
rc
=
memcmp
(
a
->
prefix
,
b
->
prefix
,
16
);
if
(
rc
!=
0
)
return
rc
;
if
(
a
->
src_plen
<
b
->
src_plen
)
return
-
1
;
else
if
(
a
->
src_plen
>
b
->
src_plen
)
return
1
;
return
memcmp
(
a
->
src_prefix
,
b
->
src_prefix
,
16
);
}
void
...
...
@@ -1118,7 +1307,9 @@ flushupdates(struct interface *ifp)
struct
xroute
*
xroute
;
struct
babel_route
*
route
;
const
unsigned
char
*
last_prefix
=
NULL
;
const
unsigned
char
*
last_src_prefix
=
NULL
;
unsigned
char
last_plen
=
0xFF
;
unsigned
char
last_src_plen
=
0xFF
;
int
i
;
if
(
ifp
==
NULL
)
{
...
...
@@ -1146,7 +1337,8 @@ flushupdates(struct interface *ifp)
with the same router-id together, with IPv6 going out before IPv4. */
for
(
i
=
0
;
i
<
n
;
i
++
)
{
route
=
find_installed_route
(
b
[
i
].
prefix
,
b
[
i
].
plen
);
route
=
find_installed_route
(
b
[
i
].
prefix
,
b
[
i
].
plen
,
b
[
i
].
src_prefix
,
b
[
i
].
src_plen
);
if
(
route
)
memcpy
(
b
[
i
].
id
,
route
->
src
->
id
,
8
);
else
...
...
@@ -1160,22 +1352,28 @@ flushupdates(struct interface *ifp)
sent out. Since our buffer is now sorted, it is enough to
compare with the previous update. */
if
(
last_prefix
)
{
if
(
b
[
i
].
plen
==
last_plen
&&
memcmp
(
b
[
i
].
prefix
,
last_prefix
,
16
)
==
0
)
if
(
last_prefix
&&
b
[
i
].
plen
==
last_plen
&&
b
[
i
].
src_plen
==
last_src_plen
&&
memcmp
(
b
[
i
].
prefix
,
last_prefix
,
16
)
==
0
&&
memcmp
(
b
[
i
].
src_prefix
,
last_src_prefix
,
16
)
==
0
)
continue
;
}
xroute
=
find_xroute
(
b
[
i
].
prefix
,
b
[
i
].
plen
);
route
=
find_installed_route
(
b
[
i
].
prefix
,
b
[
i
].
plen
);
xroute
=
find_xroute
(
b
[
i
].
prefix
,
b
[
i
].
plen
,
b
[
i
].
src_prefix
,
b
[
i
].
src_plen
);
route
=
find_installed_route
(
b
[
i
].
prefix
,
b
[
i
].
plen
,
b
[
i
].
src_prefix
,
b
[
i
].
src_plen
);
if
(
xroute
&&
(
!
route
||
xroute
->
metric
<=
kernel_metric
))
{
really_send_update
(
ifp
,
myid
,
xroute
->
prefix
,
xroute
->
plen
,
xroute
->
src_prefix
,
xroute
->
src_plen
,
myseqno
,
xroute
->
metric
,
NULL
,
0
);
last_prefix
=
xroute
->
prefix
;
last_plen
=
xroute
->
plen
;
last_src_prefix
=
xroute
->
src_prefix
;
last_src_plen
=
xroute
->
src_plen
;
}
else
if
(
route
)
{
unsigned
char
channels
[
DIVERSITY_HOPS
];
int
chlen
;
...
...
@@ -1191,6 +1389,8 @@ flushupdates(struct interface *ifp)
if
(
metric
<
INFINITY
)
satisfy_request
(
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
,
seqno
,
route
->
src
->
id
,
ifp
);
if
((
ifp
->
flags
&
IF_SPLIT_HORIZON
)
&&
...
...
@@ -1212,17 +1412,20 @@ flushupdates(struct interface *ifp)
chlen
=
channels_len
(
channels
);
really_send_update
(
ifp
,
route
->
src
->
id
,
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_
plen
,
seqno
,
metric
,
channels
,
chlen
);
update_source
(
route
->
src
,
seqno
,
metric
);
last_prefix
=
route
->
src
->
prefix
;
last_plen
=
route
->
src
->
plen
;
last_src_prefix
=
route
->
src
->
src_prefix
;
last_src_plen
=
route
->
src
->
src_plen
;
}
else
{
/* There's no route for this prefix. This can happen shortly
after an xroute has been retracted, so send a retraction. */
really_send_update
(
ifp
,
myid
,
b
[
i
].
prefix
,
b
[
i
].
plen
,
b
[
i
].
src_prefix
,
b
[
i
].
src_plen
,
myseqno
,
INFINITY
,
NULL
,
-
1
);
}
}
...
...
@@ -1247,7 +1450,8 @@ schedule_update_flush(struct interface *ifp, int urgent)
static
void
buffer_update
(
struct
interface
*
ifp
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
)
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
)
{
if
(
ifp
->
num_buffered_updates
>
0
&&
ifp
->
num_buffered_updates
>=
ifp
->
update_bufsize
)
...
...
@@ -1279,25 +1483,32 @@ buffer_update(struct interface *ifp,
memcpy
(
ifp
->
buffered_updates
[
ifp
->
num_buffered_updates
].
prefix
,
prefix
,
16
);
ifp
->
buffered_updates
[
ifp
->
num_buffered_updates
].
plen
=
plen
;
memcpy
(
ifp
->
buffered_updates
[
ifp
->
num_buffered_updates
].
src_prefix
,
src_prefix
,
16
);
ifp
->
buffered_updates
[
ifp
->
num_buffered_updates
].
src_plen
=
src_plen
;
ifp
->
num_buffered_updates
++
;
}
/* Full wildcard update with prefix == src_prefix == NULL,
Standard wildcard update with prefix == NULL && src_prefix != NULL,
Specific wildcard update with prefix != NULL && src_prefix == NULL. */
void
send_update
(
struct
interface
*
ifp
,
int
urgent
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
)
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
)
{
if
(
ifp
==
NULL
)
{
struct
interface
*
ifp_aux
;
struct
babel_route
*
route
;
FOR_ALL_INTERFACES
(
ifp_aux
)
send_update
(
ifp_aux
,
urgent
,
prefix
,
plen
);
send_update
(
ifp_aux
,
urgent
,
prefix
,
plen
,
src_prefix
,
src_plen
);
if
(
prefix
)
{
/* Since flushupdates only deals with non-wildcard interfaces, we
need to do this now. */
route
=
find_installed_route
(
prefix
,
plen
);
route
=
find_installed_route
(
prefix
,
plen
,
src_prefix
,
src_plen
);
if
(
route
&&
route_metric
(
route
)
<
INFINITY
)
satisfy_request
(
prefix
,
plen
,
route
->
src
->
seqno
,
route
->
src
->
id
,
NULL
);
satisfy_request
(
prefix
,
plen
,
src_prefix
,
src_plen
,
route
->
src
->
seqno
,
route
->
src
->
id
,
NULL
);
}
return
;
}
...
...
@@ -1305,11 +1516,12 @@ send_update(struct interface *ifp, int urgent,
if
(
!
if_up
(
ifp
))
return
;
if
(
prefix
)
{
debugf
(
"Sending update to %s for %s.
\n
"
,
ifp
->
name
,
format_prefix
(
prefix
,
plen
));
buffer_update
(
ifp
,
prefix
,
plen
);
}
else
{
if
(
prefix
&&
src_prefix
)
{
debugf
(
"Sending update to %s for %s from %s.
\n
"
,
ifp
->
name
,
format_prefix
(
prefix
,
plen
),
format_prefix
(
src_prefix
,
src_plen
));
buffer_update
(
ifp
,
prefix
,
plen
,
src_prefix
,
src_plen
);
}
else
if
(
prefix
||
src_prefix
)
{
struct
route_stream
*
routes
;
send_self_update
(
ifp
);
debugf
(
"Sending update to %s for any.
\n
"
,
ifp
->
name
);
...
...
@@ -1319,26 +1531,38 @@ send_update(struct interface *ifp, int urgent,
struct
babel_route
*
route
=
route_stream_next
(
routes
);
if
(
route
==
NULL
)
break
;
buffer_update
(
ifp
,
route
->
src
->
prefix
,
route
->
src
->
plen
);
if
((
src_prefix
&&
route
->
src
->
src_plen
!=
0
)
||
(
prefix
&&
route
->
src
->
src_plen
==
0
))
continue
;
buffer_update
(
ifp
,
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
);
}
route_stream_done
(
routes
);
}
else
{
fprintf
(
stderr
,
"Couldn't allocate route stream.
\n
"
);
}
set_timeout
(
&
ifp
->
update_timeout
,
ifp
->
update_interval
);
if
(
!
prefix
)
ifp
->
last_update_time
=
now
.
tv_sec
;
else
ifp
->
last_specific_update_time
=
now
.
tv_sec
;
}
else
{
send_update
(
ifp
,
urgent
,
NULL
,
0
,
zeroes
,
0
);
send_update
(
ifp
,
urgent
,
zeroes
,
0
,
NULL
,
0
);
}
schedule_update_flush
(
ifp
,
urgent
);
}
void
send_update_resend
(
struct
interface
*
ifp
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
)
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
)
{
assert
(
prefix
!=
NULL
);
send_update
(
ifp
,
1
,
prefix
,
plen
);
record_resend
(
RESEND_UPDATE
,
prefix
,
plen
,
0
,
NULL
,
NULL
,
resend_delay
);
send_update
(
ifp
,
1
,
prefix
,
plen
,
src_prefix
,
src_plen
);
record_resend
(
RESEND_UPDATE
,
prefix
,
plen
,
src_prefix
,
src_plen
,
0
,
NULL
,
NULL
,
resend_delay
);
}
void
...
...
@@ -1394,7 +1618,8 @@ send_self_update(struct interface *ifp)
while
(
1
)
{
struct
xroute
*
xroute
=
xroute_stream_next
(
xroutes
);
if
(
xroute
==
NULL
)
break
;
send_update
(
ifp
,
0
,
xroute
->
prefix
,
xroute
->
plen
);
send_update
(
ifp
,
0
,
xroute
->
prefix
,
xroute
->
plen
,
xroute
->
src_prefix
,
xroute
->
src_plen
);
}
xroute_stream_done
(
xroutes
);
}
else
{
...
...
@@ -1518,18 +1743,21 @@ send_marginal_ihu(struct interface *ifp)
}
}
/* Standard wildcard request with prefix == NULL && src_prefix == zeroes,
Specific wildcard request with prefix == zeroes && src_prefix == NULL. */
void
send_request
(
struct
interface
*
ifp
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
)
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
)
{
int
v4
,
pb
,
len
;
int
v4
,
pb
,
spb
,
len
;
if
(
ifp
==
NULL
)
{
struct
interface
*
ifp_auxn
;
FOR_ALL_INTERFACES
(
ifp_auxn
)
{
if
(
if_up
(
ifp_auxn
))
continue
;
send_request
(
ifp_auxn
,
prefix
,
plen
);
send_request
(
ifp_auxn
,
prefix
,
plen
,
src_prefix
,
src_plen
);
}
return
;
}
...
...
@@ -1540,49 +1768,128 @@ send_request(struct interface *ifp,
if
(
!
if_up
(
ifp
))
return
;
debugf
(
"sending request to %s for %s.
\n
"
,
ifp
->
name
,
prefix
?
format_prefix
(
prefix
,
plen
)
:
"any"
);
if
(
prefix
&&
src_prefix
)
{
debugf
(
"sending request to %s for %s from %s.
\n
"
,
ifp
->
name
,
format_prefix
(
prefix
,
plen
),
format_prefix
(
src_prefix
,
src_plen
));
}
else
if
(
prefix
)
{
debugf
(
"sending request to %s for any specific.
\n
"
,
ifp
->
name
);
start_message
(
ifp
,
MESSAGE_REQUEST_SRC_SPECIFIC
,
3
);
accumulate_byte
(
ifp
,
0
);
accumulate_byte
(
ifp
,
0
);
accumulate_byte
(
ifp
,
0
);
end_message
(
ifp
,
MESSAGE_REQUEST_SRC_SPECIFIC
,
3
);
return
;
}
else
if
(
src_prefix
)
{
debugf
(
"sending request to %s for any.
\n
"
,
ifp
->
name
);
start_message
(
ifp
,
MESSAGE_REQUEST
,
2
);
accumulate_byte
(
ifp
,
0
);
accumulate_byte
(
ifp
,
0
);
end_message
(
ifp
,
MESSAGE_REQUEST
,
2
);
return
;
}
else
{
send_request
(
ifp
,
NULL
,
0
,
zeroes
,
0
);
send_request
(
ifp
,
zeroes
,
0
,
NULL
,
0
);
return
;
}
v4
=
plen
>=
96
&&
v4mapped
(
prefix
);
pb
=
v4
?
((
plen
-
96
)
+
7
)
/
8
:
(
plen
+
7
)
/
8
;
len
=
!
prefix
?
2
:
2
+
pb
;
len
=
2
+
pb
;
if
(
src_plen
!=
0
)
{
spb
=
v4
?
((
src_plen
-
96
)
+
7
)
/
8
:
(
src_plen
+
7
)
/
8
;
len
+=
spb
+
1
;
start_message
(
ifp
,
MESSAGE_REQUEST_SRC_SPECIFIC
,
len
);
}
else
{
start_message
(
ifp
,
MESSAGE_REQUEST
,
len
);
accumulate_byte
(
ifp
,
!
prefix
?
0
:
v4
?
1
:
2
);
accumulate_byte
(
ifp
,
!
prefix
?
0
:
v4
?
plen
-
96
:
plen
);
if
(
prefix
)
{
}
accumulate_byte
(
ifp
,
v4
?
1
:
2
);
accumulate_byte
(
ifp
,
v4
?
plen
-
96
:
plen
);
if
(
src_plen
!=
0
)
accumulate_byte
(
ifp
,
v4
?
src_plen
-
96
:
src_plen
);
if
(
v4
)
accumulate_bytes
(
ifp
,
prefix
+
12
,
pb
);
else
accumulate_bytes
(
ifp
,
prefix
,
pb
);
if
(
src_plen
!=
0
)
{
if
(
v4
)
accumulate_bytes
(
ifp
,
src_prefix
+
12
,
spb
);
else
accumulate_bytes
(
ifp
,
src_prefix
,
spb
);
end_message
(
ifp
,
MESSAGE_REQUEST_SRC_SPECIFIC
,
len
);
return
;
}
end_message
(
ifp
,
MESSAGE_REQUEST
,
len
);
}
void
send_unicast_request
(
struct
neighbour
*
neigh
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
)
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
)
{
int
rc
,
v4
,
pb
,
len
;
int
rc
,
v4
,
pb
,
spb
,
len
;
/* make sure any buffered updates go out before this request. */
flushupdates
(
neigh
->
ifp
);
debugf
(
"sending unicast request to %s for %s.
\n
"
,
if
(
prefix
&&
src_prefix
)
{
debugf
(
"sending unicast request to %s for %s from %s.
\n
"
,
format_address
(
neigh
->
address
),
prefix
?
format_prefix
(
prefix
,
plen
)
:
"any"
);
format_prefix
(
prefix
,
plen
),
format_prefix
(
src_prefix
,
src_plen
));
}
else
if
(
prefix
)
{
debugf
(
"sending unicast request to %s for any specific.
\n
"
,
format_address
(
neigh
->
address
));
rc
=
start_unicast_message
(
neigh
,
MESSAGE_REQUEST_SRC_SPECIFIC
,
3
);
if
(
rc
<
0
)
return
;
accumulate_unicast_byte
(
neigh
,
0
);
accumulate_unicast_byte
(
neigh
,
0
);
accumulate_unicast_byte
(
neigh
,
0
);
end_unicast_message
(
neigh
,
MESSAGE_REQUEST_SRC_SPECIFIC
,
3
);
return
;
}
else
if
(
src_prefix
)
{
debugf
(
"sending unicast request to %s for any.
\n
"
,
format_address
(
neigh
->
address
));
rc
=
start_unicast_message
(
neigh
,
MESSAGE_REQUEST
,
2
);
if
(
rc
<
0
)
return
;
accumulate_unicast_byte
(
neigh
,
0
);
accumulate_unicast_byte
(
neigh
,
0
);
end_unicast_message
(
neigh
,
MESSAGE_REQUEST
,
2
);
return
;
}
else
{
send_unicast_request
(
neigh
,
NULL
,
0
,
zeroes
,
0
);
send_unicast_request
(
neigh
,
zeroes
,
0
,
NULL
,
0
);
return
;
}
v4
=
plen
>=
96
&&
v4mapped
(
prefix
);
pb
=
v4
?
((
plen
-
96
)
+
7
)
/
8
:
(
plen
+
7
)
/
8
;
len
=
!
prefix
?
2
:
2
+
pb
;
len
=
2
+
pb
;
if
(
src_plen
!=
0
)
{
spb
=
v4
?
((
src_plen
-
96
)
+
7
)
/
8
:
(
src_plen
+
7
)
/
8
;
len
+=
spb
+
1
;
rc
=
start_unicast_message
(
neigh
,
MESSAGE_REQUEST_SRC_SPECIFIC
,
len
);
}
else
{
rc
=
start_unicast_message
(
neigh
,
MESSAGE_REQUEST
,
len
);
}
if
(
rc
<
0
)
return
;
accumulate_unicast_byte
(
neigh
,
!
prefix
?
0
:
v4
?
1
:
2
);
accumulate_unicast_byte
(
neigh
,
!
prefix
?
0
:
v4
?
plen
-
96
:
plen
);
if
(
prefix
)
{
accumulate_unicast_byte
(
neigh
,
v4
?
1
:
2
);
accumulate_unicast_byte
(
neigh
,
v4
?
plen
-
96
:
plen
);
if
(
src_plen
!=
0
)
accumulate_unicast_byte
(
neigh
,
v4
?
src_plen
-
96
:
src_plen
);
if
(
v4
)
accumulate_unicast_bytes
(
neigh
,
prefix
+
12
,
pb
);
else
accumulate_unicast_bytes
(
neigh
,
prefix
,
pb
);
if
(
src_plen
!=
0
)
{
if
(
v4
)
accumulate_unicast_bytes
(
neigh
,
src_prefix
+
12
,
spb
);
else
accumulate_unicast_bytes
(
neigh
,
src_prefix
,
spb
);
end_unicast_message
(
neigh
,
MESSAGE_REQUEST_SRC_SPECIFIC
,
len
);
return
;
}
end_unicast_message
(
neigh
,
MESSAGE_REQUEST
,
len
);
}
...
...
@@ -1590,10 +1897,11 @@ send_unicast_request(struct neighbour *neigh,
void
send_multihop_request
(
struct
interface
*
ifp
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
const
unsigned
char
*
id
,
unsigned
short
hop_count
)
{
int
v4
,
pb
,
len
;
int
v4
,
pb
,
spb
,
len
;
/* Make sure any buffered updates go out before this request. */
flushupdates
(
ifp
);
...
...
@@ -1603,7 +1911,8 @@ send_multihop_request(struct interface *ifp,
FOR_ALL_INTERFACES
(
ifp_aux
)
{
if
(
!
if_up
(
ifp_aux
))
continue
;
send_multihop_request
(
ifp_aux
,
prefix
,
plen
,
seqno
,
id
,
hop_count
);
send_multihop_request
(
ifp_aux
,
prefix
,
plen
,
src_prefix
,
src_plen
,
seqno
,
id
,
hop_count
);
}
return
;
}
...
...
@@ -1611,18 +1920,25 @@ send_multihop_request(struct interface *ifp,
if
(
!
if_up
(
ifp
))
return
;
debugf
(
"Sending request (%d) on %s for %s.
\n
"
,
hop_count
,
ifp
->
name
,
format_prefix
(
prefix
,
plen
));
debugf
(
"Sending request (%d) on %s for %s from %s.
\n
"
,
hop_count
,
ifp
->
name
,
format_prefix
(
prefix
,
plen
),
format_prefix
(
src_prefix
,
src_plen
));
v4
=
plen
>=
96
&&
v4mapped
(
prefix
);
pb
=
v4
?
((
plen
-
96
)
+
7
)
/
8
:
(
plen
+
7
)
/
8
;
len
=
6
+
8
+
pb
;
if
(
src_plen
!=
0
)
{
spb
=
v4
?
((
src_plen
-
96
)
+
7
)
/
8
:
(
src_plen
+
7
)
/
8
;
len
+=
spb
;
start_message
(
ifp
,
MESSAGE_MH_REQUEST_SRC_SPECIFIC
,
len
);
}
else
{
start_message
(
ifp
,
MESSAGE_MH_REQUEST
,
len
);
}
accumulate_byte
(
ifp
,
v4
?
1
:
2
);
accumulate_byte
(
ifp
,
v4
?
plen
-
96
:
plen
);
accumulate_short
(
ifp
,
seqno
);
accumulate_byte
(
ifp
,
hop_count
);
accumulate_byte
(
ifp
,
0
);
accumulate_byte
(
ifp
,
v4
?
src_plen
-
96
:
src_plen
);
accumulate_bytes
(
ifp
,
id
,
8
);
if
(
prefix
)
{
if
(
v4
)
...
...
@@ -1630,34 +1946,51 @@ send_multihop_request(struct interface *ifp,
else
accumulate_bytes
(
ifp
,
prefix
,
pb
);
}
if
(
src_plen
!=
0
)
{
if
(
v4
)
accumulate_bytes
(
ifp
,
src_prefix
+
12
,
spb
);
else
accumulate_bytes
(
ifp
,
src_prefix
,
spb
);
end_message
(
ifp
,
MESSAGE_MH_REQUEST_SRC_SPECIFIC
,
len
);
return
;
}
end_message
(
ifp
,
MESSAGE_MH_REQUEST
,
len
);
}
void
send_unicast_multihop_request
(
struct
neighbour
*
neigh
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
const
unsigned
char
*
id
,
unsigned
short
hop_count
)
{
int
rc
,
v4
,
pb
,
len
;
int
rc
,
v4
,
pb
,
spb
,
len
;
/* Make sure any buffered updates go out before this request. */
flushupdates
(
neigh
->
ifp
);
debugf
(
"Sending multi-hop request to %s for %s (%d hops).
\n
"
,
debugf
(
"Sending multi-hop request to %s for %s
from %s
(%d hops).
\n
"
,
format_address
(
neigh
->
address
),
format_prefix
(
prefix
,
plen
),
hop_count
);
format_prefix
(
prefix
,
plen
),
format_prefix
(
src_prefix
,
src_plen
),
hop_count
);
v4
=
plen
>=
96
&&
v4mapped
(
prefix
);
pb
=
v4
?
((
plen
-
96
)
+
7
)
/
8
:
(
plen
+
7
)
/
8
;
len
=
6
+
8
+
pb
;
if
(
src_plen
!=
0
)
{
spb
=
v4
?
((
src_plen
-
96
)
+
7
)
/
8
:
(
src_plen
+
7
)
/
8
;
len
+=
spb
;
rc
=
start_unicast_message
(
neigh
,
MESSAGE_MH_REQUEST_SRC_SPECIFIC
,
len
);
}
else
{
rc
=
start_unicast_message
(
neigh
,
MESSAGE_MH_REQUEST
,
len
);
}
if
(
rc
<
0
)
return
;
accumulate_unicast_byte
(
neigh
,
v4
?
1
:
2
);
accumulate_unicast_byte
(
neigh
,
v4
?
plen
-
96
:
plen
);
accumulate_unicast_short
(
neigh
,
seqno
);
accumulate_unicast_byte
(
neigh
,
hop_count
);
accumulate_unicast_byte
(
neigh
,
0
);
accumulate_unicast_byte
(
neigh
,
v4
?
src_plen
-
96
:
src_plen
);
accumulate_unicast_bytes
(
neigh
,
id
,
8
);
if
(
prefix
)
{
if
(
v4
)
...
...
@@ -1665,34 +1998,47 @@ send_unicast_multihop_request(struct neighbour *neigh,
else
accumulate_unicast_bytes
(
neigh
,
prefix
,
pb
);
}
if
(
src_plen
!=
0
)
{
if
(
v4
)
accumulate_unicast_bytes
(
neigh
,
src_prefix
+
12
,
spb
);
else
accumulate_unicast_bytes
(
neigh
,
src_prefix
,
spb
);
end_unicast_message
(
neigh
,
MESSAGE_MH_REQUEST_SRC_SPECIFIC
,
len
);
return
;
}
end_unicast_message
(
neigh
,
MESSAGE_MH_REQUEST
,
len
);
}
void
send_request_resend
(
struct
neighbour
*
neigh
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
unsigned
char
*
id
)
{
if
(
neigh
)
send_unicast_multihop_request
(
neigh
,
prefix
,
plen
,
seqno
,
id
,
127
);
send_unicast_multihop_request
(
neigh
,
prefix
,
plen
,
src_prefix
,
src_plen
,
seqno
,
id
,
127
);
else
send_multihop_request
(
NULL
,
prefix
,
plen
,
seqno
,
id
,
127
);
send_multihop_request
(
NULL
,
prefix
,
plen
,
src_prefix
,
src_plen
,
seqno
,
id
,
127
);
record_resend
(
RESEND_REQUEST
,
prefix
,
plen
,
seqno
,
id
,
record_resend
(
RESEND_REQUEST
,
prefix
,
plen
,
s
rc_prefix
,
src_plen
,
s
eqno
,
id
,
neigh
?
neigh
->
ifp
:
NULL
,
resend_delay
);
}
void
handle_request
(
struct
neighbour
*
neigh
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
unsigned
char
hop_count
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
char
hop_count
,
unsigned
short
seqno
,
const
unsigned
char
*
id
)
{
struct
xroute
*
xroute
;
struct
babel_route
*
route
;
struct
neighbour
*
successor
=
NULL
;
xroute
=
find_xroute
(
prefix
,
plen
);
route
=
find_installed_route
(
prefix
,
plen
);
xroute
=
find_xroute
(
prefix
,
plen
,
src_prefix
,
src_plen
);
route
=
find_installed_route
(
prefix
,
plen
,
src_prefix
,
src_plen
);
if
(
xroute
&&
(
!
route
||
xroute
->
metric
<=
kernel_metric
))
{
if
(
hop_count
>
0
&&
memcmp
(
id
,
myid
,
8
)
==
0
)
{
...
...
@@ -1704,14 +2050,14 @@ handle_request(struct neighbour *neigh, const unsigned char *prefix,
update_myseqno
();
}
}
send_update
(
neigh
->
ifp
,
1
,
prefix
,
plen
);
send_update
(
neigh
->
ifp
,
1
,
prefix
,
plen
,
src_prefix
,
src_plen
);
return
;
}
if
(
route
&&
(
memcmp
(
id
,
route
->
src
->
id
,
8
)
!=
0
||
seqno_compare
(
seqno
,
route
->
seqno
)
<=
0
))
{
send_update
(
neigh
->
ifp
,
1
,
prefix
,
plen
);
send_update
(
neigh
->
ifp
,
1
,
prefix
,
plen
,
src_prefix
,
src_plen
);
return
;
}
...
...
@@ -1724,7 +2070,8 @@ handle_request(struct neighbour *neigh, const unsigned char *prefix,
return
;
}
if
(
request_redundant
(
neigh
->
ifp
,
prefix
,
plen
,
seqno
,
id
))
if
(
request_redundant
(
neigh
->
ifp
,
prefix
,
plen
,
src_prefix
,
src_plen
,
seqno
,
id
))
return
;
/* Let's try to forward this request. */
...
...
@@ -1736,7 +2083,8 @@ handle_request(struct neighbour *neigh, const unsigned char *prefix,
find a different neighbour to forward the request to. */
struct
babel_route
*
other_route
;
other_route
=
find_best_route
(
prefix
,
plen
,
0
,
neigh
);
other_route
=
find_best_route
(
prefix
,
plen
,
src_prefix
,
src_plen
,
0
,
neigh
);
if
(
other_route
&&
route_metric
(
other_route
)
<
INFINITY
)
successor
=
other_route
->
neigh
;
}
...
...
@@ -1745,8 +2093,8 @@ handle_request(struct neighbour *neigh, const unsigned char *prefix,
/* Give up */
return
;
send_unicast_multihop_request
(
successor
,
prefix
,
plen
,
s
eqno
,
id
,
hop_count
-
1
);
record_resend
(
RESEND_REQUEST
,
prefix
,
plen
,
seqno
,
id
,
send_unicast_multihop_request
(
successor
,
prefix
,
plen
,
s
rc_prefix
,
src_plen
,
seqno
,
id
,
hop_count
-
1
);
record_resend
(
RESEND_REQUEST
,
prefix
,
plen
,
s
rc_prefix
,
src_plen
,
s
eqno
,
id
,
neigh
->
ifp
,
0
);
}
message.h
View file @
4a4d66da
...
...
@@ -39,6 +39,10 @@ THE SOFTWARE.
#define MESSAGE_UPDATE 8
#define MESSAGE_REQUEST 9
#define MESSAGE_MH_REQUEST 10
/* 11 and 12 are for authentication */
#define MESSAGE_UPDATE_SRC_SPECIFIC 13
#define MESSAGE_REQUEST_SRC_SPECIFIC 14
#define MESSAGE_MH_REQUEST_SRC_SPECIFIC 15
/* Protocol extension through sub-TLVs. */
#define SUBTLV_PAD1 0
...
...
@@ -67,30 +71,44 @@ void send_hello_noupdate(struct interface *ifp, unsigned interval);
void
send_hello
(
struct
interface
*
ifp
);
void
flush_unicast
(
int
dofree
);
void
send_update
(
struct
interface
*
ifp
,
int
urgent
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
);
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
);
void
send_update_resend
(
struct
interface
*
ifp
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
);
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
);
void
send_wildcard_retraction
(
struct
interface
*
ifp
);
void
update_myseqno
(
void
);
void
send_self_update
(
struct
interface
*
ifp
);
void
send_ihu
(
struct
neighbour
*
neigh
,
struct
interface
*
ifp
);
void
send_marginal_ihu
(
struct
interface
*
ifp
);
void
send_request
(
struct
interface
*
ifp
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
);
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
);
void
send_unicast_request
(
struct
neighbour
*
neigh
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
);
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
);
void
send_multihop_request
(
struct
interface
*
ifp
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
const
unsigned
char
*
id
,
unsigned
short
hop_count
);
void
send_unicast_multihop_request
(
struct
neighbour
*
neigh
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
const
unsigned
char
*
id
,
unsigned
short
hop_count
);
void
send_request_resend
(
struct
neighbour
*
neigh
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
unsigned
char
*
id
);
void
handle_request
(
struct
neighbour
*
neigh
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
unsigned
char
hop_count
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
char
hop_count
,
unsigned
short
seqno
,
const
unsigned
char
*
id
);
neighbour.c
View file @
4a4d66da
...
...
@@ -193,7 +193,7 @@ update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
if
((
neigh
->
reach
&
0xFC00
)
==
0xC000
)
{
/* This is a newish neighbour, let's request a full route dump.
We ought to avoid this when the network is dense */
send_unicast_request
(
neigh
,
NULL
,
0
);
send_unicast_request
(
neigh
,
NULL
,
0
,
NULL
,
0
);
send_ihu
(
neigh
,
NULL
);
}
return
rc
;
...
...
resend.c
View file @
4a4d66da
...
...
@@ -38,10 +38,13 @@ struct resend *to_resend = NULL;
static
int
resend_match
(
struct
resend
*
resend
,
int
kind
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
)
int
kind
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
)
{
return
(
resend
->
kind
==
kind
&&
resend
->
plen
==
plen
&&
memcmp
(
resend
->
prefix
,
prefix
,
16
)
==
0
);
resend
->
plen
==
plen
&&
memcmp
(
resend
->
prefix
,
prefix
,
16
)
==
0
&&
resend
->
src_plen
==
src_plen
&&
memcmp
(
resend
->
src_prefix
,
src_prefix
,
16
)
==
0
);
}
/* This is called by neigh.c when a neighbour is flushed */
...
...
@@ -54,6 +57,7 @@ flush_resends(struct neighbour *neigh)
static
struct
resend
*
find_resend
(
int
kind
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
struct
resend
**
previous_return
)
{
struct
resend
*
current
,
*
previous
;
...
...
@@ -61,7 +65,7 @@ find_resend(int kind, const unsigned char *prefix, unsigned char plen,
previous
=
NULL
;
current
=
to_resend
;
while
(
current
)
{
if
(
resend_match
(
current
,
kind
,
prefix
,
plen
))
{
if
(
resend_match
(
current
,
kind
,
prefix
,
plen
,
src_prefix
,
src_plen
))
{
if
(
previous_return
)
*
previous_return
=
previous
;
return
current
;
...
...
@@ -75,13 +79,16 @@ find_resend(int kind, const unsigned char *prefix, unsigned char plen,
struct
resend
*
find_request
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
struct
resend
**
previous_return
)
{
return
find_resend
(
RESEND_REQUEST
,
prefix
,
plen
,
previous_return
);
return
find_resend
(
RESEND_REQUEST
,
prefix
,
plen
,
src_prefix
,
src_plen
,
previous_return
);
}
int
record_resend
(
int
kind
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
const
unsigned
char
*
id
,
struct
interface
*
ifp
,
int
delay
)
{
...
...
@@ -89,15 +96,18 @@ record_resend(int kind, const unsigned char *prefix, unsigned char plen,
unsigned
int
ifindex
=
ifp
?
ifp
->
ifindex
:
0
;
if
((
kind
==
RESEND_REQUEST
&&
input_filter
(
NULL
,
prefix
,
plen
,
NULL
,
ifindex
)
>=
INFINITY
)
||
input_filter
(
NULL
,
prefix
,
plen
,
src_prefix
,
src_plen
,
NULL
,
ifindex
)
>=
INFINITY
)
||
(
kind
==
RESEND_UPDATE
&&
output_filter
(
NULL
,
prefix
,
plen
,
ifindex
)
>=
INFINITY
))
output_filter
(
NULL
,
prefix
,
plen
,
src_prefix
,
src_plen
,
ifindex
)
>=
INFINITY
))
return
0
;
if
(
delay
>=
0xFFFF
)
delay
=
0xFFFF
;
resend
=
find_resend
(
kind
,
prefix
,
plen
,
NULL
);
resend
=
find_resend
(
kind
,
prefix
,
plen
,
src_prefix
,
src_plen
,
NULL
);
if
(
resend
)
{
if
(
resend
->
delay
&&
delay
)
resend
->
delay
=
MIN
(
resend
->
delay
,
delay
);
...
...
@@ -125,6 +135,8 @@ record_resend(int kind, const unsigned char *prefix, unsigned char plen,
resend
->
delay
=
delay
;
memcpy
(
resend
->
prefix
,
prefix
,
16
);
resend
->
plen
=
plen
;
memcpy
(
resend
->
src_prefix
,
src_prefix
,
16
);
resend
->
src_plen
=
src_plen
;
resend
->
seqno
=
seqno
;
if
(
id
)
memcpy
(
resend
->
id
,
id
,
8
);
...
...
@@ -157,11 +169,12 @@ resend_expired(struct resend *resend)
int
unsatisfied_request
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
const
unsigned
char
*
id
)
{
struct
resend
*
request
;
request
=
find_request
(
prefix
,
plen
,
NULL
);
request
=
find_request
(
prefix
,
plen
,
src_prefix
,
src_plen
,
NULL
);
if
(
request
==
NULL
||
resend_expired
(
request
))
return
0
;
...
...
@@ -176,11 +189,12 @@ unsatisfied_request(const unsigned char *prefix, unsigned char plen,
int
request_redundant
(
struct
interface
*
ifp
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
const
unsigned
char
*
id
)
{
struct
resend
*
request
;
request
=
find_request
(
prefix
,
plen
,
NULL
);
request
=
find_request
(
prefix
,
plen
,
src_prefix
,
src_plen
,
NULL
);
if
(
request
==
NULL
||
resend_expired
(
request
))
return
0
;
...
...
@@ -205,12 +219,13 @@ request_redundant(struct interface *ifp,
int
satisfy_request
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
const
unsigned
char
*
id
,
struct
interface
*
ifp
)
{
struct
resend
*
request
,
*
previous
;
request
=
find_request
(
prefix
,
plen
,
&
previous
);
request
=
find_request
(
prefix
,
plen
,
src_prefix
,
src_plen
,
&
previous
);
if
(
request
==
NULL
)
return
0
;
...
...
@@ -293,11 +308,13 @@ do_resend()
case
RESEND_REQUEST
:
send_multihop_request
(
resend
->
ifp
,
resend
->
prefix
,
resend
->
plen
,
resend
->
src_prefix
,
resend
->
src_plen
,
resend
->
seqno
,
resend
->
id
,
127
);
break
;
case
RESEND_UPDATE
:
send_update
(
resend
->
ifp
,
1
,
resend
->
prefix
,
resend
->
plen
);
resend
->
prefix
,
resend
->
plen
,
resend
->
src_prefix
,
resend
->
src_plen
);
break
;
default:
abort
();
}
...
...
resend.h
View file @
4a4d66da
...
...
@@ -33,6 +33,8 @@ struct resend {
struct
timeval
time
;
unsigned
char
prefix
[
16
];
unsigned
char
plen
;
unsigned
char
src_prefix
[
16
];
unsigned
char
src_plen
;
unsigned
short
seqno
;
unsigned
char
id
[
8
];
struct
interface
*
ifp
;
...
...
@@ -42,17 +44,22 @@ struct resend {
extern
struct
timeval
resend_time
;
struct
resend
*
find_request
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
struct
resend
**
previous_return
);
void
flush_resends
(
struct
neighbour
*
neigh
);
int
record_resend
(
int
kind
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
const
unsigned
char
*
id
,
struct
interface
*
ifp
,
int
delay
);
int
unsatisfied_request
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
const
unsigned
char
*
id
);
int
request_redundant
(
struct
interface
*
ifp
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
const
unsigned
char
*
id
);
int
satisfy_request
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
const
unsigned
char
*
id
,
struct
interface
*
ifp
);
...
...
route.c
View file @
4a4d66da
...
...
@@ -39,6 +39,7 @@ THE SOFTWARE.
#include "resend.h"
#include "configuration.h"
#include "local.h"
#include "disambiguation.h"
struct
babel_route
**
routes
=
NULL
;
static
int
route_slots
=
0
,
max_route_slots
=
0
;
...
...
@@ -57,6 +58,7 @@ static int two_to_the_one_over_hl = 0; /* 2^(1/hl) * 0x10000 */
static
int
route_compare
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
struct
babel_route
*
route
)
{
int
i
=
memcmp
(
prefix
,
route
->
src
->
prefix
,
16
);
...
...
@@ -65,9 +67,22 @@ route_compare(const unsigned char *prefix, unsigned char plen,
if
(
plen
<
route
->
src
->
plen
)
return
-
1
;
else
if
(
plen
>
route
->
src
->
plen
)
if
(
plen
>
route
->
src
->
plen
)
return
1
;
else
if
(
src_plen
==
0
)
{
if
(
route
->
src
->
src_plen
>
0
)
return
-
1
;
}
else
{
i
=
memcmp
(
src_prefix
,
route
->
src
->
src_prefix
,
16
);
if
(
i
!=
0
)
return
i
;
if
(
src_plen
<
route
->
src
->
src_plen
)
return
-
1
;
if
(
src_plen
>
route
->
src
->
src_plen
)
return
1
;
}
return
0
;
}
...
...
@@ -76,6 +91,7 @@ route_compare(const unsigned char *prefix, unsigned char plen,
static
int
find_route_slot
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
int
*
new_return
)
{
int
p
,
m
,
g
,
c
;
...
...
@@ -90,7 +106,7 @@ find_route_slot(const unsigned char *prefix, unsigned char plen,
do
{
m
=
(
p
+
g
)
/
2
;
c
=
route_compare
(
prefix
,
plen
,
routes
[
m
]);
c
=
route_compare
(
prefix
,
plen
,
src_prefix
,
src_plen
,
routes
[
m
]);
if
(
c
==
0
)
return
m
;
else
if
(
c
<
0
)
...
...
@@ -107,10 +123,11 @@ find_route_slot(const unsigned char *prefix, unsigned char plen,
struct
babel_route
*
find_route
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
struct
neighbour
*
neigh
,
const
unsigned
char
*
nexthop
)
{
struct
babel_route
*
route
;
int
i
=
find_route_slot
(
prefix
,
plen
,
NULL
);
int
i
=
find_route_slot
(
prefix
,
plen
,
src_prefix
,
src_plen
,
NULL
);
if
(
i
<
0
)
return
NULL
;
...
...
@@ -127,9 +144,10 @@ find_route(const unsigned char *prefix, unsigned char plen,
}
struct
babel_route
*
find_installed_route
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
)
find_installed_route
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
)
{
int
i
=
find_route_slot
(
prefix
,
plen
,
NULL
);
int
i
=
find_route_slot
(
prefix
,
plen
,
src_prefix
,
src_plen
,
NULL
);
if
(
i
>=
0
&&
routes
[
i
]
->
installed
)
return
routes
[
i
];
...
...
@@ -173,7 +191,8 @@ insert_route(struct babel_route *route)
assert
(
!
route
->
installed
);
i
=
find_route_slot
(
route
->
src
->
prefix
,
route
->
src
->
plen
,
&
n
);
i
=
find_route_slot
(
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
,
&
n
);
if
(
i
<
0
)
{
if
(
route_slots
>=
max_route_slots
)
...
...
@@ -214,7 +233,8 @@ flush_route(struct babel_route *route)
lost
=
1
;
}
i
=
find_route_slot
(
route
->
src
->
prefix
,
route
->
src
->
plen
,
NULL
);
i
=
find_route_slot
(
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
,
NULL
);
assert
(
i
>=
0
&&
i
<
route_slots
);
local_notify_route
(
route
,
LOCAL_FLUSH
);
...
...
@@ -370,7 +390,73 @@ route_stream_done(struct route_stream *stream)
free
(
stream
);
}
static
int
/* Search the minimum route covering (dst, src), such that either the exact
destination or source is given. If exclusive_min is true, (dst, src) is
excluded from the search. */
struct
babel_route
*
find_min_iroute
(
const
unsigned
char
*
dst_prefix
,
unsigned
char
dst_plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
int
is_fixed_dst
,
int
exclusive_min
)
{
enum
prefix_status
st
;
struct
babel_route
*
result
=
NULL
;
int
i
;
if
(
is_fixed_dst
)
{
for
(
i
=
0
;
i
<
route_slots
;
i
++
)
{
if
(
!
routes
[
i
]
->
installed
)
continue
;
st
=
prefix_cmp
(
dst_prefix
,
dst_plen
,
routes
[
i
]
->
src
->
prefix
,
routes
[
i
]
->
src
->
plen
);
if
(
st
!=
PST_EQUALS
)
continue
;
st
=
prefix_cmp
(
src_prefix
,
src_plen
,
routes
[
i
]
->
src
->
src_prefix
,
routes
[
i
]
->
src
->
src_plen
);
if
(
!
(
st
&
(
exclusive_min
?
PST_MORE_SPECIFIC
:
PST_MORE_SPECIFIC
|
PST_EQUALS
)))
continue
;
if
(
result
&&
(
prefix_cmp
(
result
->
src
->
src_prefix
,
result
->
src
->
src_plen
,
routes
[
i
]
->
src
->
src_prefix
,
routes
[
i
]
->
src
->
src_plen
)
==
PST_MORE_SPECIFIC
))
continue
;
result
=
routes
[
i
];
}
}
else
{
for
(
i
=
0
;
i
<
route_slots
;
i
++
)
{
if
(
!
routes
[
i
]
->
installed
)
continue
;
st
=
prefix_cmp
(
src_prefix
,
src_plen
,
routes
[
i
]
->
src
->
src_prefix
,
routes
[
i
]
->
src
->
src_plen
);
if
(
st
!=
PST_EQUALS
)
continue
;
st
=
prefix_cmp
(
dst_prefix
,
dst_plen
,
routes
[
i
]
->
src
->
prefix
,
routes
[
i
]
->
src
->
plen
);
if
(
!
(
st
&
(
exclusive_min
?
PST_MORE_SPECIFIC
:
PST_MORE_SPECIFIC
|
PST_EQUALS
)))
continue
;
if
(
result
&&
(
prefix_cmp
(
result
->
src
->
prefix
,
result
->
src
->
plen
,
routes
[
i
]
->
src
->
prefix
,
routes
[
i
]
->
src
->
plen
)
==
PST_MORE_SPECIFIC
))
continue
;
result
=
routes
[
i
];
}
}
if
(
result
)
assert
(
v4mapped
(
dst_prefix
)
==
v4mapped
(
result
->
src
->
prefix
));
return
result
;
}
int
metric_to_kernel
(
int
metric
)
{
if
(
metric
>=
INFINITY
)
{
...
...
@@ -413,7 +499,8 @@ install_route(struct babel_route *route)
fprintf
(
stderr
,
"WARNING: installing unfeasible route "
"(this shouldn't happen)."
);
i
=
find_route_slot
(
route
->
src
->
prefix
,
route
->
src
->
plen
,
NULL
);
i
=
find_route_slot
(
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
,
NULL
);
assert
(
i
>=
0
&&
i
<
route_slots
);
if
(
routes
[
i
]
!=
route
&&
routes
[
i
]
->
installed
)
{
...
...
@@ -422,16 +509,10 @@ install_route(struct babel_route *route)
return
;
}
rc
=
kernel_route
(
ROUTE_ADD
,
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
nexthop
,
route
->
neigh
->
ifp
->
ifindex
,
metric_to_kernel
(
route_metric
(
route
)),
NULL
,
0
,
0
);
if
(
rc
<
0
)
{
int
save
=
errno
;
perror
(
"kernel_route(ADD)"
);
if
(
save
!=
EEXIST
)
rc
=
kinstall_route
(
route
);
if
(
rc
<
0
&&
errno
!=
EEXIST
)
return
;
}
route
->
installed
=
1
;
move_installed_route
(
route
,
i
);
...
...
@@ -441,19 +522,13 @@ install_route(struct babel_route *route)
void
uninstall_route
(
struct
babel_route
*
route
)
{
int
rc
;
if
(
!
route
->
installed
)
return
;
rc
=
kernel_route
(
ROUTE_FLUSH
,
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
nexthop
,
route
->
neigh
->
ifp
->
ifindex
,
metric_to_kernel
(
route_metric
(
route
)),
NULL
,
0
,
0
);
if
(
rc
<
0
)
perror
(
"kernel_route(FLUSH)"
);
route
->
installed
=
0
;
kuninstall_route
(
route
);
local_notify_route
(
route
,
LOCAL_CHANGE
);
}
...
...
@@ -478,19 +553,15 @@ switch_routes(struct babel_route *old, struct babel_route *new)
fprintf
(
stderr
,
"WARNING: switching to unfeasible route "
"(this shouldn't happen)."
);
rc
=
kernel_route
(
ROUTE_MODIFY
,
old
->
src
->
prefix
,
old
->
src
->
plen
,
old
->
nexthop
,
old
->
neigh
->
ifp
->
ifindex
,
metric_to_kernel
(
route_metric
(
old
)),
new
->
nexthop
,
new
->
neigh
->
ifp
->
ifindex
,
metric_to_kernel
(
route_metric
(
new
)));
if
(
rc
<
0
)
{
perror
(
"kernel_route(MODIFY)"
);
rc
=
kswitch_routes
(
old
,
new
);
if
(
rc
<
0
)
return
;
}
old
->
installed
=
0
;
new
->
installed
=
1
;
move_installed_route
(
new
,
find_route_slot
(
new
->
src
->
prefix
,
new
->
src
->
plen
,
new
->
src
->
src_prefix
,
new
->
src
->
src_plen
,
NULL
));
local_notify_route
(
old
,
LOCAL_CHANGE
);
local_notify_route
(
new
,
LOCAL_CHANGE
);
...
...
@@ -508,16 +579,10 @@ change_route_metric(struct babel_route *route,
if
(
route
->
installed
&&
old
!=
new
)
{
int
rc
;
rc
=
kernel_route
(
ROUTE_MODIFY
,
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
nexthop
,
route
->
neigh
->
ifp
->
ifindex
,
old
,
route
->
nexthop
,
route
->
neigh
->
ifp
->
ifindex
,
new
);
if
(
rc
<
0
)
{
perror
(
"kernel_route(MODIFY metric)"
);
rc
=
kchange_route_metric
(
route
,
refmetric
,
cost
,
add
);
if
(
rc
<
0
)
return
;
}
}
/* Update route->smoothed_metric using the old metric. */
route_smoothed_metric
(
route
);
...
...
@@ -697,11 +762,12 @@ route_acceptable(struct babel_route *route, int feasible,
that's probably overkill. */
struct
babel_route
*
find_best_route
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
int
feasible
,
struct
neighbour
*
exclude
)
find_best_route
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
int
feasible
,
struct
neighbour
*
exclude
)
{
struct
babel_route
*
route
,
*
r
;
int
i
=
find_route_slot
(
prefix
,
plen
,
NULL
);
int
i
=
find_route_slot
(
prefix
,
plen
,
src_prefix
,
src_plen
,
NULL
);
if
(
i
<
0
)
return
NULL
;
...
...
@@ -741,6 +807,8 @@ update_route_metric(struct babel_route *route)
struct
neighbour
*
neigh
=
route
->
neigh
;
int
add_metric
=
input_filter
(
route
->
src
->
id
,
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
,
neigh
->
address
,
neigh
->
ifp
->
ifindex
);
change_route_metric
(
route
,
route
->
refmetric
,
...
...
@@ -792,6 +860,7 @@ update_interface_metric(struct interface *ifp)
struct
babel_route
*
update_route
(
const
unsigned
char
*
id
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
unsigned
short
refmetric
,
unsigned
short
interval
,
struct
neighbour
*
neigh
,
const
unsigned
char
*
nexthop
,
...
...
@@ -802,7 +871,7 @@ update_route(const unsigned char *id,
int
metric
,
feasible
;
int
add_metric
;
int
hold_time
=
MAX
((
4
*
interval
)
/
100
+
interval
/
50
,
15
);
int
is_v4
;
if
(
memcmp
(
id
,
myid
,
8
)
==
0
)
return
NULL
;
...
...
@@ -811,19 +880,30 @@ update_route(const unsigned char *id,
format_prefix
(
prefix
,
plen
),
format_address
(
nexthop
));
return
NULL
;
}
if
(
src_plen
!=
0
&&
martian_prefix
(
src_prefix
,
src_plen
))
{
fprintf
(
stderr
,
"Rejecting martian route to %s from %s through %s.
\n
"
,
format_prefix
(
prefix
,
plen
),
format_prefix
(
src_prefix
,
src_plen
),
format_eui64
(
id
));
return
NULL
;
}
is_v4
=
v4mapped
(
prefix
);
if
(
src_plen
!=
0
&&
is_v4
!=
v4mapped
(
src_prefix
))
return
NULL
;
add_metric
=
input_filter
(
id
,
prefix
,
plen
,
add_metric
=
input_filter
(
id
,
prefix
,
plen
,
src_prefix
,
src_plen
,
neigh
->
address
,
neigh
->
ifp
->
ifindex
);
if
(
add_metric
>=
INFINITY
)
return
NULL
;
route
=
find_route
(
prefix
,
plen
,
neigh
,
nexthop
);
route
=
find_route
(
prefix
,
plen
,
src_prefix
,
src_plen
,
neigh
,
nexthop
);
if
(
route
&&
memcmp
(
route
->
src
->
id
,
id
,
8
)
==
0
)
/* Avoid scanning the source table. */
src
=
route
->
src
;
else
src
=
find_source
(
id
,
prefix
,
plen
,
1
,
seqno
);
src
=
find_source
(
id
,
prefix
,
plen
,
src_prefix
,
src_plen
,
1
,
seqno
);
if
(
src
==
NULL
)
return
NULL
;
...
...
@@ -932,7 +1012,9 @@ send_unfeasible_request(struct neighbour *neigh, int force,
unsigned
short
seqno
,
unsigned
short
metric
,
struct
source
*
src
)
{
struct
babel_route
*
route
=
find_installed_route
(
src
->
prefix
,
src
->
plen
);
struct
babel_route
*
route
=
find_installed_route
(
src
->
prefix
,
src
->
plen
,
src
->
src_prefix
,
src
->
src_plen
);
if
(
seqno_minus
(
src
->
seqno
,
seqno
)
>
100
)
{
/* Probably a source that lost its seqno. Let it time-out. */
...
...
@@ -941,6 +1023,7 @@ send_unfeasible_request(struct neighbour *neigh, int force,
if
(
force
||
!
route
||
route_metric
(
route
)
>=
metric
+
512
)
{
send_unicast_multihop_request
(
neigh
,
src
->
prefix
,
src
->
plen
,
src
->
src_prefix
,
src
->
src_plen
,
src
->
metric
>=
INFINITY
?
src
->
seqno
:
seqno_plus
(
src
->
seqno
,
1
),
...
...
@@ -965,11 +1048,14 @@ consider_route(struct babel_route *route)
if
(
!
route_feasible
(
route
))
return
;
xroute
=
find_xroute
(
route
->
src
->
prefix
,
route
->
src
->
plen
);
xroute
=
find_xroute
(
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
);
if
(
xroute
&&
(
allow_duplicates
<
0
||
xroute
->
metric
>=
allow_duplicates
))
return
;
installed
=
find_installed_route
(
route
->
src
->
prefix
,
route
->
src
->
plen
);
installed
=
find_installed_route
(
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
);
if
(
installed
==
NULL
)
goto
install
;
...
...
@@ -991,7 +1077,8 @@ consider_route(struct babel_route *route)
if
(
installed
&&
route
->
installed
)
send_triggered_update
(
route
,
installed
->
src
,
route_metric
(
installed
));
else
send_update
(
NULL
,
1
,
route
->
src
->
prefix
,
route
->
src
->
plen
);
send_update
(
NULL
,
1
,
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
);
return
;
}
...
...
@@ -1040,6 +1127,7 @@ send_triggered_update(struct babel_route *route, struct source *oldsrc,
/* Route getting significantly worse */
urgent
=
1
;
else
if
(
unsatisfied_request
(
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
,
route
->
seqno
,
route
->
src
->
id
))
/* Make sure that requests are satisfied speedily */
urgent
=
1
;
...
...
@@ -1057,19 +1145,23 @@ send_triggered_update(struct babel_route *route, struct source *oldsrc,
urgent
=
0
;
if
(
urgent
>=
2
)
send_update_resend
(
NULL
,
route
->
src
->
prefix
,
route
->
src
->
plen
);
send_update_resend
(
NULL
,
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
);
else
send_update
(
NULL
,
urgent
,
route
->
src
->
prefix
,
route
->
src
->
plen
);
send_update
(
NULL
,
urgent
,
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
);
if
(
oldmetric
<
INFINITY
)
{
if
(
newmetric
>=
oldmetric
+
512
)
{
send_request_resend
(
NULL
,
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
,
route
->
src
->
metric
>=
INFINITY
?
route
->
src
->
seqno
:
seqno_plus
(
route
->
src
->
seqno
,
1
),
route
->
src
->
id
);
}
else
if
(
newmetric
>=
oldmetric
+
288
)
{
send_request
(
NULL
,
route
->
src
->
prefix
,
route
->
src
->
plen
);
send_request
(
NULL
,
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
);
}
}
}
...
...
@@ -1084,7 +1176,9 @@ route_changed(struct babel_route *route,
struct
babel_route
*
better_route
;
/* Do this unconditionally -- microoptimisation is not worth it. */
better_route
=
find_best_route
(
route
->
src
->
prefix
,
route
->
src
->
plen
,
1
,
NULL
);
find_best_route
(
route
->
src
->
prefix
,
route
->
src
->
plen
,
route
->
src
->
src_prefix
,
route
->
src
->
src_plen
,
1
,
NULL
);
if
(
better_route
&&
route_metric
(
better_route
)
<
route_metric
(
route
))
consider_route
(
better_route
);
}
...
...
@@ -1104,17 +1198,20 @@ void
route_lost
(
struct
source
*
src
,
unsigned
oldmetric
)
{
struct
babel_route
*
new_route
;
new_route
=
find_best_route
(
src
->
prefix
,
src
->
plen
,
1
,
NULL
);
new_route
=
find_best_route
(
src
->
prefix
,
src
->
plen
,
src
->
src_prefix
,
src
->
src_plen
,
1
,
NULL
);
if
(
new_route
)
{
consider_route
(
new_route
);
}
else
if
(
oldmetric
<
INFINITY
)
{
/* Avoid creating a blackhole. */
send_update_resend
(
NULL
,
src
->
prefix
,
src
->
plen
);
send_update_resend
(
NULL
,
src
->
prefix
,
src
->
plen
,
src
->
src_prefix
,
src
->
src_plen
);
/* If the route was usable enough, try to get an alternate one.
If it was not, we could be dealing with oscillations around
the value of INFINITY. */
if
(
oldmetric
<=
INFINITY
/
2
)
send_request_resend
(
NULL
,
src
->
prefix
,
src
->
plen
,
src
->
src_prefix
,
src
->
src_plen
,
src
->
metric
>=
INFINITY
?
src
->
seqno
:
seqno_plus
(
src
->
seqno
,
1
),
src
->
id
);
...
...
@@ -1147,7 +1244,8 @@ expire_routes(void)
if
(
route_old
(
r
))
/* Route about to expire, send a request. */
send_unicast_request
(
r
->
neigh
,
r
->
src
->
prefix
,
r
->
src
->
plen
);
r
->
src
->
prefix
,
r
->
src
->
plen
,
r
->
src
->
src_prefix
,
r
->
src
->
src_plen
);
}
r
=
r
->
next
;
}
...
...
route.h
View file @
4a4d66da
...
...
@@ -70,9 +70,15 @@ route_metric_noninterfering(const struct babel_route *route)
}
struct
babel_route
*
find_route
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
struct
neighbour
*
neigh
,
const
unsigned
char
*
nexthop
);
struct
babel_route
*
find_installed_route
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
);
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
);
struct
babel_route
*
find_min_iroute
(
const
unsigned
char
*
dst_prefix
,
unsigned
char
dst_plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
int
is_fixed_dst
,
int
exclusive_min
);
int
installed_routes_estimate
(
void
);
void
flush_route
(
struct
babel_route
*
route
);
void
flush_all_routes
(
void
);
...
...
@@ -81,6 +87,7 @@ void flush_interface_routes(struct interface *ifp, int v4only);
struct
route_stream
*
route_stream
(
int
installed
);
struct
babel_route
*
route_stream_next
(
struct
route_stream
*
stream
);
void
route_stream_done
(
struct
route_stream
*
stream
);
int
metric_to_kernel
(
int
metric
);
void
install_route
(
struct
babel_route
*
route
);
void
uninstall_route
(
struct
babel_route
*
route
);
int
route_feasible
(
struct
babel_route
*
route
);
...
...
@@ -93,6 +100,8 @@ void change_smoothing_half_life(int half_life);
int
route_smoothed_metric
(
struct
babel_route
*
route
);
struct
babel_route
*
find_best_route
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
int
feasible
,
struct
neighbour
*
exclude
);
struct
babel_route
*
install_best_route
(
const
unsigned
char
prefix
[
16
],
unsigned
char
plen
);
...
...
@@ -101,6 +110,8 @@ void update_interface_metric(struct interface *ifp);
void
update_route_metric
(
struct
babel_route
*
route
);
struct
babel_route
*
update_route
(
const
unsigned
char
*
id
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
unsigned
short
seqno
,
unsigned
short
refmetric
,
unsigned
short
interval
,
struct
neighbour
*
neigh
,
const
unsigned
char
*
nexthop
,
...
...
source.c
View file @
4a4d66da
...
...
@@ -35,7 +35,9 @@ THE SOFTWARE.
struct
source
*
srcs
=
NULL
;
struct
source
*
find_source
(
const
unsigned
char
*
id
,
const
unsigned
char
*
p
,
unsigned
char
plen
,
find_source
(
const
unsigned
char
*
id
,
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
int
create
,
unsigned
short
seqno
)
{
struct
source
*
src
;
...
...
@@ -49,7 +51,11 @@ find_source(const unsigned char *id, const unsigned char *p, unsigned char plen,
continue
;
if
(
src
->
plen
!=
plen
)
continue
;
if
(
memcmp
(
src
->
prefix
,
p
,
16
)
==
0
)
if
(
src
->
src_plen
!=
src_plen
)
continue
;
if
(
memcmp
(
src
->
prefix
,
prefix
,
16
)
!=
0
)
continue
;
if
(
memcmp
(
src
->
src_prefix
,
src_prefix
,
16
)
==
0
)
return
src
;
}
...
...
@@ -63,8 +69,10 @@ find_source(const unsigned char *id, const unsigned char *p, unsigned char plen,
}
memcpy
(
src
->
id
,
id
,
8
);
memcpy
(
src
->
prefix
,
p
,
16
);
memcpy
(
src
->
prefix
,
p
refix
,
16
);
src
->
plen
=
plen
;
memcpy
(
src
->
src_prefix
,
src_prefix
,
16
);
src
->
src_plen
=
src_plen
;
src
->
seqno
=
seqno
;
src
->
metric
=
INFINITY
;
src
->
time
=
now
.
tv_sec
;
...
...
source.h
View file @
4a4d66da
...
...
@@ -27,6 +27,8 @@ struct source {
unsigned
char
id
[
8
];
unsigned
char
prefix
[
16
];
unsigned
char
plen
;
unsigned
char
src_prefix
[
16
];
unsigned
char
src_plen
;
unsigned
short
seqno
;
unsigned
short
metric
;
unsigned
short
route_count
;
...
...
@@ -34,8 +36,10 @@ struct source {
};
struct
source
*
find_source
(
const
unsigned
char
*
id
,
const
unsigned
char
*
p
,
const
unsigned
char
*
p
refix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
,
int
create
,
unsigned
short
seqno
);
struct
source
*
retain_source
(
struct
source
*
src
);
void
release_source
(
struct
source
*
src
);
...
...
util.c
View file @
4a4d66da
...
...
@@ -28,6 +28,7 @@ THE SOFTWARE.
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
...
...
@@ -488,3 +489,30 @@ daemonise()
return
1
;
}
enum
prefix_status
prefix_cmp
(
const
unsigned
char
*
p1
,
unsigned
char
plen1
,
const
unsigned
char
*
p2
,
unsigned
char
plen2
)
{
int
min
=
MIN
(
plen1
,
plen2
);
unsigned
char
mask
=
0xFF
;
int
i
=
0
;
while
(
i
<
min
/
8
)
{
if
(
p1
[
i
]
!=
p2
[
i
])
return
PST_DISJOINT
;
i
++
;
}
min
-=
i
*
8
;
if
(
min
!=
0
)
{
mask
<<=
8
-
min
;
if
((
p1
[
i
]
&
mask
)
!=
(
p2
[
i
]
&
mask
))
return
PST_DISJOINT
;
}
if
(
plen1
<
plen2
)
return
PST_LESS_SPECIFIC
;
if
(
plen1
>
plen2
)
return
PST_MORE_SPECIFIC
;
return
PST_EQUALS
;
}
util.h
View file @
4a4d66da
...
...
@@ -111,6 +111,17 @@ int linklocal(const unsigned char *address) ATTRIBUTE ((pure));
int
v4mapped
(
const
unsigned
char
*
address
)
ATTRIBUTE
((
pure
));
void
v4tov6
(
unsigned
char
*
dst
,
const
unsigned
char
*
src
);
int
daemonise
(
void
);
int
set_src_prefix
(
unsigned
char
*
src_addr
,
unsigned
char
*
src_plen
);
enum
prefix_status
{
PST_DISJOINT
=
1
<<
0
,
PST_EQUALS
=
1
<<
1
,
PST_MORE_SPECIFIC
=
1
<<
2
,
PST_LESS_SPECIFIC
=
1
<<
3
,
};
enum
prefix_status
prefix_cmp
(
const
unsigned
char
*
p1
,
unsigned
char
plen1
,
const
unsigned
char
*
p2
,
unsigned
char
plen2
);
/* If debugging is disabled, we want to avoid calling format_address
for every omitted debugging message. So debug is a macro. But
...
...
xroute.c
View file @
4a4d66da
...
...
@@ -43,12 +43,15 @@ static struct xroute *xroutes;
static
int
numxroutes
=
0
,
maxxroutes
=
0
;
struct
xroute
*
find_xroute
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
)
find_xroute
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
)
{
int
i
;
for
(
i
=
0
;
i
<
numxroutes
;
i
++
)
{
if
(
xroutes
[
i
].
plen
==
plen
&&
memcmp
(
xroutes
[
i
].
prefix
,
prefix
,
16
)
==
0
)
memcmp
(
xroutes
[
i
].
prefix
,
prefix
,
16
)
==
0
&&
xroutes
[
i
].
src_plen
==
src_plen
&&
memcmp
(
xroutes
[
i
].
src_prefix
,
src_prefix
,
16
)
==
0
)
return
&
xroutes
[
i
];
}
return
NULL
;
...
...
@@ -86,9 +89,10 @@ flush_xroute(struct xroute *xroute)
int
add_xroute
(
unsigned
char
prefix
[
16
],
unsigned
char
plen
,
unsigned
char
src_prefix
[
16
],
unsigned
char
src_plen
,
unsigned
short
metric
,
unsigned
int
ifindex
,
int
proto
)
{
struct
xroute
*
xroute
=
find_xroute
(
prefix
,
plen
);
struct
xroute
*
xroute
=
find_xroute
(
prefix
,
plen
,
src_prefix
,
src_plen
);
if
(
xroute
)
{
if
(
xroute
->
metric
<=
metric
)
return
0
;
...
...
@@ -111,6 +115,8 @@ add_xroute(unsigned char prefix[16], unsigned char plen,
memcpy
(
xroutes
[
numxroutes
].
prefix
,
prefix
,
16
);
xroutes
[
numxroutes
].
plen
=
plen
;
memcpy
(
xroutes
[
numxroutes
].
src_prefix
,
src_prefix
,
16
);
xroutes
[
numxroutes
].
src_plen
=
src_plen
;
xroutes
[
numxroutes
].
metric
=
metric
;
xroutes
[
numxroutes
].
ifindex
=
ifindex
;
xroutes
[
numxroutes
].
proto
=
proto
;
...
...
@@ -163,14 +169,15 @@ check_xroutes(int send_updates)
{
int
i
,
j
,
metric
,
export
,
change
=
0
,
rc
;
struct
kernel_route
*
routes
;
int
numroutes
;
struct
filter_result
filter_result
=
{
0
};
int
numroutes
,
numaddresses
;
static
int
maxroutes
=
8
;
const
int
maxmaxroutes
=
16
*
1024
;
debugf
(
"
\n
Checking kernel routes.
\n
"
);
again:
routes
=
malloc
(
maxroutes
*
sizeof
(
struct
kernel_route
));
routes
=
calloc
(
maxroutes
,
sizeof
(
struct
kernel_route
));
if
(
routes
==
NULL
)
return
-
1
;
...
...
@@ -185,6 +192,8 @@ check_xroutes(int send_updates)
if
(
numroutes
>=
maxroutes
)
goto
resize
;
numaddresses
=
numroutes
;
rc
=
kernel_routes
(
routes
+
numroutes
,
maxroutes
-
numroutes
);
if
(
rc
<
0
)
fprintf
(
stderr
,
"Couldn't get kernel routes.
\n
"
);
...
...
@@ -194,13 +203,30 @@ check_xroutes(int send_updates)
if
(
numroutes
>=
maxroutes
)
goto
resize
;
/* Apply filter to kernel routes (e.g. change the source prefix). */
for
(
i
=
numaddresses
;
i
<
numroutes
;
i
++
)
{
filter_result
.
src_prefix
=
NULL
;
redistribute_filter
(
routes
[
i
].
prefix
,
routes
[
i
].
plen
,
routes
[
i
].
src_prefix
,
routes
[
i
].
src_plen
,
routes
[
i
].
ifindex
,
routes
[
i
].
proto
,
&
filter_result
);
if
(
filter_result
.
src_prefix
)
{
memcpy
(
routes
[
i
].
src_prefix
,
filter_result
.
src_prefix
,
16
);
routes
[
i
].
src_plen
=
filter_result
.
src_plen
;
}
}
/* Check for any routes that need to be flushed */
i
=
0
;
while
(
i
<
numxroutes
)
{
export
=
0
;
metric
=
redistribute_filter
(
xroutes
[
i
].
prefix
,
xroutes
[
i
].
plen
,
xroutes
[
i
].
ifindex
,
xroutes
[
i
].
proto
);
xroutes
[
i
].
src_prefix
,
xroutes
[
i
].
src_plen
,
xroutes
[
i
].
ifindex
,
xroutes
[
i
].
proto
,
NULL
);
if
(
metric
<
INFINITY
&&
metric
==
xroutes
[
i
].
metric
)
{
for
(
j
=
0
;
j
<
numroutes
;
j
++
)
{
if
(
xroutes
[
i
].
plen
==
routes
[
j
].
plen
&&
...
...
@@ -215,17 +241,20 @@ check_xroutes(int send_updates)
if
(
!
export
)
{
unsigned
char
prefix
[
16
],
plen
;
unsigned
char
src_prefix
[
16
],
src_plen
;
struct
babel_route
*
route
;
memcpy
(
prefix
,
xroutes
[
i
].
prefix
,
16
);
plen
=
xroutes
[
i
].
plen
;
memcpy
(
src_prefix
,
xroutes
[
i
].
src_prefix
,
16
);
src_plen
=
xroutes
[
i
].
src_plen
;
flush_xroute
(
&
xroutes
[
i
]);
route
=
find_best_route
(
prefix
,
plen
,
1
,
NULL
);
route
=
find_best_route
(
prefix
,
plen
,
src_prefix
,
src_plen
,
1
,
NULL
);
if
(
route
)
install_route
(
route
);
/* send_update_resend only records the prefix, so the update
will only be sent after we perform all of the changes. */
if
(
send_updates
)
send_update_resend
(
NULL
,
prefix
,
plen
);
send_update_resend
(
NULL
,
prefix
,
plen
,
src_prefix
,
src_plen
);
change
=
1
;
}
else
{
i
++
;
...
...
@@ -238,13 +267,17 @@ check_xroutes(int send_updates)
if
(
martian_prefix
(
routes
[
i
].
prefix
,
routes
[
i
].
plen
))
continue
;
metric
=
redistribute_filter
(
routes
[
i
].
prefix
,
routes
[
i
].
plen
,
routes
[
i
].
ifindex
,
routes
[
i
].
proto
);
routes
[
i
].
src_prefix
,
routes
[
i
].
src_plen
,
routes
[
i
].
ifindex
,
routes
[
i
].
proto
,
NULL
);
if
(
metric
<
INFINITY
)
{
rc
=
add_xroute
(
routes
[
i
].
prefix
,
routes
[
i
].
plen
,
routes
[
i
].
src_prefix
,
routes
[
i
].
src_plen
,
metric
,
routes
[
i
].
ifindex
,
routes
[
i
].
proto
);
if
(
rc
>
0
)
{
struct
babel_route
*
route
;
route
=
find_installed_route
(
routes
[
i
].
prefix
,
routes
[
i
].
plen
);
route
=
find_installed_route
(
routes
[
i
].
prefix
,
routes
[
i
].
plen
,
routes
[
i
].
src_prefix
,
routes
[
i
].
src_plen
);
if
(
route
)
{
if
(
allow_duplicates
<
0
||
routes
[
i
].
metric
<
allow_duplicates
)
...
...
@@ -252,7 +285,8 @@ check_xroutes(int send_updates)
}
change
=
1
;
if
(
send_updates
)
send_update
(
NULL
,
0
,
routes
[
i
].
prefix
,
routes
[
i
].
plen
);
send_update
(
NULL
,
0
,
routes
[
i
].
prefix
,
routes
[
i
].
plen
,
routes
[
i
].
src_prefix
,
routes
[
i
].
src_plen
);
}
}
}
...
...
xroute.h
View file @
4a4d66da
...
...
@@ -23,6 +23,8 @@ THE SOFTWARE.
struct
xroute
{
unsigned
char
prefix
[
16
];
unsigned
char
plen
;
unsigned
char
src_prefix
[
16
];
unsigned
char
src_plen
;
unsigned
short
metric
;
unsigned
int
ifindex
;
int
proto
;
...
...
@@ -30,9 +32,11 @@ struct xroute {
struct
xroute_stream
;
struct
xroute
*
find_xroute
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
);
struct
xroute
*
find_xroute
(
const
unsigned
char
*
prefix
,
unsigned
char
plen
,
const
unsigned
char
*
src_prefix
,
unsigned
char
src_plen
);
void
flush_xroute
(
struct
xroute
*
xroute
);
int
add_xroute
(
unsigned
char
prefix
[
16
],
unsigned
char
plen
,
unsigned
char
src_prefix
[
16
],
unsigned
char
src_plen
,
unsigned
short
metric
,
unsigned
int
ifindex
,
int
proto
);
int
xroutes_estimate
(
void
);
struct
xroute_stream
*
xroute_stream
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment