]> git.ipfire.org Git - thirdparty/lldpd.git/blame - README.md
Fix macos warnings at compile time.
[thirdparty/lldpd.git] / README.md
CommitLineData
1aed5ced 1# lldpd: implementation of IEEE 802.1ab (LLDP)
43c02e7b 2
fae9dd45 3![Build Status](https://github.com/lldpd/lldpd/workflows/CI/badge.svg)
ce05de54 4
9b50cef9 5 https://lldpd.github.io/
f0c42642 6
1aed5ced 7## Features
4b292b55 8
43c02e7b
VB
9LLDP (Link Layer Discovery Protocol) is an industry standard protocol
10designed to supplant proprietary Link-Layer protocols such as
11Extreme's EDP (Extreme Discovery Protocol) and CDP (Cisco Discovery
12Protocol). The goal of LLDP is to provide an inter-vendor compatible
13mechanism to deliver Link-Layer notifications to adjacent network
14devices.
15
16lldpd implements both reception and sending. It also implements an
17SNMP subagent for net-snmp to get local and remote LLDP
f7f82e1e 18information. The LLDP-MIB is partially implemented but the most useful
b193e97e 19tables are here. lldpd also partially implements LLDP-MED.
43c02e7b 20
f7f82e1e 21lldpd supports bridge, vlan and bonding.
c0cdd011 22
2b35e2d0
VB
23The following OS are supported:
24
25 * FreeBSD
26 * GNU/Linux
ac57139f 27 * macOS
2b35e2d0
VB
28 * NetBSD
29 * OpenBSD
f7f82e1e 30 * Solaris
2b35e2d0 31
032c0cf4
VB
32Windows is not supported but you can use
33[WinLLDPService](https://github.com/raspi/WinLLDPService/) as a
34transmit-only agent.
35
1aed5ced 36## Installation
4b292b55 37
7edd995b 38For general instructions [prefer the
9b50cef9 39website](https://lldpd.github.io/installation.html),
7edd995b 40including building from released tarballs.
ba666663 41
7edd995b 42To compile lldpd from Git, use the following commands:
00402c76 43
7edd995b 44 ./autogen.sh
00402c76
VB
45 ./configure
46 make
47 sudo make install
52ac3f37 48
13dce469
VB
49lldpd uses privilege separation to increase its security. Two
50processes, one running as root and doing minimal stuff and the other
51running as an unprivileged user into a chroot doing most of the stuff,
00402c76
VB
52are cooperating. You need to create a user called `_lldpd` in a group
53`_lldpd` (this can be change with `./configure`). You also need to
ba666663
VB
54create an empty directory `/usr/local/var/run/lldpd` (it needs to be
55owned by root, not `_lldpd`!). If you get fuzzy timestamps from
56syslog, copy `/etc/locatime` into the chroot.
13dce469 57
2b35e2d0 58`lldpcli` lets one query information collected through the command
33aced7a 59line. If you don't want to run it as root, just install it setuid or
00402c76 60setgid `_lldpd`.
43c02e7b 61
a244ecfb
VB
62## Installation (Docker)
63
64You can use Docker to run `lldpd`:
65
66 docker run --rm --net=host --uts=host \
67 -v /etc/os-release:/etc/os-release \
68 --cap-add=NET_RAW --cap-add=NET_ADMIN \
69 --name lldpd \
70 ghcr.io/lldpd/lldpd:latest
71
97c12712
VB
72In place of `latest` which provides you with the latest stable
73version, you may use `1`, `1.0`, `1.0.12` to match specific versions,
74or `master` to get the development version.
75
a244ecfb
VB
76To execute `lldpcli`, use:
77
78 docker exec lldpd lldpcli show neighbors
79
80Or to get the command-line:
81
82 docker exec -it lldpd lldpcli
83
1aed5ced 84## Installation (macOS)
e66b7f34 85
ac57139f 86The same procedure as above applies for macOS. However, there are
92f5db08 87simpler alternatives:
29e300e5 88
37e9556e 89 1. Use [Homebrew](https://brew.sh):
e66b7f34 90
92f5db08
VB
91 brew install lldpd
92 # Or, for the latest version:
fae9dd45 93 brew install https://raw.github.com/lldpd/lldpd/master/osx/lldpd.rb
b708297c 94
518eb927
VB
95 2. Build an OS X installer package which should work on the same
96 version of OS X (it is important to use a separate build
97 directory):
98
462d8b6c 99 mkdir build && cd build
87bb9a1b 100 ../configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/private/etc --with-embedded-libevent \
06987a24 101 --without-snmp
737afb35 102 make -C osx pkg
b708297c 103
ac57139f 104 If you want to compile for an older version of macOS, you need
518eb927 105 commands like those:
6b7d841c
VB
106
107 mkdir build && cd build
108 ../configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/private/etc --with-embedded-libevent \
06987a24 109 --without-snmp \
518eb927
VB
110 CFLAGS="-mmacosx-version-min=11.1" \
111 LDFLAGS="-mmacosx-version-min=11.1"
6b7d841c
VB
112 make -C osx pkg
113
114 You can check with `otool -l` that you got what you expected in
518eb927
VB
115 term of supported versions. If you are running on ARM64, you can
116 configure a binary supporting both architectures by adding
117 `ARCHS="arm64 x86_64"` to the arguments of the `make` command.
6b7d841c 118
92f5db08
VB
119If you don't follow the above procedures, you will have to create the
120user/group `_lldpd`. Have a look at how this is done in
121`osx/scripts/postinstall`.
b708297c 122
1aed5ced 123## Installation (Android)
8b0ca98e 124
8aed1c35
ZC
1251. Don't clone the repo or download the master branch from GitHub. Instead, download the official release from the website [https://lldpd.github.io/](https://lldpd.github.io/installation.html#install-from-source). Unpack into a working directory.
126
1272. Download the [Android NDK](https://developer.android.com/ndk/downloads#stable-downloads) (version 22 or later). Unpack into a working directory next to the `lldpd` directory.
128
1293. Install `automake`, `libtool`, and `pkg-config`. (`sudo apt-get install automake libtool pkg-config`)
130
1314. In the root of the `lldpd` directory, make a `compile.sh` file containing this script:
132```sh
133export TOOLCHAIN=$PWD/android-ndk/toolchains/llvm/prebuilt/linux-x86_64
134export TARGET=armv7a-linux-androideabi
135export API=30
136# DO NOT TOUCH BELOW
137export AR=$TOOLCHAIN/bin/llvm-ar
138export CC=$TOOLCHAIN/bin/$TARGET$API-clang
139export CXX=$TOOLCHAIN/bin/$TARGET$API-clang++
140export LD=$TOOLCHAIN/bin/ld
141export RANLIB=$TOOLCHAIN/bin/llvm-ranlib
142export STRIP=$TOOLCHAIN/bin/llvm-strip
143export AS=$CC
144./autogen.sh
145mkdir -p build && cd build
146../configure \
147 --host=$TARGET \
148 --with-sysroot=$TOOLCHAIN/sysroot \
149 --prefix=/system \
150 --sbindir=/system/bin \
151 --runstatedir=/data/data/lldpd \
152 --with-privsep-user=root \
153 --with-privsep-group=root \
154 PKG_CONFIG=/bin/false
155make
156make install DESTDIR=$PWD/install
157```
158
1595. In the **Android NDK** directory, locate the `toolchains/llvm/prebuilt/linux-x86_64` directory and change the `TOOLCHAIN` variable of the above script to match the path where the `linux-x86_64` directory resides.
160
161```sh
162export TOOLCHAIN=$PWD/android-ndk-r22b-linux-x86_64/android-ndk-r22b/toolchains/llvm/prebuilt/linux-x86_64
163```
164
1656. Determine the CPU architecture target (`adb shell getprop ro.product.cpu.abi`). Change the `TARGET` variable in the above script to match the target architecture. The target name will not exactly match the output of the `adb` command as there will be a trailing suffix to the target name, so look in the `linux-x86_64/bin` directory for the `clang` file that starts with the CPU architecture target. Don't include the API version in the target name.
166```sh
167$ adb shell getprop ro.product.cpu.abi
168armeabi-v7a
169```
170```sh
171linux-x86_64/bin$ ls *-clang
172aarch64-linux-android21-clang armv7a-linux-androideabi23-clang i686-linux-android26-clang
173aarch64-linux-android22-clang armv7a-linux-androideabi24-clang i686-linux-android27-clang
174aarch64-linux-android23-clang armv7a-linux-androideabi26-clang i686-linux-android28-clang
175aarch64-linux-android24-clang armv7a-linux-androideabi27-clang i686-linux-android29-clang
176aarch64-linux-android26-clang armv7a-linux-androideabi28-clang i686-linux-android30-clang
177aarch64-linux-android27-clang armv7a-linux-androideabi29-clang x86_64-linux-android21-clang
178aarch64-linux-android28-clang armv7a-linux-androideabi30-clang x86_64-linux-android22-clang
179aarch64-linux-android29-clang i686-linux-android16-clang x86_64-linux-android23-clang
180aarch64-linux-android30-clang i686-linux-android17-clang x86_64-linux-android24-clang
181armv7a-linux-androideabi16-clang i686-linux-android18-clang x86_64-linux-android26-clang
182armv7a-linux-androideabi17-clang i686-linux-android19-clang x86_64-linux-android27-clang
183armv7a-linux-androideabi18-clang i686-linux-android21-clang x86_64-linux-android28-clang
184armv7a-linux-androideabi19-clang i686-linux-android22-clang x86_64-linux-android29-clang
185armv7a-linux-androideabi21-clang i686-linux-android23-clang x86_64-linux-android30-clang
186armv7a-linux-androideabi22-clang i686-linux-android24-clang
187```
188```sh
189export TARGET=armv7a-linux-androideabi
190```
191
1927. Set the `API` variable in the script above to your target API version. Check in the same `linux-x86_64/bin` to ensure the API you are targeting has a supported `clang` file for that CPU architecture and version. As of this writing, there is support for API `21-30` included for all architectures and some CPU architectures supported back to version `16`.
193```sh
194export API=30
195```
196
1978. Run the compile script (`./compile.sh`).
198
1999. Copy the `./bin/*` and `./lib/*.so` files from `lldpd/build/install/system` to the target system (`./bin/*` to `/system/bin`, `./lib/*.so` to `/system/lib64`):
200```sh
201# Push files to target
202cd build/install/system
203adb shell mkdir -p /sdcard/Download/lldpd/bin
204adb push bin/lldpcli /sdcard/Download/lldpd/bin/lldpcli
205adb push bin/lldpd /sdcard/Download/lldpd/bin/lldpd
206adb shell mkdir -p /sdcard/Download/lldpd/lib64
207adb push lib/liblldpctl.so /sdcard/Download/lldpd/lib64/liblldpctl.so
208
209# Enter target shell and move files
210adb shell
211# Run as root for all commands
212$ su
213# Make /system writeable
214$ mount -o rw,remount /system
215$ mv /sdcard/Download/lldpd/bin/lldpcli /system/bin/lldpcli
216$ chmod 755 /system/bin/lldpcli
217$ chown root:shell /system/bin/lldpcli
218$ mv /sdcard/Download/lldpd/bin/lldpd /system/bin/lldpd
219$ chmod 755 /system/bin/lldpd
220$ chown root:shell /system/bin/lldpd
221# $ touch /system/bin/lldpctl
222# $ chmod 755 /system/bin/lldpctl
223# $ chown root:shell /system/bin/lldpctl
224$ mv /sdcard/Download/lldpd/lib64/liblldpctl.so /system/lib64/liblldpctl.so
225$ chmod 644 /system/lib64/liblldpctl.so
226$ chown root:root /system/lib64/liblldpctl.so
227# Make /system readonly again
228$ mount -o ro,remount /system
229# Might not be necessary on some systems
230$ mkdir /data/data/lldpd
231$ chmod 700 /data/data/lldpd
232$ chown shell:shell /data/data/lldpd
233# Clean up
234$ rm -rf /sdcard/Download/lldpd
235```
8b0ca98e 236
1aed5ced 237## Usage
4b292b55 238
031118c4
VB
239lldpd also implements CDP (Cisco Discovery Protocol), FDP (Foundry
240Discovery Protocol), SONMP (Nortel Discovery Protocol) and EDP
241(Extreme Discovery Protocol). However, recent versions of IOS should
242support LLDP and most Extreme stuff support LLDP. When a EDP, CDP or
243SONMP frame is received on a given interface, lldpd starts sending
244EDP, CDP, FDP or SONMP frame on this interface. Informations collected
245through EDP/CDP/FDP/SONMP are integrated with other informations and
2b35e2d0 246can be queried with `lldpcli` or through SNMP.
43c02e7b 247
c167357d
VB
248More information:
249 * http://en.wikipedia.org/wiki/Link_Layer_Discovery_Protocol
250 * http://standards.ieee.org/getieee802/download/802.1AB-2005.pdf
29203ab2 251 * https://gitlab.com/wireshark/wireshark/-/wikis/LinkLayerDiscoveryProtocol
c167357d 252
1aed5ced 253## Compatibility with older kernels
c167357d 254
389ec9d4
VB
255If you have a kernel older than Linux 4.0, you need to compile lldpd with
256`--enable-oldies` to enable some compatibility functions: otherwise, lldpd will
257only rely on Netlink to receive wireless, bridge, bond and VLAN information.
c167357d 258
43c02e7b
VB
259For bonding, you need 2.6.24 (in previous version, PACKET_ORIGDEV
260affected only non multicast packets). See:
00402c76
VB
261
262 * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=80feaacb8a6400a9540a961b6743c69a5896b937
263 * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=8032b46489e50ef8f3992159abd0349b5b8e476c
43c02e7b 264
c8851c73 265Otherwise, a packet received on a bond will be affected to all
c167357d
VB
266interfaces of the bond. In this case, lldpd will affect a received
267randomly to one of the interface (so a neighbor may be affected to the
268wrong interface).
43c02e7b 269
0da01fd6 270On 2.6.27, we are able to receive packets on real interface for enslaved
21d89e7d 271devices. This allows one to get neighbor information on active/backup
43c02e7b
VB
272bonds. Without the 2.6.27, lldpd won't receive any information on
273inactive slaves. Here are the patchs (thanks to Joe Eykholt):
00402c76
VB
274
275 * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=0d7a3681232f545c6a59f77e60f7667673ef0e93
276 * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=cc9bd5cebc0825e0fabc0186ab85806a0891104f
277 * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=f982307f22db96201e41540295f24e8dcc10c78f
43c02e7b 278
63aebf55
VB
279On FreeBSD, only a recent 9 kernel (9.1 or more recent) will allow to
280send LLDP frames on enslaved devices. See this bug report for more
281information:
282
283 * http://www.freebsd.org/cgi/query-pr.cgi?pr=138620
284
c167357d 285Some devices (notably Cisco IOS) send frames tagged with the native
50724a52
VB
286VLAN while they should send them untagged. If your network card does
287not support accelerated VLAN, you will receive those frames as long as
288the corresponding interface exists (see below). However, if your
289network card handles VLAN encapsulation/decapsulation (check with
5f7d1cd5
VB
290`ethtool -k`), you need a recent kernel to be able to receive those
291frames without listening on all available VLAN. Starting from Linux
2922.6.27, lldpd is able to capture VLAN frames when VLAN acceleration is
293supported by the network card. Here is the patch:
49697208 294
50724a52
VB
295 * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=bc1d0411b804ad190cdadabac48a10067f17b9e6
296
297On some other versions, frames are sent on VLAN 1. If this is not the
298native VLAN and if your network card support accelerated VLAN, you
299need to subscribe to this VLAN as well. The Linux kernel does not
300provide any interface for this. The easiest way is to create the VLAN
301for each port:
5f7d1cd5
VB
302
303 ip link add link eth0 name eth0.1 type vlan id 1
304 ip link set up dev eth0.1
305
306You can check both cases using tcpdump:
307
308 tcpdump -epni eth0 ether host 01:80:c2:00:00:0e
309 tcpdump -eni eth0 ether host 01:80:c2:00:00:0e
310
311If the first command does not display received LLDP packets but the
312second one does, LLDP packets are likely encapsulated into a VLAN:
313
314 10:54:06.431154 f0:29:29:1d:7c:01 > 01:80:c2:00:00:0e, ethertype 802.1Q (0x8100), length 363: vlan 1, p 7, ethertype LLDP, LLDP, name SW-APP-D07.VTY, length 345
315
50724a52
VB
316In this case, just create VLAN 1 will fix the situation. There are
317other solutions:
318
319 1. Disable VLAN acceleration on the receive side (`ethtool -K eth0
320 rxvlan off`) but this may or may not work. Check if there are
321 similar properties that could apply with `ethtool -k eth0`.
f84199dd
VB
322 2. Put the interface in promiscuous mode with `ip link set
323 promisc on dev eth0`.
50724a52 324
f4da5f84
VB
325The last solution can be done directly by `lldpd` (on Linux only) by
326using the option `configure system interface promiscuous`.
327
50724a52 328On modern networks, the performance impact should be nonexistent.
5f7d1cd5 329
1aed5ced 330## Development
426ee11e
VB
331
332During development, you may want to execute lldpd at its current
3bd5a878 333location instead of doing `make install`. The correct way to do this is
426ee11e
VB
334to issue the following command:
335
336 sudo libtool execute src/daemon/lldpd -L $PWD/src/client/lldpcli -d
337
338You can append any further arguments. If lldpd is unable to find
339`lldpcli` it will start in an unconfigured mode and won't send or
340accept LLDP frames.
341
8cd1f2d0 342There is a general test suite with `make check`. It's also possible to
f6ad9aa7 343run integration tests. They need [pytest](http://pytest.org/latest/)
e0a84778 344and rely on Linux containers to be executed.
8cd1f2d0 345
76bae8b9
VB
346To enable code coverage, use:
347
348 ../configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
28d521e2
VB
349 --enable-sanitizers --enable-gcov --with-snmp \
350 CFLAGS="-O0 -g"
76bae8b9
VB
351 make
352 make check
353 # maybe, run integration tests
354 lcov --base-directory $PWD/src/lib \
355 --directory src --capture --output-file gcov.info
356 genhtml gcov.info --output-directory coverage
357
14d35a08 358## Fuzzing
14d35a08 359
261f3af4 360### With [libfuzzer](https://llvm.org/docs/LibFuzzer.html)
14d35a08 361
dc13f3e6 362Using address sanitizer:
261f3af4
AS
363```bash
364export CC=clang
365export CFLAGS="-O1 -fno-omit-frame-pointer -gline-tables-only -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=fuzzer-no-link"
366export LIB_FUZZING_ENGINE="-fsanitize=fuzzer"
367```
0fa28337 368
dc13f3e6 369Using undefined-behaviour sanitizer:
261f3af4
AS
370```bash
371export CC=clang
372export CFLAGS="-O1 -fno-omit-frame-pointer -gline-tables-only -fsanitize=array-bounds,bool,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unsigned-integer-overflow,unreachable,vla-bound,vptr -fno-sanitize-recover=array-bounds,bool,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,vla-bound,vptr -fsanitize=fuzzer-no-link"
373export LIB_FUZZING_ENGINE="-fsanitize=fuzzer"
374```
fa2ab06c 375
dc13f3e6 376Using memory sanitizer:
261f3af4
AS
377```bash
378export CC=clang
379export CFLAGS="-O1 -fno-omit-frame-pointer -gline-tables-only -fsanitize=memory -fsanitize-memory-track-origins -fsanitize=fuzzer-no-link"
380export LIB_FUZZING_ENGINE="-fsanitize=fuzzer"
381```
fa2ab06c 382
dc13f3e6 383Build and run:
261f3af4
AS
384```
385./configure --disable-shared --enable-pie --enable-fuzzer=$LIB_FUZZING_ENGINE
386make
387cd tests/
388./fuzz_cdp fuzzing_seed_corpus/fuzz_cdp_seed_corpus
389./fuzz_edp fuzzing_seed_corpus/fuzz_edp_seed_corpus
390./fuzz_lldp fuzzing_seed_corpus/fuzz_lldp_seed_corpus
391./fuzz_sonmp fuzzing_seed_corpus/fuzz_sonmp_seed_corpus
392```
fa2ab06c 393
261f3af4
AS
394### With [AFL++](https://aflplus.plus)
395
396You can use AFL++ to test some other aspects of lldpd. To test frame decoding:
397```bash
398export CC=afl-clang-fast
399./configure --disable-shared --enable-pie
400make clean check
401cd tests
402mkdir inputs
403mv *.pcap inputs
404afl-fuzz -i inputs -o outputs ./decode @@
405```
14d35a08 406
1aed5ced 407## Embedding
4b292b55
VB
408
409To embed lldpd into an existing system, there are two point of entries:
410
411 1. If your system does not use standard Linux interface, you can
412 support additional interfaces by implementing the appropriate
e12c2365
VB
413 `struct lldpd_ops`. You can look at
414 `src/daemon/interfaces-linux.c` for examples. Also, have a look at
415 `interfaces_update()` which is responsible for discovering and
416 registering interfaces.
4b292b55 417
2b35e2d0 418 2. `lldpcli` provides a convenient way to query `lldpd`. It also
4b292b55
VB
419 comes with various outputs, including XML which allows one to
420 parse its output for integration and automation purpose. Another
421 way is to use SNMP support. A third way is to write your own
422 controller using `liblldpctl.so`. Its API is described in
423 `src/lib/lldpctl.h`. The custom binary protocol between
424 `liblldpctl.so` and `lldpd` is not stable. Therefore, the library
425 should always be shipped with `lldpd`. On the other hand, programs
426 using `liblldpctl.so` can rely on the classic ABI rules.
427
1aed5ced 428## Troubleshooting
22f1ea46
VB
429
430You can use `tcpdump` to look after the packets received and send by
431`lldpd`. To look after LLDPU, use:
432
433 tcpdump -s0 -vv -pni eth0 ether dst 01:80:c2:00:00:0e
434
45f3c773
VB
435Intel X710 cards may handle LLDP themselves, intercepting any incoming
436packets. If you don't see anything through `tcpdump`, check if you
437have such a card (with `lspci`) and stop the embedded LLDP daemon:
438
439 for f in /sys/kernel/debug/i40e/*/command; do
440 echo lldp stop > $f
441 done
442
443This may also apply to the `ice` (Intel E8xx cards) driver. These
444steps are not necessary with a recent version of `lldpd` (1.0.11+).
445
1aed5ced 446## License
4b292b55 447
c882a2cf 448lldpd is distributed under the ISC license:
00402c76 449
51434125 450 > Permission to use, copy, modify, and/or distribute this software for any
00402c76
VB
451 > purpose with or without fee is hereby granted, provided that the above
452 > copyright notice and this permission notice appear in all copies.
453 >
454 > THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
455 > WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
456 > MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
457 > ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
458 > WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
459 > ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
460 > OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35f6f4fb
VB
461
462Also, `lldpcli` will be linked to GNU Readline (which is GPL licensed)
463if available. To avoid this, use `--without-readline` as a configure
464option.