Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
W
White Rabbit Switch - Software
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
86
Issues
86
List
Board
Labels
Milestones
Merge Requests
4
Merge Requests
4
CI / CD
CI / CD
Pipelines
Schedules
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
White Rabbit Switch - Software
Commits
17d478da
Commit
17d478da
authored
Dec 12, 2014
by
Alessandro Rubini
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dot-config'
parents
2905bb85
398172e2
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
337 additions
and
75 deletions
+337
-75
Kconfig
Kconfig
+14
-0
wrs_build_wraprootfs
build/scripts/wrs_build_wraprootfs
+2
-37
wrs-developer-manual.in
doc/wrs-developer-manual.in
+28
-16
wrs-user-manual.in
doc/wrs-user-manual.in
+134
-22
S20dot-config
userspace/rootfs_override/etc/init.d/S20dot-config
+56
-0
rsyslog.conf.in
userspace/rootfs_override/etc/rsyslog.conf.in
+0
-0
apply_dot-config
userspace/rootfs_override/wr/bin/apply_dot-config
+77
-0
change_dot-config
userspace/rootfs_override/wr/bin/change_dot-config
+26
-0
snmpd.conf.in
userspace/rootfs_override/wr/etc/snmpd.conf.in
+0
-0
start-daemons.sh.in
userspace/rootfs_override/wr/sbin/start-daemons.sh.in
+0
-0
No files found.
Kconfig
View file @
17d478da
mainmenu "White Rabbit Switch configuration"
config DOTCONF_URL
string "URL for a run-time replacement of dot-config"
help
The White Rabbit Switch is configured at run-time,
according to a dot-config .config file. The file
is the same .config you are defining now. If you
select an empty string, dot-config is not replaced
at run time. Otherwise, tftp://, ftp:// or http://
URLs are allowed. Names are allowed if you configured
a DNS server. The special strings IPADDR and MACADDR
are substituted before retrieving the file.
Example: "tftp://morgana/wrs-config-IPADDR"
config BR2_CONFIGFILE
string "Configuration file for Buildroot"
default "wrs_release_br2_config"
...
...
build/scripts/wrs_build_wraprootfs
View file @
17d478da
...
...
@@ -32,7 +32,8 @@ ROOTFS_INITRAMFS="$WRS_OUTPUT_DIR/images/wrs-initramfs.gz"
cat
>
$TMPSCRIPT
<<
EOF
.
$WRS_BASE_DIR
/../.config
mkdir -p
$TMPFS
/wr
mkdir -p
$TMPFS
/wr/etc
cp
$WRS_BASE_DIR
/../.config
$TMPFS
/wr/etc/dot-config
cp -r
$rootfs_vanilla
/*
$TMPFS
cp -r
$WRS_OUTPUT_DIR
/images/wr/*
$TMPFS
/wr
...
...
@@ -46,42 +47,6 @@ rm -rf $TMPFS/dev
(cd
$TMPFS
&& tar xzf
$DEVTAR
)
(cd
$TMPFS
&& ln -fs sbin/init .)
if [ ! -z "
$CONFIG_NTP_SERVER
" ]; then
echo "ntpserver
$CONFIG_NTP_SERVER
" >
$TMPFS
/wr/etc/wr_date.conf
fi
if [ ! -z "
$CONFIG_DNS_SERVER
" ]; then
rm -f
$TMPFS
/etc/resolv.conf
echo "nameserver
$CONFIG_DNS_SERVER
" >
$TMPFS
/etc/resolv.conf
if [ ! -z "
$CONFIG_DNS_DOMAIN
" ]; then
echo "domain
$CONFIG_DNS_DOMAIN
" >>
$TMPFS
/etc/resolv.conf
fi
fi
if [ "
$CONFIG_REMOTE_SYSLOG_UDP
" = "y" ]; then
sed -i 's/@@remote-host/@remote-host/'
$TMPFS
/etc/rsyslog.conf
fi
if [ ! -z "
$CONFIG_REMOTE_SYSLOG_SERVER
" ]; then
sed -i '/remote-host/ s/^##//'
$TMPFS
/etc/rsyslog.conf
sed -i 's/remote-host/
$CONFIG_REMOTE_SYSLOG_SERVER
/'
$TMPFS
/etc/rsyslog.conf
fi
# Fix SNMP values: for all not-empty configs remove commend and replace value
cfgfile="
$TMPFS
/wr/etc/snmpd.conf"
set | grep CONFIG_SNMP | sed 's/=/ /' | while read varname value; do
if [ -z "\
$value
" ]; then continue; fi
sed -i "/\
$varname
/ s/^#//" \
$cfgfile
sed -i "/\
$varname
/ s/\
$varname
/\
$value
/" \
$cfgfile
done
# Fix log values
cfgfile="
$TMPFS
/wr/sbin/start-daemons.sh"
set | grep CONFIG_WRS_LOG | sed 's/=/ /' | while read varname value; do
if [ -z "\
$value
" ]; then continue; fi
sed -i "/\
$varname
/ s,\
$varname
,\
$value
," \
$cfgfile
done
mkdir -p
$TMPFS
/root/.ssh
#cat
$HOME
/.ssh/id_?sa.pub >>
$TMPFS
/root/.ssh/authorized_keys
if [ -f
$WRS_BASE_DIR
/authorized_keys ]; then
...
...
doc/wrs-developer-manual.in
View file @
17d478da
...
...
@@ -177,12 +177,11 @@ After release 3.3, we decided to add @i{Kconfig} support. This means
that
the
first
build
step
is
expected
to
be
``@
t
{
make
menuconfig
}
''
,
like
it
happens
for
the
kernel
.
The
default
configuration
is
selected
by
default
when
one
of
the
build
scripts
is
run
,
so
the
procedure
for
the
final
user
is
the
same
as
for
v3
.3
and
earlier
.
A
build
with
a
non
-
default
configuration
,
however
,
is
not
considered
as
``
supported
''
,
and
@
i
{
Kconfig
}
is
there
mainly
to
help
developers
try
new
packages
and
setups
without
changing
the
repository
or
introducing
problems
for
other
users
.
For
some
more
information
about
@
i
{
Kconfig
}
in
this
package
,
see
the
@
i
{@
sc
{
wrs
}
User
's Manual}.
the
final
user
is
the
same
as
for
v3
.3
and
earlier
.
After
release
4.1
we
support
dynamic
reconfiguration
.
As
opposed
to
build
-
time
configuration
,
run
-
time
configuration
is
expected
to
be
frequent
,
and
it
's thus documented in the @i{@sc{wrs} Users'
Manual
}.
The
build
system
is
set
up
as
a
mix
of
scripts
and
makefiles
.
Every
sub
-
package
is
built
by
its
own
script
and
/
or
Makefile
,
and
configuration
is
...
...
@@ -451,14 +450,9 @@ to be used at installation time. See @ref{Flashing Procedure} for details.
Some
details
of
the
complete
firmware
archive
depend
on
the
values
of
active
@
t
{
Kconfig
}
variables
.
If
no
manual
configuration
is
performed
,
what applies is @t{configs/wrs_release_defconfig}.
If you want to customize your configuration to install several
switches pre-configured for your network, we suggest you rebuild
the @i{firmware} archive after running @t{make menuconfig} to select
your own values
@c FIXME FIXME FIXME: Store kconfig and build info in the archive itself
what
applies
is
@
t
{
configs
/
wrs_release_defconfig
}.
Please
note
that
we
now
support
dynamic
reconfiguration
at
run
-
time
.
See
the
@
i
{@
sc
{
wrs
}
Users
' Manual}.
@c --------------------------------------------------------------------------
@node Rebuilding Parts
...
...
@@ -811,7 +805,11 @@ The main components are:
@
end
table
The
most
important
tools
in
@
file
{
userspace
/
tools
}
are
the
following
:
@
sc
{
wrs
}
user
space
includes
also
some
tools
and
scripts
.
Tools
are
build
from
source
files
in
@
file
{
userspace
/
tools
}
while
the
scripts
are
copied
directly
from
@
file
{
userspace
/
rootfs_override
/
wr
/
bin
}.
The
following
tools
and
scripts
are
provided
:
@
table
@
file
...
...
@@ -838,7 +836,7 @@ The most important tools in @file{userspace/tools} are the following:
The
program
is
a
simple
program
for
talking
with
serial
ports
.
@
item
wr_phytool
A
tool
to
read
and
write
PHY
registers
in
the
switch
A
tool
to
read
and
write
PHY
registers
in
the
switch
.
@
item
wr_mon
A
simple
monitor
of
White
Rabbit
status
.
It
prints
to
@
i
{
stdout
}
...
...
@@ -880,6 +878,20 @@ The most important tools in @file{userspace/tools} are the following:
for each port and for the RTU daemon. The @t{--help} option
lists all configuration items of the tool.
@item apply_dot-config
The script is used to apply @t{dot-config} settings to the
current configuration files. It is run at boot time before
any service is started. The @t{dot-config} mechanism is
documented in the @i{@sc{wrs} Users'
Manual
}.
@
item
change_dot
-
config
This
script
changes
the
current
@
t
{
dot
-
config
}
file
.
It
is
designed
to
be
the
back
-
end
of
the
web
interface
,
when
changing
configuration
items
.
The
script
does
nothing
to
@
i
{
apply
}
the
changes
,
and
it
only
performs
editing
.
It
is
the
responsibility
of
the
caller
to
ensure
the
proper
service
is
restarted
with
the
new
configuration
.
@
item
sdb
-
read
The
tool
,
copied
from
the
@
t
{
fpga
-
config
-
space
}
project
,
is
documented
in
the
next
section
,
...
...
doc/wrs-user-manual.in
View file @
17d478da
...
...
@@ -281,28 +281,121 @@ only be performed by the manufacturer, not the final user.
@c ##########################################################################
@node
Kconfig Support
@chapter
Kconfig Support
@node
Configuration of the Device
@chapter
Configuration of the Device
After release 3.3 of this software package, we added Kconfig support
to wr-switch-sw. The user can ignore this step: building as usual
from a fresh checkout of @t
{
wr-switch-sw
}
silently selects
the default configuration.
to wr-switch-sw. If you build your software image (as documented
in the @i
{
@sc
{
wrs
}
Developer's Manual
}
), you can make some
configuration choices for your customized firmware image. But most
users are not expected to rebuild.
After release 4.1, we moved most of the configuration to run-time
(rather than build-time): the @t
{
.config
}
file that you create
with a ``@t
{
make menuconfig
}
'' or equivalent command, is now copied
to the @sc
{
wrs
}
filesystem and used during boot. Moreover, the
switch can download a new configuration at boot time, if so
configured. This allows customization of each installed switch
through a central server, without modifying the filesystem image in
each specimen.
You may exploit this @t
{
Kconfig
}
option to build firmware images
preconfigured for your own network.
@c ==========================================================================
@node Dynamic WRS Configuration
@section Dynamic WRS Configuration
The switch can boot using its internal @sc
{
nand
}
memory or as an NFS-Root
host. In the latter case configuration can be changed on the server,
and if a unit is replaced, a change in the @sc
{
dhcp
}
database is all
that's needed to recover network operation. But this option implies
some network traffic on your management network, as well as an NFS
server able to host all of your switches.
When a switch is booted from internal storage, we used to rely on
internal configuration (either selected at build time or modified
using @i
{
ssh
}
or the web interface). This approach doesn't scale
well to large installation, because if a device needs to be replaced,
its own configuration is lost.
With @i
{
dynamic configuration
}
, each @sc
{
wrs
}
device loads its own
configuration file each time it is booted, and applies the choices
before starting any service. The name of the configuration file can
include the @sc
{
mac
}
or @sc
{
ip
}
address of the device, to allow
running several switches with different configurations in the same
network.
@c ==========================================================================
@node The Configuration File
@section The Configuration File
The main configuration file for the @sc
{
wrs
}
is
@t
{
/wr/etc/dot-config
}
. You create this file by running ``@t
{
make
menuconfig
}
'' within @t
{
wr-switch-sw
}
, and making your choices.
You can also edit the text file, or run other configurators: @t
{
make xconfig
}
,
@t
{
make gconfig
}
, @t
{
make config
}
.
The configuration step creates @t
{
.config
}
, that you can copy to your
@sc
{
wrs
}
as @t
{
/wr/etc/dot-config
}
. After reboot, you'll see your
choices in effect.
The first configuration choice is @t
{
CONFIG
_
DOTCONF
_
URL
}
. If the
selected string is not empty, the Switch will download a new @t
{
dot-config
}
file, and replace the copy in local storage if it is different. If
the string is empty, no network access is performed.
@t
{
CONFIG
_
DOTCONF
_
URL
}
is of the form
``@i
{
protocol
}
@t
{
://
}
@i
{
host
}
@t
{
/
}
@i
{
pathname
}
''. The special upper-case
strings @t
{
IPADDR
}
and @t
{
MACADDR
}
are substituted with the current
addresses of the management port of the switch.
The three parts of the URL are as follows:
@table @i
@item protocol
We support @t
{
http
}
, @t
{
ftp
}
and @t
{
tftp
}
. Any other protocols
result in an error, and the @t
{
dot-config
}
file is not replaced.
@item host
The host can be an IP address, or a name. In order to use
a name you must specify a valid @t
{
CONFIG
_
DNS
_
SERVER
}
and
optionally @t
{
CONFIG
_
DNS
_
DOMAIN
}
. The values
in the current @t
{
dot-config
}
are used to load the new file.
@item path
The pathname can include directory components and @t
{
IPADDR
}
or @t
{
MACADDR
}
(or both).
@end table
For example this is a valid configuration for run-time update:
@smallexample
CONFIG
_
DOTCONF
_
URL="tftp://morgana/wrs-config-IPADDR"
CONFIG
_
DNS
_
SERVER="192.168.16.1"
CONFIG
_
DNS
_
DOMAIN="i.gnudd.com"
@end smallexample
And it results, in my case, in @t
{
wrs-config-192.168.16.9
}
being
served to the @sc
{
wrs
}
.
To change configuration, you are expected to run ``@t
{
make
menuconfig
}
'' (or @i
{
gconfig
}
or @i
{
kconfig
}
or the old text-mode
@i
{
config
}
) from the top-level directory of @i
{
wr-switch-sw
}
. To
silently enact the default configuration, run ``@t
{
make defconfig
}
''
(this is done by the normal build if no configuration is present).
Please remember that the new @t
{
dot-config
}
should include a valid
@t
{
DOTCONF
_
URL
}
setting, or you won't be able to update the configuration
at the next boot. In any case, you can always copy a configuration
file using @i
{
ssh
}
, or use the web interface to change the configuration.
Changes performed using the web interface are immediately active, because
the web server takes proper action; the new file copied over with @i
{
ssh
}
,
or any hand-edits, are only effective at next boot, unless overwritten by
a remote configuration file.
The released firmware image uses the default configuration, but we'll
soon offer the option to change most of these values at boot-t
ime
(by downloading configuration from a network server) or run-time.
@c ==========================================================================
@node Configuration Items that Apply at Build T
ime
@section Configuration Items that Apply at Build Time
The following configuration options are available
The following items in @t
{
dot-config
}
are used at build time; changing
them in the installed version has no effect:
@table @code
...
...
@@ -313,6 +406,31 @@ The following configuration options are available
@t
{
configs/buildroot
}
directory; an absolute pathname is used
unchanged.
@item CONFIG
_
KEEP
_
ROOTFS
A boolean option for developers: if set the build script does
not delete the temporary copy of the generated filesystem and
reports its pathname in the build messages.
@end table
@c ==========================================================================
@node Configuration Items that Apply at Run Time
@section Configuration Items that Apply at Run Time
The following items in @t
{
dot-config
}
are used at run time: at every
boot the value (the old one or the just-downloaded one) is used in the
appropriate way, before the respective service is started. When the
value is changed by the web interface, proper action is taken.
@table @code
@item CONFIG
_
DOTCONF
_
URL
The location of a config file to be used at a replacement
the next time the system boots. See @ref
{
Dynamic WRS Configuration
}
and @ref
{
The Configuration File
}
for details.
@item CONFIG
_
NTP
_
SERVER
The NTP server used to prime White Rabbit time, at system boot.
...
...
@@ -358,12 +476,6 @@ The following configuration options are available
unknown facility names will generate a runtime error on the switch.
All three strings default to ``@t
{
daemon.info
}
''.
@item CONFIG
_
KEEP
_
ROOTFS
A boolean option for developers: if set the build script does
not delete the temporary copy of the generated filesystem and
reports its pathname in the build messages.
@end table
@c ############################################################################
...
...
userspace/rootfs_override/etc/init.d/S20dot-config
0 → 100755
View file @
17d478da
#!/bin/sh
# This script applies the dot-config. It is a boot script, but actual
# functionality is moved to a separate binary, so the web interface
# could edit dot-config and run /wr/bin/apply_dot-config like we do here,
# without the need to rember wheter this is S20 or S10 during boot.
# First, read dot-config to get the new location, if any.
dotconfig
=
/wr/etc/dot-config
tmpconfig
=
/tmp/dot-config
if
[
-f
$dotconfig
]
;
then
.
$dotconfig
fi
# Create /etc/resolv.conf, so we can use it. /etc is ramdisk anyways
if
[
!
-z
"
$CONFIG_DNS_SERVER
"
]
;
then
echo
"nameserver
$CONFIG_DNS_SERVER
"
>
/etc/resolv.conf
if
[
!
-z
"
$CONFIG_DNS_DOMAIN
"
]
;
then
echo
"domain
$CONFIG_DNS_DOMAIN
"
>>
/etc/resolv.conf
fi
fi
# If we are expected to get a new dot-conf, do it
if
[
-n
"
$CONFIG_DOTCONF_URL
"
]
;
then
# replace IPADDR and MACADDR, to have a device-specific name
macaddr
=
$(
cat
/sys/class/net/eth0/address
)
ipaddr
=
$(
ifconfig eth0 |
grep
inet |
cut
-d
:
-f
2 |
cut
'-d '
-f
1
)
URL
=
$(
echo
$CONFIG_DOTCONF_URL
|
\
sed
-e
s/MACADDR/
$macaddr
/
-e
s/IPADDR/
$ipaddr
/
)
# split the parts, as we need to handle tftp by hand
proto
=
$(
echo
$URL
|
cut
-d
:
-f
1
)
host
=
$(
echo
$URL
|
cut
-d
/
-f
3
)
filename
=
$(
echo
$URL
|
cut
-d
/
-f
4-
)
rm
-f
$tmpconfig
case
$proto
in
http|ftp
)
wget
$URL
-O
$tmpconfig
;;
tftp
)
tftp
-g
-r
"
$filename
"
-l
$tmpconfig
$host
;;
*
)
echo
"Invalid URL for dot-config:
\"
$URL
\"
"
>
& 2
;;
esac
# If it exists and it is not empty or awfully small, trust it
if
[
-f
$tmpconfig
]
&&
[
$(
cat
$tmpconfig
|
wc
-c
)
-gt
200
]
;
then
cmp
-s
$tmpconfig
$dotconfig
||
cp
$tmpconfig
$dotconfig
fi
fi
# Finally, apply what we have, be it old or new
.
/wr/bin/apply_dot-config
userspace/rootfs_override/etc/rsyslog.conf
→
userspace/rootfs_override/etc/rsyslog.conf
.in
View file @
17d478da
File moved
userspace/rootfs_override/wr/bin/apply_dot-config
0 → 100755
View file @
17d478da
#!/bin/sh
# This script applies the current dot-config to make
# the choices users wanted. You can change the dot-config on flash,
# and call this script to apply changes (please note that some changes
# require restarting running processes). The script is called at
# every boot by /etc/init.d/S20dot-config
# We create a temporary file in /tmp, to avoid wearing flash if not
# needed. Then we replace the real file if different.
T
=
$(
mktemp
/tmp/config-XXXXXX
)
copy_conf
()
{
# busybox cmp exits 1 or 2 according to GNU man page
for
dest
in
$*
;
do
cmp
-s
$T
$1
||
cp
$T
$1
done
}
# Check and complain, but we need to edit some files even if unconfigured.
if
[
-f
/wr/etc/dot-config
]
;
then
.
/wr/etc/dot-config
configured
=
true
else
echo
"No /wr/etc/dot-config to use"
>
& 2
configured
=
false
fi
##### Actual configuration actions start here.
# A non-existent wr_date.conf means no NTP. So "rm" if unconfigured
if
[
!
-z
"
$CONFIG_NTP_SERVER
"
]
;
then
echo
"ntpserver
$CONFIG_NTP_SERVER
"
>
$T
copy_conf /wr/etc/wr_date.conf
else
rm
-f
/wr/etc/wr_date.conf
fi
# /etc/resolv.conf can be empty, so start empty
>
$T
if
[
!
-z
"
$CONFIG_DNS_SERVER
"
]
;
then
echo
"nameserver
$CONFIG_DNS_SERVER
"
>>
$T
if
[
!
-z
"
$CONFIG_DNS_DOMAIN
"
]
;
then
echo
"domain
$CONFIG_DNS_DOMAIN
"
>>
$T
fi
fi
copy_conf /etc/resolv.conf /usr/etc/resolv.conf
# rsyslog.conf is created from a template file, and busybox sed has -i
cp
/usr/etc/rsyslog.conf.in
$T
if
[
"
$CONFIG_REMOTE_SYSLOG_UDP
"
=
"y"
]
;
then
sed
-i
's/@@remote-host/@remote-host/'
$T
fi
if
[
!
-z
"
$CONFIG_REMOTE_SYSLOG_SERVER
"
]
;
then
sed
-i
'/remote-host/ s/^##//'
$T
sed
-i
"s/remote-host/
$CONFIG_REMOTE_SYSLOG_SERVER
/"
$T
fi
copy_conf /etc/rsyslog.conf /usr/etc/rsyslog.conf
# Fix SNMP values: for all not-empty configs remove comment and replace value
cp
/wr/etc/snmpd.conf.in
$T
set
|
grep
CONFIG_SNMP |
sed
's/=/ /'
|
while
read
varname value
;
do
if
[
-z
"
$value
"
]
;
then continue
;
fi
sed
-i
"/
$varname
/ s/^#//"
$T
sed
-i
"/
$varname
/ s/
$varname
/
$value
/"
$T
done
copy_conf /wr/etc/snmpd.conf
# Fix log values
cp
/wr/sbin/start-daemons.sh.in
$T
set
|
grep
CONFIG_WRS_LOG |
sed
's/=/ /'
|
while
read
varname value
;
do
if
[
-z
"
$value
"
]
;
then continue
;
fi
sed
-i
"/
$varname
/ s,
$varname
,
$value
,"
$T
done
copy_conf /wr/sbin/start-daemons.sh
userspace/rootfs_override/wr/bin/change_dot-config
0 → 100755
View file @
17d478da
#!/bin/sh
# Change a configuration item in dot-config. "=n" is special and it means
# the option is being unset. "=y" remains unquoted, all the rest is quoted.
# We still lack support for integers, not used in wrs' .config so far.
dotconfig
=
"/wr/etc/dot-config"
for
action
in
"
$*
"
;
do
# We accept both CONFIG_THIS= and THIS=
item
=
"CONFIG_
$(
echo
$action
|
cut
-d
=
-f
1 |
sed
's/^CONFIG_//'
)
"
value
=
$(
echo
$action
|
cut
-d
=
-f
2
)
if
[
"
$value
"
=
"n"
]
;
then
line
=
"#
$item
is not set"
else
if
[
"
$value
"
=
"y"
]
;
then
line
=
"
${
item
}
=y"
else
line
=
"
${
item
}
=
\"
$value
\"
"
fi
fi
# now, a config item may be a substring of another one: careful
sed
-i
-e
"/^
${
item
}
=/d"
-e
"/#
${
item
}
is/d"
$dotconfig
echo
$line
>>
$dotconfig
done
userspace/rootfs_override/wr/etc/snmpd.conf
→
userspace/rootfs_override/wr/etc/snmpd.conf
.in
View file @
17d478da
File moved
userspace/rootfs_override/wr/sbin/start-daemons.sh
→
userspace/rootfs_override/wr/sbin/start-daemons.sh
.in
View file @
17d478da
File moved
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