summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_mplsvpn.c1
-rw-r--r--bgpd/bgp_packet.c386
-rw-r--r--bgpd/bgp_packet.h2
-rw-r--r--bgpd/bgp_route.c4
-rw-r--r--bgpd/bgp_route.h2
-rw-r--r--tests/bgp_mp_attr_test.c11
6 files changed, 162 insertions, 244 deletions
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 900bc487..83bb6ca9 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_packet.h"
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index d40c24c2..628c333a 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1591,11 +1591,29 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
return 0;
}
+/* Frontend for NLRI parsing, to fan-out to AFI/SAFI specific parsers */
+int
+bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
+{
+ switch (packet->safi)
+ {
+ case SAFI_UNICAST:
+ case SAFI_MULTICAST:
+ return bgp_nlri_parse_ip (peer, attr, packet);
+ case SAFI_MPLS_VPN:
+ case SAFI_MPLS_LABELED_VPN:
+ return bgp_nlri_parse_vpn (peer, attr, packet);
+ case SAFI_ENCAP:
+ return bgp_nlri_parse_encap (peer, attr, packet);
+ }
+ return -1;
+}
+
/* Parse BGP Update packet and make attribute object. */
static int
bgp_update_receive (struct peer *peer, bgp_size_t size)
{
- int ret;
+ int ret, nlri_ret;
u_char *end;
struct stream *s;
struct attr attr;
@@ -1603,10 +1621,16 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
bgp_size_t attribute_len;
bgp_size_t update_len;
bgp_size_t withdraw_len;
- struct bgp_nlri update;
- struct bgp_nlri withdraw;
- struct bgp_nlri mp_update;
- struct bgp_nlri mp_withdraw;
+ int i;
+
+ enum NLRI_TYPES {
+ NLRI_UPDATE,
+ NLRI_WITHDRAW,
+ NLRI_MP_UPDATE,
+ NLRI_MP_WITHDRAW,
+ NLRI_TYPE_MAX,
+ };
+ struct bgp_nlri nlris[NLRI_TYPE_MAX];
/* Status must be Established. */
if (peer->status != Established)
@@ -1620,10 +1644,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
/* Set initial values. */
memset (&attr, 0, sizeof (struct attr));
memset (&extra, 0, sizeof (struct attr_extra));
- memset (&update, 0, sizeof (struct bgp_nlri));
- memset (&withdraw, 0, sizeof (struct bgp_nlri));
- memset (&mp_update, 0, sizeof (struct bgp_nlri));
- memset (&mp_withdraw, 0, sizeof (struct bgp_nlri));
+ memset (&nlris, 0, sizeof nlris);
attr.extra = &extra;
s = peer->ibuf;
@@ -1660,14 +1681,18 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
/* Unfeasible Route packet format check. */
if (withdraw_len > 0)
{
- withdraw.afi = AFI_IP;
- withdraw.safi = SAFI_UNICAST;
- withdraw.nlri = stream_pnt (s);
- withdraw.length = withdraw_len;
- ret = bgp_nlri_sanity_check (peer, &withdraw);
- if (ret < 0)
- return -1;
-
+ nlris[NLRI_WITHDRAW].afi = AFI_IP;
+ nlris[NLRI_WITHDRAW].safi = SAFI_UNICAST;
+ nlris[NLRI_WITHDRAW].nlri = stream_pnt (s);
+ nlris[NLRI_WITHDRAW].length = withdraw_len;
+
+ if (bgp_nlri_sanity_check (peer, &nlris[NLRI_WITHDRAW]) < 0)
+ {
+ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_INVAL_NETWORK);
+ return -1;
+ }
+
if (BGP_DEBUG (packet, PACKET_RECV))
zlog_debug ("%s [Update:RECV] Unfeasible NLRI received", peer->host);
@@ -1716,7 +1741,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
if (attribute_len)
{
attr_parse_ret = bgp_attr_parse (peer, &attr, attribute_len,
- &mp_update, &mp_withdraw);
+ &nlris[NLRI_MP_UPDATE], &nlris[NLRI_MP_WITHDRAW]);
if (attr_parse_ret == BGP_ATTR_PARSE_ERROR)
{
bgp_attr_unintern_sub (&attr);
@@ -1752,15 +1777,17 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
if (update_len)
{
/* Set NLRI portion to structure. */
- update.afi = AFI_IP;
- update.safi = SAFI_UNICAST;
- update.nlri = stream_pnt (s);
- update.length = update_len;
+ nlris[NLRI_UPDATE].afi = AFI_IP;
+ nlris[NLRI_UPDATE].safi = SAFI_UNICAST;
+ nlris[NLRI_UPDATE].nlri = stream_pnt (s);
+ nlris[NLRI_UPDATE].length = update_len;
/* Check NLRI packet format and prefix length. */
- ret = bgp_nlri_sanity_check (peer, &update);
+ ret = bgp_nlri_sanity_check (peer, &nlris[NLRI_UPDATE]);
if (ret < 0)
{
+ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_INVAL_NETWORK);
bgp_attr_unintern_sub (&attr);
bgp_attr_flush (&attr);
return -1;
@@ -1768,226 +1795,117 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
stream_forward_getp (s, update_len);
}
-
- /* NLRI is processed only when the peer is configured specific
- Address Family and Subsequent Address Family. */
- if (peer->afc[AFI_IP][SAFI_UNICAST])
- {
- if (withdraw.length)
- bgp_nlri_parse (peer, NULL, &withdraw);
-
- if (update.length)
- bgp_nlri_parse (peer, NLRI_ATTR_ARG, &update);
-
- if (mp_update.length
- && mp_update.afi == AFI_IP
- && mp_update.safi == SAFI_UNICAST)
- bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update);
-
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP
- && mp_withdraw.safi == SAFI_UNICAST)
- bgp_nlri_parse (peer, NULL, &mp_withdraw);
-
- if (! attribute_len && ! withdraw_len)
- {
- /* End-of-RIB received */
- SET_FLAG (peer->af_sflags[AFI_IP][SAFI_UNICAST],
- PEER_STATUS_EOR_RECEIVED);
-
- /* NSF delete stale route */
- if (peer->nsf[AFI_IP][SAFI_UNICAST])
- bgp_clear_stale_route (peer, AFI_IP, SAFI_UNICAST);
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv4 Unicast from %s",
- peer->host);
- }
+
+ /* Parse any given NLRIs */
+ for (i = NLRI_UPDATE; i < NLRI_TYPE_MAX; i++)
+ {
+ /* We use afi and safi as indices into tables and what not. It would
+ * be impossible, at this time, to support unknown afi/safis. And
+ * anyway, the peer needs to be configured to enable the afi/safi
+ * explicitly which requires UI support.
+ *
+ * Ignore unknown afi/safi NLRIs.
+ *
+ * Note: this means nlri[x].afi/safi still can not be trusted for
+ * indexing later in this function!
+ *
+ * Note2: This will also remap the wire code-point for VPN safi to the
+ * internal safi_t point, as needs be.
+ */
+ if (!bgp_afi_safi_valid_indices (nlris[i].afi, &nlris[i].safi))
+ {
+ plog_info (peer->log,
+ "%s [Info] UPDATE with unsupported AFI/SAFI %u/%u",
+ peer->host, nlris[i].afi, nlris[i].safi);
+ continue;
+ }
+
+ /* NLRI is processed only when the peer is configured specific
+ Address Family and Subsequent Address Family. */
+ if (!peer->afc[nlris[i].afi][nlris[i].safi])
+ {
+ plog_info (peer->log,
+ "%s [Info] UPDATE for non-enabled AFI/SAFI %u/%u",
+ peer->host, nlris[i].afi, nlris[i].safi);
+ continue;
+ }
+
+ /* EoR handled later */
+ if (nlris[i].length == 0)
+ continue;
+
+ switch (i)
+ {
+ case NLRI_UPDATE:
+ case NLRI_MP_UPDATE:
+ nlri_ret = bgp_nlri_parse (peer, NLRI_ATTR_ARG, &nlris[i]);
+ break;
+ case NLRI_WITHDRAW:
+ case NLRI_MP_WITHDRAW:
+ nlri_ret = bgp_nlri_parse (peer, NULL, &nlris[i]);
+ }
+
+ if (nlri_ret < 0)
+ {
+ plog_err (peer->log,
+ "%s [Error] Error parsing NLRI", peer->host);
+ if (peer->status == Established)
+ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
+ i <= NLRI_WITHDRAW
+ ? BGP_NOTIFY_UPDATE_INVAL_NETWORK
+ : BGP_NOTIFY_UPDATE_OPT_ATTR_ERR);
+ bgp_attr_unintern_sub (&attr);
+ return -1;
+ }
}
- if (peer->afc[AFI_IP][SAFI_MULTICAST])
+
+ /* EoR checks.
+ *
+ * Non-MP IPv4/Unicast EoR is a completely empty UPDATE
+ * and MP EoR should have only an empty MP_UNREACH
+ */
+ if (!update_len && !withdraw_len
+ && nlris[NLRI_MP_UPDATE].length == 0)
{
- if (mp_update.length
- && mp_update.afi == AFI_IP
- && mp_update.safi == SAFI_MULTICAST)
- bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update);
-
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP
- && mp_withdraw.safi == SAFI_MULTICAST)
- bgp_nlri_parse (peer, NULL, &mp_withdraw);
-
- if (! withdraw_len
- && mp_withdraw.afi == AFI_IP
- && mp_withdraw.safi == SAFI_MULTICAST
- && mp_withdraw.length == 0)
- {
+ afi_t afi = 0;
+ safi_t safi;
+
+ /* Non-MP IPv4/Unicast is a completely empty UPDATE - already
+ * checked update and withdraw NLRI lengths are 0.
+ */
+ if (!attribute_len)
+ {
+ afi = AFI_IP;
+ safi = SAFI_UNICAST;
+ }
+ /* otherwise MP AFI/SAFI is an empty update, other than an empty
+ * MP_UNREACH_NLRI attr (with an AFI/SAFI we recognise).
+ */
+ else if (attr.flag == BGP_ATTR_MP_UNREACH_NLRI
+ && nlris[NLRI_MP_WITHDRAW].length == 0
+ && bgp_afi_safi_valid_indices (nlris[NLRI_MP_WITHDRAW].afi,
+ &nlris[NLRI_MP_WITHDRAW].safi))
+ {
+ afi = nlris[NLRI_MP_WITHDRAW].afi;
+ safi = nlris[NLRI_MP_WITHDRAW].safi;
+ }
+
+ if (afi && peer->afc[afi][safi])
+ {
/* End-of-RIB received */
- SET_FLAG (peer->af_sflags[AFI_IP][SAFI_MULTICAST],
+ SET_FLAG (peer->af_sflags[afi][safi],
PEER_STATUS_EOR_RECEIVED);
/* NSF delete stale route */
- if (peer->nsf[AFI_IP][SAFI_MULTICAST])
- bgp_clear_stale_route (peer, AFI_IP, SAFI_MULTICAST);
+ if (peer->nsf[afi][safi])
+ bgp_clear_stale_route (peer, afi, safi);
if (BGP_DEBUG (normal, NORMAL))
- zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv4 Multicast from %s",
- peer->host);
- }
- }
- if (peer->afc[AFI_IP6][SAFI_UNICAST])
- {
- if (mp_update.length
- && mp_update.afi == AFI_IP6
- && mp_update.safi == SAFI_UNICAST)
- bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update);
-
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP6
- && mp_withdraw.safi == SAFI_UNICAST)
- bgp_nlri_parse (peer, NULL, &mp_withdraw);
-
- if (! withdraw_len
- && mp_withdraw.afi == AFI_IP6
- && mp_withdraw.safi == SAFI_UNICAST
- && mp_withdraw.length == 0)
- {
- /* End-of-RIB received */
- SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_UNICAST], PEER_STATUS_EOR_RECEIVED);
-
- /* NSF delete stale route */
- if (peer->nsf[AFI_IP6][SAFI_UNICAST])
- bgp_clear_stale_route (peer, AFI_IP6, SAFI_UNICAST);
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv6 Unicast from %s",
- peer->host);
- }
- }
- if (peer->afc[AFI_IP6][SAFI_MULTICAST])
- {
- if (mp_update.length
- && mp_update.afi == AFI_IP6
- && mp_update.safi == SAFI_MULTICAST)
- bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update);
-
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP6
- && mp_withdraw.safi == SAFI_MULTICAST)
- bgp_nlri_parse (peer, NULL, &mp_withdraw);
-
- if (! withdraw_len
- && mp_withdraw.afi == AFI_IP6
- && mp_withdraw.safi == SAFI_MULTICAST
- && mp_withdraw.length == 0)
- {
- /* End-of-RIB received */
-
- /* NSF delete stale route */
- if (peer->nsf[AFI_IP6][SAFI_MULTICAST])
- bgp_clear_stale_route (peer, AFI_IP6, SAFI_MULTICAST);
-
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv6 Multicast from %s",
- peer->host);
- }
- }
- if (peer->afc[AFI_IP][SAFI_MPLS_VPN])
- {
- if (mp_update.length
- && mp_update.afi == AFI_IP
- && mp_update.safi == SAFI_MPLS_LABELED_VPN)
- bgp_nlri_parse_vpn (peer, NLRI_ATTR_ARG, &mp_update);
-
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP
- && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN)
- bgp_nlri_parse_vpn (peer, NULL, &mp_withdraw);
-
- if (! withdraw_len
- && mp_withdraw.afi == AFI_IP
- && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN
- && mp_withdraw.length == 0)
- {
- /* End-of-RIB received */
-
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for VPNv4 Unicast from %s",
- peer->host);
- }
- }
- if (peer->afc[AFI_IP6][SAFI_MPLS_VPN])
- {
- if (mp_update.length
- && mp_update.afi == AFI_IP6
- && mp_update.safi == SAFI_MPLS_LABELED_VPN)
- bgp_nlri_parse_vpn (peer, NLRI_ATTR_ARG, &mp_update);
-
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP6
- && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN)
- bgp_nlri_parse_vpn (peer, NULL, &mp_withdraw);
-
- if (! withdraw_len
- && mp_withdraw.afi == AFI_IP6
- && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN
- && mp_withdraw.length == 0)
- {
- /* End-of-RIB received */
-
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for VPNv4 Unicast from %s",
- peer->host);
- }
- }
- if (peer->afc[AFI_IP][SAFI_ENCAP])
- {
- if (mp_update.length
- && mp_update.afi == AFI_IP
- && mp_update.safi == SAFI_ENCAP)
- bgp_nlri_parse_encap (peer, NLRI_ATTR_ARG, &mp_update);
-
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP
- && mp_withdraw.safi == SAFI_ENCAP)
- bgp_nlri_parse_encap (peer, NULL, &mp_withdraw);
-
- if (! withdraw_len
- && mp_withdraw.afi == AFI_IP
- && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN
- && mp_withdraw.length == 0)
- {
- /* End-of-RIB received */
-
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for Encap Unicast from %s",
- peer->host);
- }
- }
- if (peer->afc[AFI_IP6][SAFI_ENCAP])
- {
- if (mp_update.length
- && mp_update.afi == AFI_IP6
- && mp_update.safi == SAFI_ENCAP)
- bgp_nlri_parse_encap (peer, NLRI_ATTR_ARG, &mp_update);
-
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP6
- && mp_withdraw.safi == SAFI_ENCAP)
- bgp_nlri_parse_encap (peer, NULL, &mp_withdraw);
-
- if (! withdraw_len
- && mp_withdraw.afi == AFI_IP6
- && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN
- && mp_withdraw.length == 0)
- {
- /* End-of-RIB received */
-
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for Encap Unicast from %s",
- peer->host);
- }
+ zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for %s from %s",
+ peer->host, afi_safi_print (afi, safi));
+ }
}
-
+
/* Everything is done. We unintern temporary structures which
interned in bgp_attr_parse(). */
bgp_attr_unintern_sub (&attr);
diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h
index 8f0ebe31..6b0b7f4d 100644
--- a/bgpd/bgp_packet.h
+++ b/bgpd/bgp_packet.h
@@ -54,4 +54,6 @@ extern void bgp_default_withdraw_send (struct peer *, afi_t, safi_t);
extern int bgp_capability_receive (struct peer *, bgp_size_t);
+extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *);
+
#endif /* _QUAGGA_BGP_PACKET_H */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index c1e5e59b..b581fd99 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -3226,7 +3226,8 @@ bgp_reset (void)
/* Parse NLRI stream. Withdraw NLRI is recognized by NULL attr
value. */
int
-bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
+bgp_nlri_parse_ip (struct peer *peer, struct attr *attr,
+ struct bgp_nlri *packet)
{
u_char *pnt;
u_char *lim;
@@ -3401,6 +3402,7 @@ bgp_nlri_sanity_check (struct peer *peer, struct bgp_nlri *nlri)
switch (nlri->safi)
{
case SAFI_MPLS_LABELED_VPN:
+ case SAFI_MPLS_VPN:
return bgp_nlri_sanity_check_vpn (peer, nlri);
case SAFI_UNICAST:
case SAFI_MULTICAST:
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index c16eca7b..8064598c 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -197,7 +197,7 @@ extern void bgp_info_set_flag (struct bgp_node *, struct bgp_info *, u_int32_t);
extern void bgp_info_unset_flag (struct bgp_node *, struct bgp_info *, u_int32_t);
extern int bgp_nlri_sanity_check (struct peer *, struct bgp_nlri *);
-extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *);
+extern int bgp_nlri_parse_ip (struct peer *, struct attr *, struct bgp_nlri *);
extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int);
diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c
index 39f3b0da..5400dd17 100644
--- a/tests/bgp_mp_attr_test.c
+++ b/tests/bgp_mp_attr_test.c
@@ -32,6 +32,7 @@
#include "bgpd/bgp_open.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_nexthop.h"
@@ -723,16 +724,10 @@ parse_test (struct peer *peer, struct test_segment *t, int type)
if (!parse_ret)
{
- int (*f) (struct peer *, struct attr *, struct bgp_nlri *)
- = bgp_nlri_parse;
-
- if (t->safi == SAFI_MPLS_LABELED_VPN)
- f = bgp_nlri_parse_vpn;
-
if (type == BGP_ATTR_MP_REACH_NLRI)
- nlri_ret = f (peer, &attr, &nlri);
+ nlri_ret = bgp_nlri_parse (peer, &attr, &nlri);
else
- nlri_ret = f (peer, NULL, &nlri);
+ nlri_ret = bgp_nlri_parse (peer, NULL, &nlri);
}
handle_result (peer, t, parse_ret, nlri_ret);