Age | Commit message (Collapse) | Author |
|
|
|
* Respect the session's negotiated maximum pdu length and split the
sending of our local addresses into multiple messages if necessary;
* Log sent/received addresses;
* Add new wrappers to send only one address (send_address_single)
and to send all addresses of the given address-family
(send_address_all). These wrappers create a temporary list of addresses
to be sent, and send_address() then acts on this last.
|
|
|
|
The previous value of 180 was just too long. If a neighbor get stuck in
the initialization FSM for more than 15 seconds, then there's certainly
something wrong and the session should be dropped.
A potential case of a neighbor getting stuck in the initialization
FSM is when both the local and the remote LSRs disable the LDPv4 GTSM
negotiation and there's a mismatch in their GTSM configuration (one is
enabled for GTSM while the other is not).
In this case, a smaller timeout allows for a quicker recovery of the
session when the configuration is fixed on either side.
|
|
This also finishes the missing bits from our RFC 7552 implementation
because GTSM is mandatory for LDPv6.
To avoid any kind of interoperability problems, I included a few
knobs to enable/disable GTSM on a per-address-family and per-neighbor
basis. Cisco's LDPv6 implementation, for instance, doesn't support GTSM.
"reads good" claudio@
|
|
The Configuration Sequence Number optional TLV is documented in RFC 5036,
pages 53 and 54.
Fixes IxANVL LDP test 23.10.
|
|
This prevents neighbors stuck in the initialization FSM to linger forever
as long as the associated transport connection is up.
This timeout can be seen in the 'Session Initialization State Transition
Diagram' of RFC 5036. The RFC, however, doesn't specify how much we
should wait. Let's use 180 seconds for that, the default LDP hold time.
Fixes IxANVL LDP test 6.15.
|
|
|
|
|
|
|
|
The benefits of this include:
* clean up of the ldpd global namespace;
* improved readability;
* more hints to the compiler/linker to generate more efficient code.
Whenever possible, move global static variables to a smaller scope
(function).
All extern variables are now declared in header files to avoid unnecessary
duplication.
This patch also cleans up the indentation of all function prototypes
and global variables.
|
|
This includes:
* Full compliance to RFC 7552;
* Support for MD5 on LDPov6 sessions;
* Support for pseudowires over IPv6 LSPs (we're probably the world's
first implementation doing this);
* Support for the IPv6 explicit-null label;
* Knob to specify the prefered address-family for TCP transport
connections;
* Knob to use cisco non-compliant format to send and interpret the
Dual-Stack capability TLV.
|
|
Nothing really interesting here.
|
|
Copying by straight assignment is shorter, easier to read and has a
higher level of abstraction. We'll only avoid it when copying from an
unaligned source (e.g., network buffers).
In addition, copy in_addr structs directly.
|
|
I screwed up everything... trying to fix now.
|
|
|
|
|
|
We were using several different names for the same thing in our log
messages: neighbor, neighbor ID, nbr ID and LSR ID.
Standardize to always use "lsr-id" to refer to a neighbor.
Also:
* Use log_warnx() instead of log_warn() when appropriate;
* Use fatal(x) instead of err(x) when appropriate;
* Fix some inconsistent log messages.
|
|
With the advent of IPv6 support, a single neighbor can have two different
transport-addresses: one for ipv4 and one for ipv6. In order to define
neighbor-specific parameters in an indistinguishable way, define them
by lsr-id. This way we can switch between LDPov4 and LDPov6 and keep
the same configuration.
|
|
The logic of the previous code was to accept all TCP connection requests
(destined to port 646) and create a tcp_conn structure for each them. Once
the first packet of a connection was received, we would analyze the
LDP Initialization message and identify its origin by looking at the
LSR-ID field.
When parsing a received TCP packet, we would need to distinguish between
two cases: tcp packet from an LDP neighbor and tcp packet from a newborn
connection (not associated with any neighbor yet). For this reason,
the session_read() function was quite complicated.
Also, we were not keeping track of the allocated tcp_conn structures. So,
we were subject to memory leaks and even DOS attacks.
With this patch, we also accept all TCP connection requests, but with two
major differences:
* We identify the neighbor by the source address of the SYN
packet. This is possible because we don't support label spaces, so
the transport-address by itself is enough to identify a neighbor,
we don't need to wait for the Initialization message;
* If there's no matching adjacency for this neighbor, then we start a
timer of 5 seconds. If we receive a Hello packet from this neighbor
within this interval, then we stop this timer and move on in
the Initialization state machine. Otherwise, we send a No Hello
Notification message and close the socket. We try to avoid sending
the No Hello notification as much as possible because it triggers the
backoff exponential in the remote peer, which considerably slow down
the session establishment process.
In summary, this new approach allows for a simpler code and fixes the
memory leak problem mentioned before.
|
|
Do not start the exponential backoff timer when playing the passive role
of the session establishment process.
RFC 5036 - Section 2.5.3 says:
"The specific session establishment action that must be
delayed is the attempt to open the session transport connection by
the LSR playing the active role".
|
|
|
|
Address and Address Withdraw messages have the exact same format, only
their type is different.
|
|
This patch doesn't introduce any logical change.
|
|
This will be especially important when we add support for IPv6, because
we'll not be able to use the router-id as the transport-address in
this case.
|
|
|
|
|
|
ok claudio@
|
|
ok claudio@
|
|
Under some rare circumstances the following can happen:
1 - one neighbor sends a label withdraw followed by a fatal notification
message;
2 - ldpe parses the label withdraw and sends it to lde;
3 - ldpe parses the fatal notification message and closes the session;
4 - lde processes the label withdraw and asks ldpe to send a label release;
5 - at around the same time, ldpe restarts the session with the neighbor;
6 - ldpe processes the lde message and then sends a label release to the new
neighbor.
The problem is that we don't want a message enqueue to a neighbor to be sent
after the session is restarted. If a session is closed, all the enqueued
messages should be discarded.
To acomplish this, we update the peerid of the nbr structure everytime the
session is established.
ok claudio@
|
|
ok claudio@
|
|
ok claudio@
|
|
ok claudio@
|
|
LDP has several modes of operation, it was designed in that way so it
could run on legacy equipment like ATM/FR switches with very strict
memory limitations.
For modern hardware there's no point on using either the "Conservative
Label Retention" or "Downstream On Demand" modes of operation since they
save memory at cost of blackholing traffic when routing changes. Major
vendors implement only the "Liberal Label Retention" and "Downstream
Unsolicited" modes for non ATM/FR hardware. Let's do that too.
As for using either "Independent Control" or "Ordered Control", let's
stick with the first option mainly because it's easier to implement
and because it doesn't really matter which control mode is used. For
reference, Cisco implements only "Independent Control" and Juniper only
"Ordered Control". Both modes are interoperable.
The point of supporting only one combination of all modes of operation
is that it will allow for the writing of a simpler code without removing
useful functionality.
ok claudio@
|
|
|
|
|
|
functions into a single generic function.
Add a few error checks and implement parsing of optional tlvs.
Putting it all together helps avoid to code duplication and improve
maintainability.
|
|
if_del(): this function is always called after an IF_EVT_DOWN event so
there's no need to cleanup things here;
nbr_new(): C structs shouldn't be copied directly.
OK claudio@
|
|
There's no need the pass a whole lde_nbr structure as argument if we
want only the neighbor IP address.
Also, remove the lde_nbr_del() prototype on lde.h because it's a
duplicate.
OK claudio@
|
|
OK claudio@
|
|
OK claudio@
|
|
* Send an extra Hello message before attempting to connect to a remote
peer to guarantee that it formed an adjacency with us as well;
* Don't wait for the first timeout to send the first Hello message.
Both tricks together will allow for fast session establish since with both
optimizations passive role neighbors can open the connection immediatly by
sending and receiving the hellos at the same time as the TCP session.
From Renato Westphal
|
|
it belongs only _after_ receiving an Initialization message containing
the information we need. Before an Initialization message is received,
the TCP connection shouldn't be associated with any neighbor/adjacency.
Therefor refactor that part into a own module.
From Renato Westphal
|
|
Refactor adjacencies out of the neighbor handling so that it is possible to
have more complex topologies with targeted sessions.
From Renato Westphal
|
|
According with the section 2.5.3 of RFC 5036, an LSR must throttle its
session setup retry attempts with an exponential backoff in situations
where Initialization messages are being NAK'd (because of disagreements
on session parameters). It doesn't mention using this procedure for TCP
connection failures. With that said, start the inactive delay timer only
after receiving an appropriate notification message.
When playing the active role of the initialization process, throttle the
session setup retry attempts by not connecting to the remote peer. When
playing the passive role, throttle the session setup retry attempts by
delaying the processing of the received Initialization message.
Diff by Renato Westphal, adjusted by myself
|
|
* Remove the unused NBR_EVT_DOWN event;
* Print the FSM transitions before performing the appropriate actions. In
this way nested calls to nbr_fsm() won't print the state transitions in
reverse order;
* When playing the active role of the initialization process, transition
from NBA_STA_PRESENT to NBR_STA_INITIAL before going to NBR_STA_OPENSENT;
* Call session_shutdown() on nbr_ktimeout() to remove duplicated code;
* Notify the lde process when a neighbor is deleted (discovery timeout);
* Fix a few memory leaks on nbr_del().
Diff from Renato Westphal.
|
|
to send a keepalive packet when a other PDU was sent out.
Also add a missing NBR_EVT_PDU_RCVD call to recv_address() which restarts
the session keepalive timeout. All other places already do that.
Diff by Renato Westphal
|
|
interface.
Remove the iface pointer from the 'nbr' structure because it's not
needed anymore.
Diff from Renato Westphal
|
|
Support for per-interface labelspaces is only necessary for legacy ATM/FR
interfaces running in cell-mode. We shouldn't worry about this.
For platform-wide label spaces the label space id is always 0.
Diff by Renato Westphal
|
|
Diff from Renato Westphal
|