bgpd: Implement BGP confederation error handling (RFC5065, Par. 5)

This patch implements BGP confederation error handling in Quagga as described
in RFC5065, paragraph 5.

* bgp_aspath.c: (aspath_confed_check, aspath_left_confed_check) new functions
* bgp_attr.c: (bgp_attr_aspath_check) apply previous and NOTIFY if there's
  a problem.
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 13f32b8..e65541f 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -1122,6 +1122,42 @@
   return 1;
 }
 
+/* AS path confed check.  If aspath contains confed set or sequence then return 1. */
+int
+aspath_confed_check (struct aspath *aspath)
+{
+  struct assegment *seg;
+
+  if ( !(aspath && aspath->segments) )
+    return 0;
+
+  seg = aspath->segments;
+
+  while (seg)
+    {
+      if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
+	  return 1;
+      seg = seg->next;
+    }
+  return 0;
+}
+
+/* Leftmost AS path segment confed check.  If leftmost AS segment is of type
+  AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1.  */
+int
+aspath_left_confed_check (struct aspath *aspath)
+{
+
+  if ( !(aspath && aspath->segments) )
+    return 0;
+
+  if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
+      || (aspath->segments->type == AS_CONFED_SET) )
+    return 1;
+
+  return 0;
+}
+
 /* Merge as1 to as2.  as2 should be uninterned aspath. */
 static struct aspath *
 aspath_merge (struct aspath *as1, struct aspath *as2)
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index 2b4625c..9854d18 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -88,6 +88,8 @@
 extern int aspath_loop_check (struct aspath *, as_t);
 extern int aspath_private_as_check (struct aspath *);
 extern int aspath_firstas_check (struct aspath *, as_t);
+extern int aspath_confed_check (struct aspath *);
+extern int aspath_left_confed_check (struct aspath *);
 extern unsigned long aspath_count (void);
 extern unsigned int aspath_count_hops (struct aspath *);
 extern unsigned int aspath_count_confeds (struct aspath *);
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 9416837..a664858 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -872,6 +872,17 @@
 
   bgp = peer->bgp;
     
+  /* Confederation sanity check. */
+  if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
+     (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
+    {
+      zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
+      bgp_notify_send (peer, 
+		       BGP_NOTIFY_UPDATE_ERR, 
+		       BGP_NOTIFY_UPDATE_MAL_AS_PATH);
+      return -1;
+    }
+
   /* First AS check for EBGP. */
   if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
     {