]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge branch 'frr/pull/236' ("tools: frr-reload.py needs to treat "mpls" as a single...
authorDavid Lamparter <equinox@opensourcerouting.org>
Tue, 7 Mar 2017 15:02:41 +0000 (16:02 +0100)
committerDavid Lamparter <equinox@opensourcerouting.org>
Tue, 7 Mar 2017 15:02:41 +0000 (16:02 +0100)
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
163 files changed:
bgpd/Makefile.am
bgpd/bgp_attr.c
bgpd/bgp_attr.h
bgpd/bgp_attr_evpn.c [new file with mode: 0644]
bgpd/bgp_attr_evpn.h [new file with mode: 0644]
bgpd/bgp_clist.c
bgpd/bgp_debug.c
bgpd/bgp_debug.h
bgpd/bgp_ecommunity.c
bgpd/bgp_ecommunity.h
bgpd/bgp_encap.c
bgpd/bgp_encap_tlv.c
bgpd/bgp_encap_types.h
bgpd/bgp_evpn.c [new file with mode: 0644]
bgpd/bgp_evpn.h [new file with mode: 0644]
bgpd/bgp_evpn_vty.c [new file with mode: 0644]
bgpd/bgp_evpn_vty.h [new file with mode: 0644]
bgpd/bgp_main.c
bgpd/bgp_mpath.c
bgpd/bgp_mplsvpn.c
bgpd/bgp_mplsvpn.h
bgpd/bgp_open.c
bgpd/bgp_packet.c
bgpd/bgp_packet.h
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_updgrp_adv.c
bgpd/bgp_updgrp_packet.c
bgpd/bgp_vpn.c [new file with mode: 0644]
bgpd/bgp_vpn.h [new file with mode: 0644]
bgpd/bgp_vty.c
bgpd/bgp_vty.h
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/bgpd.h
bgpd/rfapi/bgp_rfapi_cfg.c
bgpd/rfapi/rfapi.c
bgpd/rfapi/rfapi_import.c
bgpd/rfapi/rfapi_monitor.c
bgpd/rfapi/rfapi_private.h
bgpd/rfapi/rfapi_rib.c
bgpd/rfapi/rfapi_vty.c
bgpd/rfapi/vnc_export_bgp.c
bgpd/rfapi/vnc_zebra.c
configure.ac
cumulus/etc/frr/daemons
cumulus/etc/frr/debian.conf
debian/README.Debian
debian/frr.preinst
doc/Building_FRR_on_CentOS6.md [new file with mode: 0644]
doc/Building_FRR_on_CentOS7.md [new file with mode: 0644]
doc/Building_FRR_on_Debian8.md [new file with mode: 0644]
doc/Building_FRR_on_Fedora24.md [new file with mode: 0644]
doc/Building_FRR_on_FreeBSD10.md [new file with mode: 0644]
doc/Building_FRR_on_FreeBSD11.md [new file with mode: 0644]
doc/Building_FRR_on_FreeBSD9.md [new file with mode: 0644]
doc/Building_FRR_on_NetBSD6.md [new file with mode: 0644]
doc/Building_FRR_on_NetBSD7.md [new file with mode: 0644]
doc/Building_FRR_on_OmniOS.md [new file with mode: 0644]
doc/Building_FRR_on_OpenBSD6.md [new file with mode: 0644]
doc/Building_FRR_on_Ubuntu1204.md [new file with mode: 0644]
doc/Building_FRR_on_Ubuntu1404.md [new file with mode: 0644]
doc/Building_FRR_on_Ubuntu1604.md [new file with mode: 0644]
doc/cli.md [new file with mode: 0644]
doc/vtysh.1.in
doc/vtysh.texi
isisd/dict.c
isisd/isis_circuit.c
isisd/isis_lsp.c
isisd/isis_pdu.c
isisd/isis_route.c
isisd/isis_spf.c
isisd/isis_spf.h
isisd/isis_te.c
isisd/isis_vty.c
isisd/isisd.c
isisd/isisd.h
ldpd/address.c
ldpd/control.c
ldpd/init.c
ldpd/l2vpn.c
ldpd/labelmapping.c
ldpd/lde.c
ldpd/lde.h
ldpd/lde_lib.c
ldpd/ldp.h
ldpd/ldp_debug.h
ldpd/ldp_zebra.c
ldpd/ldpd.h
ldpd/ldpe.c
ldpd/ldpe.h
ldpd/log.c
ldpd/neighbor.c
ldpd/notification.c
ldpd/packet.c
ldpd/pfkey.c
lib/Makefile.am
lib/command.c
lib/command.h
lib/linklist.h
lib/log.c
lib/monotime.h
lib/plist.c
lib/prefix.c
lib/prefix.h
lib/spf_backoff.c [new file with mode: 0644]
lib/spf_backoff.h [new file with mode: 0644]
lib/srcdest_table.c
lib/srcdest_table.h
lib/thread.h
lib/vty.c
lib/vty.h
lib/zebra.h
ospf6d/ospf6_zebra.c
ospfd/.gitignore
ospfd/ospf_main.c
pimd/pim_assert.c
pimd/pim_iface.c
pimd/pim_iface.h
pimd/pim_ifchannel.c
pimd/pim_ifchannel.h
pimd/pim_igmp.c
pimd/pim_igmp.h
pimd/pim_igmpv3.c
pimd/pim_join.c
pimd/pim_join.h
pimd/pim_mroute.c
pimd/pim_msg.c
pimd/pim_msg.h
pimd/pim_oil.c
pimd/pim_pim.c
pimd/pim_pim.h
pimd/pim_rpf.c
pimd/pim_rpf.h
pimd/pim_static.c
pimd/pim_upstream.c
pimd/pim_upstream.h
pimd/pim_zebra.c
pimd/pim_zlookup.c
pimd/pimd.h
tests/bgpd/test_ecommunity.c
tests/bgpd/test_mp_attr.c
tools/frr
tools/frr-reload.py
tools/frr.service
vtysh/vtysh.c
vtysh/vtysh.h
vtysh/vtysh_main.c
watchfrr/watchfrr_vty.c
zebra/if_netlink.c
zebra/if_netlink.h
zebra/kernel_netlink.c
zebra/kernel_netlink.h
zebra/main.c
zebra/rib.h
zebra/rt_netlink.c
zebra/rt_netlink.h
zebra/zebra_fpm_netlink.c
zebra/zebra_fpm_protobuf.c
zebra/zebra_mpls_openbsd.c
zebra/zebra_rib.c
zebra/zserv.c
zebra/zserv.h

index 611dbb8558524e58a5fcee9d1c26dbab753bb527..50afc7ed64edd00c1a8108801fbc1b95ce0280cf 100644 (file)
@@ -78,8 +78,9 @@ libbgp_a_SOURCES = \
        bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_lcommunity.c \
        bgp_mplsvpn.c bgp_nexthop.c \
        bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \
-        bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \
-       bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC)
+       bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \
+       bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \
+       bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c
 
 noinst_HEADERS = \
        bgp_memory.h \
@@ -89,8 +90,8 @@ noinst_HEADERS = \
        bgp_ecommunity.h bgp_lcommunity.h \
        bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
        bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h \
-        bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \
-       $(BGP_VNC_RFAPI_HD) 
+       bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \
+       $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h bgp_vpn.h
 
 bgpd_SOURCES = bgp_main.c
 bgpd_LDADD = libbgp.a  $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@
index 7dc42e719f8f42735b92033a329cf14add6aad36..153187fd43603b9d9632e93fe6171de7c81c6e41 100644 (file)
@@ -50,6 +50,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 # include "bgp_encap_types.h"
 # include "bgp_vnc_types.h"
 #endif
+#include "bgp_encap_types.h"
+#include "bgp_evpn.h"
 
 /* Attribute strings for logging. */
 static const struct message attr_str [] = 
@@ -419,6 +421,18 @@ encap_finish (void)
 #endif
 }
 
+static bool
+overlay_index_same(const struct attr_extra *ae1, const struct attr_extra *ae2)
+{
+  if(!ae1 && ae2)
+    return false;
+  if(!ae2 && ae1)
+    return false;
+  if(!ae1 && !ae2)
+    return true;
+  return !memcmp(&(ae1->evpn_overlay), &(ae2->evpn_overlay), sizeof(struct overlay_index));
+}
+
 /* Unknown transit attribute. */
 static struct hash *transit_hash;
 
@@ -730,7 +744,8 @@ attrhash_cmp (const void *p1, const void *p2)
 #if ENABLE_BGP_VNC
          && encap_same(ae1->vnc_subtlvs, ae2->vnc_subtlvs)
 #endif
-          && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id))
+          && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id)
+          && overlay_index_same(ae1, ae2))
         return 1;
       else if (ae1 || ae2)
         return 0;
@@ -2799,6 +2814,39 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
        break;
       }
       break;
+    case AFI_L2VPN:
+      switch (safi)
+      {
+      case SAFI_EVPN:
+          if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV4)
+            {
+              stream_putc (s, 12);
+              stream_putl (s, 0);   /* RD = 0, per RFC */
+              stream_putl (s, 0);
+              stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
+            }
+          else if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL)
+            {
+              stream_putc (s, 24);
+              stream_putl (s, 0);   /* RD = 0, per RFC */
+              stream_putl (s, 0);
+              stream_put (s, &attr->extra->mp_nexthop_global, IPV6_MAX_BYTELEN);
+            }
+          else if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
+            {
+              stream_putc (s, 48);
+              stream_putl (s, 0);   /* RD = 0, per RFC */
+              stream_putl (s, 0);
+              stream_put (s, &attr->extra->mp_nexthop_global, IPV6_MAX_BYTELEN);
+              stream_putl (s, 0);   /* RD = 0, per RFC */
+              stream_putl (s, 0);
+              stream_put (s, &attr->extra->mp_nexthop_local, IPV6_MAX_BYTELEN);
+            }
+         break;
+        break;
+      default:
+        break;
+      }
     default:
       break;
     }
@@ -2812,7 +2860,7 @@ void
 bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi,
                          struct prefix *p, struct prefix_rd *prd,
                           u_char *tag, int addpath_encode,
-                          u_int32_t addpath_tx_id)
+                          u_int32_t addpath_tx_id, struct attr *attr)
 {
   if (safi == SAFI_MPLS_VPN)
     {
@@ -2824,6 +2872,10 @@ bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi,
       stream_put (s, prd->val, 8);
       stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
     }
+  else if (safi == SAFI_EVPN)
+    {
+      bgp_packet_mpattr_route_type_5(s, p, prd, tag, attr);
+    }
   else
     stream_put_prefix_addpath (s, p, addpath_encode, addpath_tx_id);
 }
@@ -2977,7 +3029,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
                                      AFI_MAX), /* get from NH */
                                     vecarr, attr);
       bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag,
-                               addpath_encode, addpath_tx_id);
+                               addpath_encode, addpath_tx_id, attr);
       bgp_packet_mpattr_end(s, mpattrlen_pos);
     }
 
@@ -3338,8 +3390,9 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
       stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
     }
 
-  if ((afi == AFI_IP || afi == AFI_IP6) &&
-      (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN))
+  if (((afi == AFI_IP || afi == AFI_IP6) &&
+       (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN)) ||
+      (afi == AFI_L2VPN && safi == SAFI_EVPN))
     {
        /* Tunnel Encap attribute */
        bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP);
@@ -3385,21 +3438,10 @@ void
 bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
                             afi_t afi, safi_t safi, struct prefix_rd *prd,
                             u_char *tag, int addpath_encode,
-                             u_int32_t addpath_tx_id)
+                             u_int32_t addpath_tx_id, struct attr *attr)
 {
-  if (safi == SAFI_MPLS_VPN)
-    {
-      /* addpath TX ID */
-      if (addpath_encode)
-        stream_putl(s, addpath_tx_id);
-
-      stream_putc (s, p->prefixlen + 88);
-      stream_put (s, tag, 3);
-      stream_put (s, prd->val, 8);
-      stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
-    }
-  else
-    stream_put_prefix_addpath (s, p, addpath_encode, addpath_tx_id);
+  return bgp_packet_mpattr_prefix (s, afi, safi, p, prd,
+                                   tag, addpath_encode, addpath_tx_id, attr);
 }
 
 void
index c5799ccd0dd54a19a1b84587a7caf4b466af0aef..015039c6cd671e4ce8ef0a345d36f7dbbaa88f58 100644 (file)
@@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #ifndef _QUAGGA_BGP_ATTR_H
 #define _QUAGGA_BGP_ATTR_H
 
+#include "bgp_attr_evpn.h"
+
 /* Simple bit mapping. */
 #define BITMAP_NBBY 8
 
@@ -80,6 +82,13 @@ struct bgp_tea_options {
 
 #endif
 
+/* Overlay Index Info */
+struct overlay_index
+{
+  struct eth_segment_id eth_s_id;
+  union gw_addr gw_ip;
+};
+
 /* Additional/uncommon BGP attributes.
  * lazily allocated as and when a struct attr
  * requires it.
@@ -131,6 +140,8 @@ struct attr_extra
 #if ENABLE_BGP_VNC
   struct bgp_attr_encap_subtlv *vnc_subtlvs;           /* VNC-specific */
 #endif
+  /* EVPN */
+  struct overlay_index evpn_overlay;
 };
 
 /* BGP core attribute structure. */
@@ -283,7 +294,8 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, afi_t afi, safi_t safi,
 extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
                                     struct prefix *p, struct prefix_rd *prd,
                                     u_char *tag, int addpath_encode,
-                                     u_int32_t addpath_tx_id);
+                                     u_int32_t addpath_tx_id,
+                                     struct attr *);
 extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi,
                                             struct prefix *p);
 extern void bgp_packet_mpattr_end(struct stream *s, size_t sizep);
@@ -292,7 +304,7 @@ extern size_t bgp_packet_mpunreach_start (struct stream *s, afi_t afi,
                                          safi_t safi);
 extern void bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
                             afi_t afi, safi_t safi, struct prefix_rd *prd,
-                            u_char *tag, int, u_int32_t);
+                            u_char *tag, int, u_int32_t, struct attr *);
 extern void bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt);
 
 static inline int
diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c
new file mode 100644 (file)
index 0000000..be97ffd
--- /dev/null
@@ -0,0 +1,141 @@
+/* Ethernet-VPN Attribute handling file
+   Copyright (C) 2016 6WIND
+
+This file is part of Free Range Routing.
+
+Free Range Routing is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Free Range Routing is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Free Range Routing; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "filter.h"
+#include "prefix.h"
+#include "log.h"
+#include "memory.h"
+#include "stream.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr_evpn.h"
+#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_evpn.h"
+
+void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac)
+{
+       struct ecommunity_val routermac_ecom;
+
+       if (attr->extra) {
+               memset(&routermac_ecom, 0, sizeof(struct ecommunity_val));
+               routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN;
+               routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC;
+               memcpy(&routermac_ecom.val[2], routermac->octet, ETHER_ADDR_LEN);
+               if (!attr->extra->ecommunity)
+                       attr->extra->ecommunity = ecommunity_new();
+               ecommunity_add_val(attr->extra->ecommunity, &routermac_ecom);
+               ecommunity_str (attr->extra->ecommunity);
+       }
+}
+
+/* converts to an esi
+ * returns 1 on success, 0 otherwise
+ * format accepted: AA:BB:CC:DD:EE:FF:GG:HH:II:JJ
+ * if id is null, check only is done
+ */
+int str2esi(const char *str, struct eth_segment_id *id)
+{
+       unsigned int a[ESI_LEN];
+       int i;
+
+       if (!str)
+               return 0;
+       if (sscanf (str, "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x",
+                    a + 0, a + 1, a + 2, a + 3, a + 4, a + 5,
+                    a + 6, a + 7, a + 8, a + 9) != ESI_LEN)
+       {
+               /* error in incoming str length */
+               return 0;
+       }
+       /* valid mac address */
+       if (!id)
+               return 1;
+       for (i = 0; i < ESI_LEN; ++i)
+               id->val[i] = a[i] & 0xff;
+       return 1;
+}
+
+char *esi2str(struct eth_segment_id *id)
+{
+       char *ptr;
+       u_char *val;
+
+       if (!id)
+               return NULL;
+
+       val = id->val;
+       ptr = (char *)XMALLOC(MTYPE_TMP, (ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char));
+
+       snprintf(ptr, (ESI_LEN * 2 + ESI_LEN - 1 + 1),
+                "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+                val[0], val[1], val[2], val[3], val[4],
+                val[5], val[6], val[7], val[8], val[9]);
+
+       return ptr;
+}
+
+char *ecom_mac2str(char *ecom_mac)
+{
+       char *en;
+
+       en = ecom_mac;
+       en += 2;
+        return prefix_mac2str((struct ethaddr *)en, NULL, 0);
+}
+
+/* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */
+extern int
+bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag, struct prefix *dst)
+{
+       struct evpn_addr *p_evpn_p;
+       struct prefix p2;
+       struct prefix *src = &p2;
+
+       if (!dst || dst->family == 0)
+               return -1;
+       /* store initial prefix in src */
+       prefix_copy(src, dst);
+       memset(dst, 0, sizeof(struct prefix));
+       p_evpn_p = &(dst->u.prefix_evpn);
+       dst->family = AF_ETHERNET;
+       p_evpn_p->route_type = evpn_type;
+       if (evpn_type == EVPN_IP_PREFIX) {
+               p_evpn_p->eth_tag = eth_tag;
+               p_evpn_p->ip_prefix_length = p2.prefixlen;
+               if (src->family == AF_INET) {
+                       p_evpn_p->flags = IP_PREFIX_V4;
+                       memcpy(&p_evpn_p->ip.v4_addr, &src->u.prefix4,
+                              sizeof(struct in_addr));
+                       dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4;
+               } else {
+                       p_evpn_p->flags = IP_PREFIX_V6;
+                       memcpy(&p_evpn_p->ip.v6_addr, &src->u.prefix6,
+                              sizeof(struct in6_addr));
+                       dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV6;
+               }
+       } else
+               return -1;
+       return 0;
+}
diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h
new file mode 100644 (file)
index 0000000..e6da7e7
--- /dev/null
@@ -0,0 +1,59 @@
+/* E-VPN attribute handling structure file
+   Copyright (C) 2016 6WIND
+
+This file is part of Free Range Routing.
+
+Free Range Routing is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Free Range Routing is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Free Range Routing; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#ifndef _QUAGGA_BGP_ATTR_EVPN_H
+#define _QUAGGA_BGP_ATTR_EVPN_H
+
+/* value of first byte of ESI */
+#define ESI_TYPE_ARBITRARY 0   /* */
+#define ESI_TYPE_LACP      1   /* <> */
+#define ESI_TYPE_BRIDGE    2   /* <Root bridge Mac-6B>:<Root Br Priority-2B>:00 */
+#define ESI_TYPE_MAC       3   /* <Syst Mac Add-6B>:<Local Discriminator Value-3B> */
+#define ESI_TYPE_ROUTER    4   /* <RouterId-4B>:<Local Discriminator Value-4B> */
+#define ESI_TYPE_AS        5   /* <AS-4B>:<Local Discriminator Value-4B> */
+#define MAX_ESI {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}
+#define ESI_LEN 10
+
+#define MAX_ET 0xffffffff
+u_long eth_tag_id;
+struct attr;
+
+struct eth_segment_id {
+       u_char val[ESI_LEN];
+};
+
+union gw_addr {
+       struct in_addr ipv4;
+       struct in6_addr ipv6;
+};
+
+struct bgp_route_evpn {
+       struct eth_segment_id eth_s_id;
+       union gw_addr gw_ip;
+};
+
+extern int str2esi(const char *str, struct eth_segment_id *id);
+extern char *esi2str(struct eth_segment_id *id);
+extern char *ecom_mac2str(char *ecom_mac);
+
+extern void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac);
+extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag,
+                                struct prefix *dst);
+#endif                         /* _QUAGGA_BGP_ATTR_EVPN_H */
index b37034bf295b44c214a9025304cdc9625b6d0ef3..3def97c73d132eac0cdfb99cc0710f590689a8cc 100644 (file)
@@ -506,18 +506,22 @@ lcommunity_str_get (struct lcommunity *lcom, int i)
 static int
 lcommunity_regexp_include (regex_t * reg, struct lcommunity *lcom, int i)
 {
-  const char *str;
+  char *str;
 
   /* When there is no communities attribute it is treated as empty string. */
   if (lcom == NULL || lcom->size == 0)
-    str = "";
+    str = XSTRDUP (MTYPE_LCOMMUNITY_STR, "");
   else
     str = lcommunity_str_get (lcom, i);
 
   /* Regular expression match.  */
   if (regexec (reg, str, 0, NULL, 0) == 0)
-    return 1;
+    {
+      XFREE (MTYPE_LCOMMUNITY_STR, str);
+      return 1;
+    }
 
+  XFREE (MTYPE_LCOMMUNITY_STR, str);
   /* No match.  */
   return 0;
 }
@@ -1166,14 +1170,14 @@ extcommunity_list_set (struct community_list_handler *ch,
     }
 
   if (ecom)
-    ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
+    ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY, 0);
 
   entry = community_entry_new ();
   entry->direct = direct;
   entry->style = style;
   entry->any = (str ? 0 : 1);
   if (ecom)
-    entry->config = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
+    entry->config = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0);
   else if (regex)
     entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
   else
index ab05878210696c4bc0e9396e9b242e8265623975..e1e7cb1d5b677aa659696d3a54dc320d357bba7e 100644 (file)
@@ -38,6 +38,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_debug.h"
 #include "bgpd/bgp_community.h"
 #include "bgpd/bgp_updgrp.h"
+#include "bgpd/bgp_mplsvpn.h"
+
+#define BGP_ADDPATH_STR 20
 
 unsigned long conf_bgp_debug_as4;
 unsigned long conf_bgp_debug_neighbor_events;
@@ -2086,3 +2089,31 @@ bgp_debug_zebra (struct prefix *p)
 
   return 0;
 }
+
+const char *
+bgp_debug_rdpfxpath2str (struct prefix_rd *prd, union prefixconstptr pu,
+                         int addpath_valid, u_int32_t addpath_id,
+                         char *str, int size)
+{
+  char rd_buf[RD_ADDRSTRLEN];
+  char pfx_buf[PREFIX_STRLEN];
+  char pathid_buf[BGP_ADDPATH_STR];
+
+  if (size < BGP_PRD_PATH_STRLEN)
+    return NULL;
+
+  /* Note: Path-id is created by default, but only included in update sometimes. */
+  pathid_buf[0] = '\0';
+  if (addpath_valid)
+    sprintf(pathid_buf, " with addpath ID %d", addpath_id);
+
+  if (prd)
+    snprintf (str, size, "RD %s %s%s",
+              prefix_rd2str(prd, rd_buf, sizeof (rd_buf)),
+              prefix2str (pu, pfx_buf, sizeof (pfx_buf)), pathid_buf);
+  else
+    snprintf (str, size, "%s%s",
+              prefix2str (pu, pfx_buf, sizeof (pfx_buf)), pathid_buf);
+
+  return str;
+}
index 00fb670a47314cb0f0d0458865e2e63d36cab36f..23ea7b0e52d9bf8cfdbd509c656dd6bb7a3620cd 100644 (file)
@@ -36,6 +36,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 /* dump detail */
 #define DUMP_DETAIL   32
 
+/* RD + Prefix + Path-Id */
+#define BGP_PRD_PATH_STRLEN (PREFIX_STRLEN + RD_ADDRSTRLEN + 20)
+
 extern int dump_open;
 extern int dump_update;
 extern int dump_keepalive;
@@ -151,4 +154,6 @@ extern int bgp_debug_bestpath(struct prefix *p);
 extern int bgp_debug_zebra(struct prefix *p);
 
 extern int bgp_debug_count(void);
+extern const char *bgp_debug_rdpfxpath2str (struct prefix_rd *, union prefixconstptr,
+                                            int, u_int32_t, char *, int);
 #endif /* _QUAGGA_BGP_DEBUG_H */
index 6689883d94efa53e4a0d60ce98ba3a3c67b4358b..c80966ec6da05fb9705c2846944b30051153eada 100644 (file)
@@ -175,7 +175,7 @@ char *
 ecommunity_str (struct ecommunity *ecom)
 {
   if (! ecom->str)
-    ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
+    ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY, 0);
   return ecom->str;
 }
 
@@ -213,7 +213,7 @@ ecommunity_intern (struct ecommunity *ecom)
   find->refcnt++;
 
   if (! find->str)
-    find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY);
+    find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY, 0);
 
   return find;
 }
@@ -601,9 +601,12 @@ ecommunity_str2com (const char *str, int type, int keyword_included)
    ECOMMUNITY_FORMAT_ROUTE_MAP
    ECOMMUNITY_FORMAT_COMMUNITY_LIST
    ECOMMUNITY_FORMAT_DISPLAY
+
+   Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases. 
+   0 value displays all
 */
 char *
-ecommunity_ecom2str (struct ecommunity *ecom, int format)
+ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter)
 {
   int i;
   u_int8_t *pnt;
@@ -640,6 +643,7 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
   /* Prepare buffer.  */
   str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1);
   str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1;
+  str_buf[0] = '\0';
   str_pnt = 0;
 
   for (i = 0; i < ecom->size; i++)
@@ -668,6 +672,10 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
           break;
 
         case ECOMMUNITY_ENCODE_OPAQUE:
+          if(filter == ECOMMUNITY_ROUTE_TARGET)
+            {
+              continue;
+            }
           if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP)
             {
               uint16_t tunneltype;
@@ -678,8 +686,31 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
               first = 0;
               continue;
             }
-            /* fall through */
-
+          len = sprintf (str_buf + str_pnt, "?");
+          str_pnt += len;
+          first = 0;
+          continue;
+        case ECOMMUNITY_ENCODE_EVPN:
+          if(filter == ECOMMUNITY_ROUTE_TARGET)
+            {
+              continue;
+            }
+          if (*pnt == ECOMMUNITY_SITE_ORIGIN)
+            {
+              char macaddr[6];
+              pnt++;
+              memcpy(&macaddr, pnt, 6);
+              len = sprintf(str_buf + str_pnt, "EVPN:%02x:%02x:%02x:%02x:%02x:%02x",
+                            macaddr[0], macaddr[1], macaddr[2],
+                            macaddr[3], macaddr[4], macaddr[5]);
+              str_pnt += len;
+              first = 0;
+              continue;
+            }
+          len = sprintf (str_buf + str_pnt, "?");
+          str_pnt += len;
+          first = 0;
+          continue;
         default:
           len = sprintf (str_buf + str_pnt, "?");
           str_pnt += len;
@@ -791,3 +822,64 @@ ecommunity_match (const struct ecommunity *ecom1,
   else
     return 0;
 }
+
+/* return first occurence of type */
+extern struct ecommunity_val *ecommunity_lookup (const struct ecommunity *ecom, uint8_t type, uint8_t subtype)
+{
+  u_int8_t *p;
+  int c;
+
+  /* If the value already exists in the structure return 0.  */
+  c = 0;
+  for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
+    {
+      if(p == NULL)
+        {
+          continue;
+        }
+      if(p[0] == type && p[1] == subtype)
+        return (struct ecommunity_val *)p;
+    }
+  return NULL;
+}
+
+/* remove ext. community matching type and subtype
+ * return 1 on success ( removed ), 0 otherwise (not present)
+ */
+extern int ecommunity_strip (struct ecommunity *ecom, uint8_t type, uint8_t subtype)
+{
+  u_int8_t *p;
+  int c, found = 0;
+  /* When this is fist value, just add it.  */
+  if (ecom == NULL || ecom->val == NULL)
+    {
+      return 0;
+    }
+
+  /* If the value already exists in the structure return 0.  */
+  c = 0;
+  for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
+    {
+      if (p[0] == type && p[1] == subtype)
+        {
+          found = 1;
+          break;
+        }
+    }
+  if (found == 0)
+    return 0;
+  /* Strip The selected value */
+  ecom->size--;
+  /* size is reduced. no memmove to do */
+  p = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
+  if (c != 0)
+    memcpy(p, ecom->val, c * ECOMMUNITY_SIZE);
+  if( (ecom->size - c) != 0)
+    memcpy(p + (c) * ECOMMUNITY_SIZE,
+           ecom->val + (c +1)* ECOMMUNITY_SIZE,
+           (ecom->size - c) * ECOMMUNITY_SIZE);
+  /* shift last ecommunities */
+  XFREE (MTYPE_ECOMMUNITY, ecom->val);
+  ecom->val = p;
+  return 1;
+}
index c5c58e42609ef1b64042af7e4380f3b6ab175fc9..356598f6b180f3cb0d66a532b0d42683117b7e13 100644 (file)
@@ -26,11 +26,18 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #define ECOMMUNITY_ENCODE_IP                0x01
 #define ECOMMUNITY_ENCODE_AS4               0x02
 #define ECOMMUNITY_ENCODE_OPAQUE            0x03
+#define ECOMMUNITY_ENCODE_EVPN              0x06
 
 /* Low-order octet of the Extended Communities type field.  */
 #define ECOMMUNITY_ROUTE_TARGET             0x02
 #define ECOMMUNITY_SITE_ORIGIN              0x03
 
+#define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY  0x00
+#define ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL    0x01
+#define ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT 0x02
+#define ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC    0x03
+#define ECOMMUNITY_EVPN_SUBTYPE_DEF_GW       0x0d
+
 /* Low-order octet of the Extended Communities type field for OPAQUE types */
 #define ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP     0x0c
 
@@ -81,11 +88,15 @@ extern int ecommunity_cmp (const void *, const void *);
 extern void ecommunity_unintern (struct ecommunity **);
 extern unsigned int ecommunity_hash_make (void *);
 extern struct ecommunity *ecommunity_str2com (const char *, int, int);
-extern char *ecommunity_ecom2str (struct ecommunity *, int);
+extern char *ecommunity_ecom2str (struct ecommunity *, int, int);
 extern int ecommunity_match (const struct ecommunity *, const struct ecommunity *);
 extern char *ecommunity_str (struct ecommunity *);
+extern struct ecommunity_val *ecommunity_lookup (const struct ecommunity *, uint8_t, uint8_t );
+extern int ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval);
 
 /* for vpn */
 extern struct ecommunity *ecommunity_new (void);
 extern int ecommunity_add_val (struct ecommunity *, struct ecommunity_val *);
+extern int ecommunity_strip (struct ecommunity *ecom, uint8_t type, uint8_t subtype);
+extern struct ecommunity *ecommunity_new (void);
 #endif /* _QUAGGA_BGP_ECOMMUNITY_H */
index 4ec45108b4e4a85be0c102ce97f106a7e92320dd..603979942d6bcdfd33f6263b67a60c816e18c3c9 100644 (file)
@@ -188,10 +188,10 @@ bgp_nlri_parse_encap(
 
       if (attr) {
        bgp_update (peer, &p, 0, attr, afi, SAFI_ENCAP,
-                   ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0);
+                   ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0, NULL);
       } else {
        bgp_withdraw (peer, &p, 0, attr, afi, SAFI_ENCAP,
-                     ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL);
+                     ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, NULL);
       }
     }
 
@@ -219,7 +219,8 @@ DEFUN (encap_network,
   int idx_ipv4 = 1;
   int idx_rd = 3;
   int idx_word = 5;
-  return bgp_static_set_safi (SAFI_ENCAP, vty, argv[idx_ipv4]->arg, argv[idx_rd]->arg, argv[idx_word]->arg, NULL);
+  return bgp_static_set_safi (SAFI_ENCAP, vty, argv[idx_ipv4]->arg, argv[idx_rd]->arg, argv[idx_word]->arg,
+                              NULL, 0, NULL, NULL, NULL, NULL);
 }
 
 /* For testing purpose, static route of ENCAP. */
@@ -237,7 +238,8 @@ DEFUN (no_encap_network,
   int idx_ipv4 = 2;
   int idx_rd = 4;
   int idx_word = 6;
-  return bgp_static_unset_safi (SAFI_ENCAP, vty, argv[idx_ipv4]->arg, argv[idx_rd]->arg, argv[idx_word]->arg);
+  return bgp_static_unset_safi (SAFI_ENCAP, vty, argv[idx_ipv4]->arg, argv[idx_rd]->arg, argv[idx_word]->arg,
+                                0, NULL, NULL, NULL);
 }
 
 static int
@@ -587,24 +589,27 @@ DEFUN (show_bgp_ipv4_encap_neighbor_routes,
        "Neighbor to display information about\n"
        "Display routes learned from neighbor\n")
 {
-  int idx_peer = 5;
-  union sockunion su;
+  int idx_peer = 0;
+  union sockunion *su;
   struct peer *peer;
 
-  if (sockunion_str2su (argv[idx_peer]->arg))
+  argv_find(argv, argc, "A.B.C.D", &idx_peer);
+  su = sockunion_str2su (argv[idx_peer]->arg);
+
+  if (!su)
     {
       vty_out (vty, "Malformed address: %s%s", argv[idx_peer]->arg, VTY_NEWLINE);
                return CMD_WARNING;
     }
 
-  peer = peer_lookup (NULL, &su);
+  peer = peer_lookup (NULL, su);
   if (! peer || ! peer->afc[AFI_IP][SAFI_ENCAP])
     {
       vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
       return CMD_WARNING;
     }
 
-  return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_neighbor, &su, 0);
+  return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_neighbor, su, 0);
 }
 
 DEFUN (show_bgp_ipv6_encap_neighbor_routes,
index 5c18629aa6bb4f43e3c495b3a8a049e84d68be69..8c5ab8d6f6b51c5e59969f576f92aa49dc1d0ff3 100644 (file)
@@ -391,8 +391,30 @@ bgp_encap_type_vxlan_to_tlv(
     struct attr                                *attr)
 {
     struct attr_extra                  *extra = bgp_attr_extra_get(attr);
+    struct bgp_attr_encap_subtlv       *tlv;
+    uint32_t vnid;
 
     extra->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN;
+
+    if(bet == NULL ||!bet->vnid)
+      return;
+    if(extra->encap_subtlvs)
+      XFREE(MTYPE_ENCAP_TLV, extra->encap_subtlvs);
+    tlv = XCALLOC (MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv)-1+12);
+    tlv->type = 1; /* encapsulation type */
+    tlv->length = 12;
+    if(bet->vnid)
+      {
+        vnid = htonl(bet->vnid | VXLAN_ENCAP_MASK_VNID_VALID);
+        memcpy(&tlv->value, &vnid, 4);
+      }
+    if(bet->mac_address)
+      {
+        char *ptr = (char *)&tlv->value + 4;
+        memcpy( ptr, bet->mac_address, 6);
+      }
+    extra->encap_subtlvs = tlv;
+    return;
 }
 
 void
index 0985446ff2a00e303a6fea5043ca7a40084deb11..04c0d2f235a8f7999d5972e44e6b16c8f02c1f01 100644 (file)
@@ -167,10 +167,15 @@ struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode {
     struct bgp_tea_subtlv_remote_endpoint       st_endpoint;    /* optional */
 };
 
+#define VXLAN_ENCAP_MASK_VNID_VALID 0x80000000
+#define VXLAN_ENCAP_MASK_MAC_VALID  0x40000000
+
 struct bgp_encap_type_vxlan {
     uint32_t                                   valid_subtlvs;
     struct bgp_tea_subtlv_remote_endpoint       st_endpoint;    /* optional */
-    /* No subtlvs defined in spec? */
+    /* draft-ietf-idr-tunnel-encaps-02 */
+    uint32_t                                    vnid; /* does not include V and M bit */
+    uint8_t                                     *mac_address;   /* optional */
 };
 
 struct bgp_encap_type_nvgre {
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
new file mode 100644 (file)
index 0000000..1ab8e23
--- /dev/null
@@ -0,0 +1,225 @@
+/* Ethernet-VPN Packet and vty Processing File
+   Copyright (C) 2016 6WIND
+
+This file is part of Free Range Routing.
+
+Free Range Routing is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Free Range Routing is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Free Range Routing; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "filter.h"
+#include "prefix.h"
+#include "log.h"
+#include "memory.h"
+#include "stream.h"
+
+#include "bgpd/bgp_attr_evpn.h"
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_evpn.h"
+
+int
+bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
+                   struct bgp_nlri *packet, int withdraw)
+{
+       u_char *pnt;
+       u_char *lim;
+       struct prefix p;
+       struct prefix_rd prd;
+       struct evpn_addr *p_evpn_p;
+       struct bgp_route_evpn evpn;
+       uint8_t route_type, route_length;
+       u_char *pnt_label;
+       u_int32_t addpath_id = 0;
+
+       /* Check peer status. */
+       if (peer->status != Established)
+               return 0;
+
+       /* Make prefix_rd */
+       prd.family = AF_UNSPEC;
+       prd.prefixlen = 64;
+
+       p_evpn_p = &p.u.prefix_evpn;
+       pnt = packet->nlri;
+       lim = pnt + packet->length;
+       while (pnt < lim) {
+               /* clear evpn structure */
+               memset(&evpn, 0, sizeof(evpn));
+
+               /* Clear prefix structure. */
+               memset(&p, 0, sizeof(struct prefix));
+               memset(&evpn.gw_ip, 0, sizeof(union gw_addr));
+               memset(&evpn.eth_s_id, 0, sizeof(struct eth_segment_id));
+
+               /* Fetch Route Type */
+               route_type = *pnt++;
+               route_length = *pnt++;
+               /* simply ignore. goto next route type if any */
+               if (route_type != EVPN_IP_PREFIX) {
+                       if (pnt + route_length > lim) {
+                               zlog_err
+                                   ("not enough bytes for New Route Type left in NLRI?");
+                               return -1;
+                       }
+                       pnt += route_length;
+                       continue;
+               }
+
+               /* Fetch RD */
+               if (pnt + 8 > lim) {
+                       zlog_err("not enough bytes for RD left in NLRI?");
+                       return -1;
+               }
+
+               /* Copy routing distinguisher to rd. */
+               memcpy(&prd.val, pnt, 8);
+               pnt += 8;
+
+               /* Fetch ESI */
+               if (pnt + 10 > lim) {
+                       zlog_err("not enough bytes for ESI left in NLRI?");
+                       return -1;
+               }
+               memcpy(&evpn.eth_s_id.val, pnt, 10);
+               pnt += 10;
+
+               /* Fetch Ethernet Tag */
+               if (pnt + 4 > lim) {
+                       zlog_err("not enough bytes for Eth Tag left in NLRI?");
+                       return -1;
+               }
+
+               if (route_type == EVPN_IP_PREFIX) {
+                       p_evpn_p->route_type = route_type;
+                       memcpy(&(p_evpn_p->eth_tag), pnt, 4);
+                       p_evpn_p->eth_tag = ntohl(p_evpn_p->eth_tag);
+                       pnt += 4;
+
+                       /* Fetch IP prefix length. */
+                       p_evpn_p->ip_prefix_length = *pnt++;
+
+                       if (p_evpn_p->ip_prefix_length > 128) {
+                               zlog_err("invalid prefixlen %d in EVPN NLRI?",
+                                        p.prefixlen);
+                               return -1;
+                       }
+                       /* determine IPv4 or IPv6 prefix */
+                       if (route_length - 4 - 10 - 8 -
+                           3 /* label to be read */  >= 32) {
+                               p_evpn_p->flags = IP_PREFIX_V6;
+                               memcpy(&(p_evpn_p->ip.v6_addr), pnt, 16);
+                               pnt += 16;
+                               memcpy(&evpn.gw_ip.ipv6, pnt, 16);
+                               pnt += 16;
+                       } else {
+                               p_evpn_p->flags = IP_PREFIX_V4;
+                               memcpy(&(p_evpn_p->ip.v4_addr), pnt, 4);
+                               pnt += 4;
+                               memcpy(&evpn.gw_ip.ipv4, pnt, 4);
+                               pnt += 4;
+                       }
+                       p.family = AFI_L2VPN;
+                       if (p_evpn_p->flags == IP_PREFIX_V4)
+                               p.prefixlen =
+                                   (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4;
+                       else
+                               p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6;
+                       p.family = AF_ETHERNET;
+               }
+
+               /* Fetch Label */
+               if (pnt + 3 > lim) {
+                       zlog_err("not enough bytes for Label left in NLRI?");
+                       return -1;
+               }
+               pnt_label = pnt;
+
+               pnt += 3;
+
+               if (!withdraw) {
+                       bgp_update(peer, &p, addpath_id, attr, AFI_L2VPN,
+                                  SAFI_EVPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
+                                  &prd, pnt_label, 0, &evpn);
+               } else {
+                       bgp_withdraw(peer, &p, addpath_id, attr, AFI_L2VPN,
+                                    SAFI_EVPN, ZEBRA_ROUTE_BGP,
+                                    BGP_ROUTE_NORMAL, &prd, pnt_label, &evpn);
+               }
+       }
+
+       /* Packet length consistency check. */
+       if (pnt != lim)
+               return -1;
+       return 0;
+}
+
+void
+bgp_packet_mpattr_route_type_5(struct stream *s,
+                              struct prefix *p, struct prefix_rd *prd,
+                              u_char * label, struct attr *attr)
+{
+       int len;
+       char temp[16];
+       struct evpn_addr *p_evpn_p;
+
+       memset(&temp, 0, 16);
+       if (p->family != AF_ETHERNET)
+               return;
+       p_evpn_p = &(p->u.prefix_evpn);
+       if (p_evpn_p->flags & IP_PREFIX_V4)
+               len = 8;        /* ipv4 */
+       else
+               len = 32;       /* ipv6 */
+       stream_putc(s, EVPN_IP_PREFIX);
+       stream_putc(s,
+                   8 /* RD */  + 10 /* ESI */  + 4 /* EthTag */  + 1 + len +
+                   3 /* label */ );
+       stream_put(s, prd->val, 8);
+       if (attr && attr->extra)
+               stream_put(s, &(attr->extra->evpn_overlay.eth_s_id), 10);
+       else
+               stream_put(s, &temp, 10);
+       stream_putl(s, p_evpn_p->eth_tag);
+       stream_putc(s, p_evpn_p->ip_prefix_length);
+       if (p_evpn_p->flags & IP_PREFIX_V4)
+               stream_put_ipv4(s, p_evpn_p->ip.v4_addr.s_addr);
+       else
+               stream_put(s, &p_evpn_p->ip.v6_addr, 16);
+       if (attr && attr->extra) {
+               if (p_evpn_p->flags & IP_PREFIX_V4)
+                       stream_put_ipv4(s,
+                                       attr->extra->evpn_overlay.gw_ip.ipv4.
+                                       s_addr);
+               else
+                       stream_put(s, &(attr->extra->evpn_overlay.gw_ip.ipv6),
+                                  16);
+       } else {
+               if (p_evpn_p->flags & IP_PREFIX_V4)
+                       stream_put_ipv4(s, 0);
+               else
+                       stream_put(s, &temp, 16);
+       }
+       if (label)
+               stream_put(s, label, 3);
+       else
+               stream_put3(s, 0);
+       return;
+}
diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h
new file mode 100644 (file)
index 0000000..63c1a76
--- /dev/null
@@ -0,0 +1,40 @@
+/* E-VPN header for packet handling
+   Copyright (C) 2016 6WIND
+
+This file is part of Free Range Routing.
+
+Free Range Routing is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Free Range Routing is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Free Range Routing; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#ifndef _QUAGGA_BGP_EVPN_H
+#define _QUAGGA_BGP_EVPN_H
+
+extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
+                              struct bgp_nlri *packet, int withdraw);
+
+extern void
+bgp_packet_mpattr_route_type_5(struct stream *s,
+                              struct prefix *p, struct prefix_rd *prd,
+                              u_char * label, struct attr *attr);
+/* EVPN route types as per RFC7432 and
+ * as per draft-ietf-bess-evpn-prefix-advertisement-02
+ */
+#define EVPN_ETHERNET_AUTO_DISCOVERY 1
+#define EVPN_MACIP_ADVERTISEMENT 2
+#define EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG 3
+#define EVPN_ETHERNET_SEGMENT 4
+#define EVPN_IP_PREFIX 5
+
+#endif                         /* _QUAGGA_BGP_EVPN_H */
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
new file mode 100644 (file)
index 0000000..1654265
--- /dev/null
@@ -0,0 +1,752 @@
+/* Ethernet-VPN Packet and vty Processing File
+   Copyright (C) 2017 6WIND
+
+This file is part of Free Range Routing
+
+Free Range Routing is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Free Range Routing is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Free Range Routing; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+#include "command.h"
+#include "prefix.h"
+#include "lib/json.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_vpn.h"
+#include "bgpd/bgp_evpn_vty.h"
+#include "bgpd/bgp_evpn.h"
+
+#define SHOW_DISPLAY_STANDARD 0
+#define SHOW_DISPLAY_TAGS 1
+#define SHOW_DISPLAY_OVERLAY 2
+
+static int
+bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
+                     enum bgp_show_type type, void *output_arg, int option,
+                     u_char use_json)
+{
+       afi_t afi = AFI_L2VPN;
+       struct bgp *bgp;
+       struct bgp_table *table;
+       struct bgp_node *rn;
+       struct bgp_node *rm;
+       struct bgp_info *ri;
+       int rd_header;
+       int header = 1;
+       char v4_header[] =
+           "   Network          Next Hop            Metric LocPrf Weight Path%s";
+       char v4_header_tag[] =
+           "   Network          Next Hop      In tag/Out tag%s";
+       char v4_header_overlay[] =
+           "   Network          Next Hop      EthTag    Overlay Index   RouterMac%s";
+
+       unsigned long output_count = 0;
+       unsigned long total_count = 0;
+       json_object *json = NULL;
+       json_object *json_nroute = NULL;
+       json_object *json_array = NULL;
+       json_object *json_scode = NULL;
+       json_object *json_ocode = NULL;
+
+       bgp = bgp_get_default();
+       if (bgp == NULL) {
+               if (!use_json)
+                       vty_out(vty, "No BGP process is configured%s",
+                               VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       if (use_json) {
+               json_scode = json_object_new_object();
+               json_ocode = json_object_new_object();
+               json = json_object_new_object();
+               json_nroute = json_object_new_object();
+
+               json_object_string_add(json_scode, "suppressed", "s");
+               json_object_string_add(json_scode, "damped", "d");
+               json_object_string_add(json_scode, "history", "h");
+               json_object_string_add(json_scode, "valid", "*");
+               json_object_string_add(json_scode, "best", ">");
+               json_object_string_add(json_scode, "internal", "i");
+
+               json_object_string_add(json_ocode, "igp", "i");
+               json_object_string_add(json_ocode, "egp", "e");
+               json_object_string_add(json_ocode, "incomplete", "?");
+       }
+
+       for (rn = bgp_table_top(bgp->rib[afi][SAFI_EVPN]); rn;
+            rn = bgp_route_next(rn)) {
+               if (use_json)
+                       continue;       /* XXX json TODO */
+
+               if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
+                       continue;
+
+               if ((table = rn->info) != NULL) {
+                       rd_header = 1;
+
+                       for (rm = bgp_table_top(table); rm;
+                            rm = bgp_route_next(rm))
+                               for (ri = rm->info; ri; ri = ri->next) {
+                                       total_count++;
+                                       if (type == bgp_show_type_neighbor) {
+                                               union sockunion *su =
+                                                   output_arg;
+
+                                               if (ri->peer->su_remote == NULL
+                                                   || !sockunion_same(ri->
+                                                                      peer->
+                                                                      su_remote,
+                                                                      su))
+                                                       continue;
+                                       }
+                                       if (header == 0) {
+                                               if (use_json) {
+                                                       if (option ==
+                                                           SHOW_DISPLAY_TAGS) {
+                                                               json_object_int_add
+                                                                   (json,
+                                                                    "bgpTableVersion",
+                                                                    0);
+                                                               json_object_string_add
+                                                                   (json,
+                                                                    "bgpLocalRouterId",
+                                                                    inet_ntoa
+                                                                    (bgp->
+                                                                     router_id));
+                                                               json_object_object_add
+                                                                   (json,
+                                                                    "bgpStatusCodes",
+                                                                    json_scode);
+                                                               json_object_object_add
+                                                                   (json,
+                                                                    "bgpOriginCodes",
+                                                                    json_ocode);
+                                                       }
+                                               } else {
+                                                       if (option ==
+                                                           SHOW_DISPLAY_TAGS)
+                                                               vty_out(vty,
+                                                                       v4_header_tag,
+                                                                       VTY_NEWLINE);
+                                                       else if (option ==
+                                                                SHOW_DISPLAY_OVERLAY)
+                                                               vty_out(vty,
+                                                                       v4_header_overlay,
+                                                                       VTY_NEWLINE);
+                                                       else {
+                                                               vty_out(vty,
+                                                                       "BGP table version is 0, local router ID is %s%s",
+                                                                       inet_ntoa
+                                                                       (bgp->
+                                                                        router_id),
+                                                                       VTY_NEWLINE);
+                                                               vty_out(vty,
+                                                                       "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s",
+                                                                       VTY_NEWLINE);
+                                                               vty_out(vty,
+                                                                       "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
+                                                                       VTY_NEWLINE,
+                                                                       VTY_NEWLINE);
+                                                               vty_out(vty,
+                                                                       v4_header,
+                                                                       VTY_NEWLINE);
+                                                       }
+                                               }
+                                               header = 0;
+                                       }
+                                       if (rd_header) {
+                                               u_int16_t type;
+                                               struct rd_as rd_as;
+                                               struct rd_ip rd_ip;
+                                               u_char *pnt;
+
+                                               pnt = rn->p.u.val;
+
+                                               /* Decode RD type. */
+                                               type = decode_rd_type(pnt);
+                                               /* Decode RD value. */
+                                               if (type == RD_TYPE_AS)
+                                                       decode_rd_as(pnt + 2,
+                                                                    &rd_as);
+                                               else if (type == RD_TYPE_AS4)
+                                                       decode_rd_as4(pnt + 2,
+                                                                     &rd_as);
+                                               else if (type == RD_TYPE_IP)
+                                                       decode_rd_ip(pnt + 2,
+                                                                    &rd_ip);
+                                               if (use_json) {
+                                                       char buffer[BUFSIZ];
+                                                       if (type == RD_TYPE_AS
+                                                           || type ==
+                                                           RD_TYPE_AS4)
+                                                               sprintf(buffer,
+                                                                       "%u:%d",
+                                                                       rd_as.
+                                                                       as,
+                                                                       rd_as.
+                                                                       val);
+                                                       else if (type ==
+                                                                RD_TYPE_IP)
+                                                               sprintf(buffer,
+                                                                       "%s:%d",
+                                                                       inet_ntoa
+                                                                       (rd_ip.
+                                                                        ip),
+                                                                       rd_ip.
+                                                                       val);
+                                                       json_object_string_add
+                                                           (json_nroute,
+                                                            "routeDistinguisher",
+                                                            buffer);
+                                               } else {
+                                                       vty_out(vty,
+                                                               "Route Distinguisher: ");
+                                                       if (type == RD_TYPE_AS)
+                                                               vty_out(vty,
+                                                                       "as2 %u:%d",
+                                                                       rd_as.
+                                                                       as,
+                                                                       rd_as.
+                                                                       val);
+                                                       else if (type ==
+                                                                RD_TYPE_AS4)
+                                                               vty_out(vty,
+                                                                       "as4 %u:%d",
+                                                                       rd_as.
+                                                                       as,
+                                                                       rd_as.
+                                                                       val);
+                                                       else if (type ==
+                                                                RD_TYPE_IP)
+                                                               vty_out(vty,
+                                                                       "ip %s:%d",
+                                                                       inet_ntoa
+                                                                       (rd_ip.
+                                                                        ip),
+                                                                       rd_ip.
+                                                                       val);
+                                                       vty_out(vty, "%s",
+                                                               VTY_NEWLINE);
+                                               }
+                                               rd_header = 0;
+                                       }
+                                       if (use_json)
+                                               json_array =
+                                                   json_object_new_array();
+                                       else
+                                               json_array = NULL;
+                                       if (option == SHOW_DISPLAY_TAGS)
+                                               route_vty_out_tag(vty, &rm->p,
+                                                                 ri, 0,
+                                                                 SAFI_EVPN,
+                                                                 json_array);
+                                       else if (option == SHOW_DISPLAY_OVERLAY)
+                                               route_vty_out_overlay(vty,
+                                                                     &rm->p,
+                                                                     ri, 0,
+                                                                     json_array);
+                                       else
+                                               route_vty_out(vty, &rm->p, ri,
+                                                             0, SAFI_EVPN,
+                                                             json_array);
+                                       output_count++;
+                               }
+                       /* XXX json */
+               }
+       }
+       if (output_count == 0)
+               vty_out(vty, "No prefixes displayed, %ld exist%s", total_count,
+                       VTY_NEWLINE);
+       else
+               vty_out(vty, "%sDisplayed %ld out of %ld total prefixes%s",
+                       VTY_NEWLINE, output_count, total_count, VTY_NEWLINE);
+       return CMD_SUCCESS;
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn,
+      show_ip_bgp_l2vpn_evpn_cmd,
+      "show [ip] bgp l2vpn evpn [json]",
+      SHOW_STR IP_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR JSON_STR)
+{
+       return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, 0,
+                                    use_json(argc, argv));
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_rd,
+      show_ip_bgp_l2vpn_evpn_rd_cmd,
+      "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn [json]",
+      SHOW_STR
+      IP_STR
+      BGP_STR
+      L2VPN_HELP_STR
+      EVPN_HELP_STR
+      "Display information for a route distinguisher\n"
+      "VPN Route Distinguisher\n" JSON_STR)
+{
+       int idx_ext_community = 6;
+       int ret;
+       struct prefix_rd prd;
+
+       ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
+       if (!ret) {
+               vty_out(vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+       return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, 0,
+                                    use_json(argc, argv));
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_all_tags,
+      show_ip_bgp_l2vpn_evpn_all_tags_cmd,
+      "show [ip] bgp l2vpn evpn all tags",
+      SHOW_STR
+      IP_STR
+      BGP_STR
+      L2VPN_HELP_STR
+      EVPN_HELP_STR
+      "Display information about all EVPN NLRIs\n"
+      "Display BGP tags for prefixes\n")
+{
+       return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, 1,
+                                    0);
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_rd_tags,
+      show_ip_bgp_l2vpn_evpn_rd_tags_cmd,
+      "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn tags",
+      SHOW_STR
+      IP_STR
+      BGP_STR
+      L2VPN_HELP_STR
+      EVPN_HELP_STR
+      "Display information for a route distinguisher\n"
+      "VPN Route Distinguisher\n" "Display BGP tags for prefixes\n")
+{
+       int idx_ext_community = 6;
+       int ret;
+       struct prefix_rd prd;
+
+       ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
+       if (!ret) {
+               vty_out(vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+       return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, 1,
+                                    0);
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_routes,
+      show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd,
+      "show [ip] bgp l2vpn evpn all neighbors A.B.C.D routes [json]",
+      SHOW_STR
+      IP_STR
+      BGP_STR
+      L2VPN_HELP_STR
+      EVPN_HELP_STR
+      "Display information about all EVPN NLRIs\n"
+      "Detailed information on TCP and BGP neighbor connections\n"
+      "Neighbor to display information about\n"
+      "Display routes learned from neighbor\n" JSON_STR)
+{
+       int idx_ipv4 = 6;
+       union sockunion su;
+       struct peer *peer;
+       int ret;
+       u_char uj = use_json(argc, argv);
+
+       ret = str2sockunion(argv[idx_ipv4]->arg, &su);
+       if (ret < 0) {
+               if (uj) {
+                       json_object *json_no = NULL;
+                       json_no = json_object_new_object();
+                       json_object_string_add(json_no, "warning",
+                                              "Malformed address");
+                       vty_out(vty, "%s%s",
+                               json_object_to_json_string(json_no),
+                               VTY_NEWLINE);
+                       json_object_free(json_no);
+               } else
+                       vty_out(vty, "Malformed address: %s%s",
+                               argv[idx_ipv4]->arg, VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       peer = peer_lookup(NULL, &su);
+       if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
+               if (uj) {
+                       json_object *json_no = NULL;
+                       json_no = json_object_new_object();
+                       json_object_string_add(json_no, "warning",
+                                              "No such neighbor or address family");
+                       vty_out(vty, "%s%s",
+                               json_object_to_json_string(json_no),
+                               VTY_NEWLINE);
+                       json_object_free(json_no);
+               } else
+                       vty_out(vty, "%% No such neighbor or address family%s",
+                               VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_neighbor, &su, 0,
+                                    uj);
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes,
+      show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd,
+      "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes [json]",
+      SHOW_STR
+      IP_STR
+      BGP_STR
+      L2VPN_HELP_STR
+      EVPN_HELP_STR
+      "Display information for a route distinguisher\n"
+      "VPN Route Distinguisher\n"
+      "Detailed information on TCP and BGP neighbor connections\n"
+      "Neighbor to display information about\n"
+      "Display routes learned from neighbor\n" JSON_STR)
+{
+       int idx_ext_community = 6;
+       int idx_ipv4 = 8;
+       int ret;
+       union sockunion su;
+       struct peer *peer;
+       struct prefix_rd prd;
+       u_char uj = use_json(argc, argv);
+
+       ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
+       if (!ret) {
+               if (uj) {
+                       json_object *json_no = NULL;
+                       json_no = json_object_new_object();
+                       json_object_string_add(json_no, "warning",
+                                              "Malformed Route Distinguisher");
+                       vty_out(vty, "%s%s",
+                               json_object_to_json_string(json_no),
+                               VTY_NEWLINE);
+                       json_object_free(json_no);
+               } else
+                       vty_out(vty, "%% Malformed Route Distinguisher%s",
+                               VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       ret = str2sockunion(argv[idx_ipv4]->arg, &su);
+       if (ret < 0) {
+               if (uj) {
+                       json_object *json_no = NULL;
+                       json_no = json_object_new_object();
+                       json_object_string_add(json_no, "warning",
+                                              "Malformed address");
+                       vty_out(vty, "%s%s",
+                               json_object_to_json_string(json_no),
+                               VTY_NEWLINE);
+                       json_object_free(json_no);
+               } else
+                       vty_out(vty, "Malformed address: %s%s",
+                               argv[idx_ext_community]->arg, VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       peer = peer_lookup(NULL, &su);
+       if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
+               if (uj) {
+                       json_object *json_no = NULL;
+                       json_no = json_object_new_object();
+                       json_object_string_add(json_no, "warning",
+                                              "No such neighbor or address family");
+                       vty_out(vty, "%s%s",
+                               json_object_to_json_string(json_no),
+                               VTY_NEWLINE);
+                       json_object_free(json_no);
+               } else
+                       vty_out(vty, "%% No such neighbor or address family%s",
+                               VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_neighbor, &su, 0,
+                                    uj);
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes,
+      show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd,
+      "show [ip] bgp l2vpn evpn all neighbors A.B.C.D advertised-routes [json]",
+      SHOW_STR
+      IP_STR
+      BGP_STR
+      L2VPN_HELP_STR
+      EVPN_HELP_STR
+      "Display information about all EVPN NLRIs\n"
+      "Detailed information on TCP and BGP neighbor connections\n"
+      "Neighbor to display information about\n"
+      "Display the routes advertised to a BGP neighbor\n" JSON_STR)
+{
+       int idx_ipv4 = 7;
+       int ret;
+       struct peer *peer;
+       union sockunion su;
+       u_char uj = use_json(argc, argv);
+
+       ret = str2sockunion(argv[idx_ipv4]->arg, &su);
+       if (ret < 0) {
+               if (uj) {
+                       json_object *json_no = NULL;
+                       json_no = json_object_new_object();
+                       json_object_string_add(json_no, "warning",
+                                              "Malformed address");
+                       vty_out(vty, "%s%s",
+                               json_object_to_json_string(json_no),
+                               VTY_NEWLINE);
+                       json_object_free(json_no);
+               } else
+                       vty_out(vty, "Malformed address: %s%s",
+                               argv[idx_ipv4]->arg, VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+       peer = peer_lookup(NULL, &su);
+       if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
+               if (uj) {
+                       json_object *json_no = NULL;
+                       json_no = json_object_new_object();
+                       json_object_string_add(json_no, "warning",
+                                              "No such neighbor or address family");
+                       vty_out(vty, "%s%s",
+                               json_object_to_json_string(json_no),
+                               VTY_NEWLINE);
+                       json_object_free(json_no);
+               } else
+                       vty_out(vty, "%% No such neighbor or address family%s",
+                               VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       return show_adj_route_vpn(vty, peer, NULL, AFI_L2VPN, SAFI_EVPN, uj);
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes,
+      show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd,
+      "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes [json]",
+      SHOW_STR
+      IP_STR
+      BGP_STR
+      L2VPN_HELP_STR
+      EVPN_HELP_STR
+      "Display information for a route distinguisher\n"
+      "VPN Route Distinguisher\n"
+      "Detailed information on TCP and BGP neighbor connections\n"
+      "Neighbor to display information about\n"
+      "Display the routes advertised to a BGP neighbor\n" JSON_STR)
+{
+       int idx_ext_community = 6;
+       int idx_ipv4 = 8;
+       int ret;
+       struct peer *peer;
+       struct prefix_rd prd;
+       union sockunion su;
+       u_char uj = use_json(argc, argv);
+
+       ret = str2sockunion(argv[idx_ipv4]->arg, &su);
+       if (ret < 0) {
+               if (uj) {
+                       json_object *json_no = NULL;
+                       json_no = json_object_new_object();
+                       json_object_string_add(json_no, "warning",
+                                              "Malformed address");
+                       vty_out(vty, "%s%s",
+                               json_object_to_json_string(json_no),
+                               VTY_NEWLINE);
+                       json_object_free(json_no);
+               } else
+                       vty_out(vty, "Malformed address: %s%s",
+                               argv[idx_ext_community]->arg, VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+       peer = peer_lookup(NULL, &su);
+       if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
+               if (uj) {
+                       json_object *json_no = NULL;
+                       json_no = json_object_new_object();
+                       json_object_string_add(json_no, "warning",
+                                              "No such neighbor or address family");
+                       vty_out(vty, "%s%s",
+                               json_object_to_json_string(json_no),
+                               VTY_NEWLINE);
+                       json_object_free(json_no);
+               } else
+                       vty_out(vty, "%% No such neighbor or address family%s",
+                               VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
+       if (!ret) {
+               if (uj) {
+                       json_object *json_no = NULL;
+                       json_no = json_object_new_object();
+                       json_object_string_add(json_no, "warning",
+                                              "Malformed Route Distinguisher");
+                       vty_out(vty, "%s%s",
+                               json_object_to_json_string(json_no),
+                               VTY_NEWLINE);
+                       json_object_free(json_no);
+               } else
+                       vty_out(vty, "%% Malformed Route Distinguisher%s",
+                               VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       return show_adj_route_vpn(vty, peer, &prd, AFI_L2VPN, SAFI_EVPN, uj);
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_all_overlay,
+      show_ip_bgp_l2vpn_evpn_all_overlay_cmd,
+      "show [ip] bgp l2vpn evpn all overlay",
+      SHOW_STR
+      IP_STR
+      BGP_STR
+      L2VPN_HELP_STR
+      EVPN_HELP_STR
+      "Display information about all EVPN NLRIs\n"
+      "Display BGP Overlay Information for prefixes\n")
+{
+       return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL,
+                                    SHOW_DISPLAY_OVERLAY, use_json(argc,
+                                                                   argv));
+}
+
+DEFUN(show_ip_bgp_evpn_rd_overlay,
+      show_ip_bgp_evpn_rd_overlay_cmd,
+      "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn overlay",
+      SHOW_STR
+      IP_STR
+      BGP_STR
+      L2VPN_HELP_STR
+      EVPN_HELP_STR
+      "Display information for a route distinguisher\n"
+      "VPN Route Distinguisher\n"
+      "Display BGP Overlay Information for prefixes\n")
+{
+       int idx_ext_community = 6;
+       int ret;
+       struct prefix_rd prd;
+
+       ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
+       if (!ret) {
+               vty_out(vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+       return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL,
+                                    SHOW_DISPLAY_OVERLAY, use_json(argc,
+                                                                   argv));
+}
+
+/* For testing purpose, static route of MPLS-VPN. */
+DEFUN(evpnrt5_network,
+      evpnrt5_network_cmd,
+      "network <A.B.C.D/M|X:X::X:X/M> rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip <A.B.C.D|X:X::X:X> routermac WORD [route-map WORD]",
+      "Specify a network to announce via BGP\n"
+      "IP prefix\n"
+      "IPv6 prefix\n"
+      "Specify Route Distinguisher\n"
+      "VPN Route Distinguisher\n"
+      "Ethernet Tag\n"
+      "Ethernet Tag Value\n"
+      "BGP label\n"
+      "label value\n"
+      "Ethernet Segment Identifier\n"
+      "ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n"
+      "Gateway IP\n"
+      "Gateway IP ( A.B.C.D )\n"
+      "Gateway IPv6 ( X:X::X:X )\n"
+      "Router Mac Ext Comm\n"
+      "Router Mac address Value ( aa:bb:cc:dd:ee:ff format)\n"
+      "Route-map to modify the attributes\n"
+      "Name of the route map\n")
+{
+       int idx_ipv4_prefixlen = 1;
+       int idx_ext_community = 3;
+       int idx_word = 7;
+       int idx_esi = 9;
+       int idx_gwip = 11;
+       int idx_ethtag = 5;
+       int idx_routermac = 13;
+       int idx_rmap = 15;
+       return bgp_static_set_safi(SAFI_EVPN, vty,
+                                  argv[idx_ipv4_prefixlen]->arg,
+                                  argv[idx_ext_community]->arg,
+                                  argv[idx_word]->arg,
+                                  argv[idx_rmap] ? argv[idx_gwip]->arg : NULL,
+                                  EVPN_IP_PREFIX, argv[idx_esi]->arg,
+                                  argv[idx_gwip]->arg, argv[idx_ethtag]->arg,
+                                  argv[idx_routermac]->arg);
+}
+
+/* For testing purpose, static route of MPLS-VPN. */
+DEFUN(no_evpnrt5_network,
+      no_evpnrt5_network_cmd,
+      "no network <A.B.C.D/M|X:X::X:X/M> rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip <A.B.C.D|X:X::X:X>",
+      NO_STR
+      "Specify a network to announce via BGP\n"
+      "IP prefix\n"
+      "IPv6 prefix\n"
+      "Specify Route Distinguisher\n"
+      "VPN Route Distinguisher\n"
+      "Ethernet Tag\n"
+      "Ethernet Tag Value\n"
+      "BGP label\n"
+      "label value\n"
+      "Ethernet Segment Identifier\n"
+      "ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n"
+      "Gateway IP\n" "Gateway IP ( A.B.C.D )\n" "Gateway IPv6 ( X:X::X:X )\n")
+{
+       int idx_ipv4_prefixlen = 2;
+       int idx_ext_community = 4;
+       int idx_label = 8;
+       int idx_ethtag = 6;
+       int idx_esi = 10;
+       int idx_gwip = 12;
+       return bgp_static_unset_safi(SAFI_EVPN, vty,
+                                    argv[idx_ipv4_prefixlen]->arg,
+                                    argv[idx_ext_community]->arg,
+                                    argv[idx_label]->arg, EVPN_IP_PREFIX,
+                                    argv[idx_esi]->arg, argv[idx_gwip]->arg,
+                                    argv[idx_ethtag]->arg);
+}
+
+void bgp_ethernetvpn_init(void)
+{
+       install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_cmd);
+       install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_cmd);
+       install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_tags_cmd);
+       install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_tags_cmd);
+       install_element(VIEW_NODE,
+                       &show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd);
+       install_element(VIEW_NODE,
+                       &show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd);
+       install_element(VIEW_NODE,
+                       &show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd);
+       install_element(VIEW_NODE,
+                       &show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd);
+       install_element(VIEW_NODE, &show_ip_bgp_evpn_rd_overlay_cmd);
+       install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd);
+       install_element(BGP_EVPN_NODE, &no_evpnrt5_network_cmd);
+       install_element(BGP_EVPN_NODE, &evpnrt5_network_cmd);
+}
diff --git a/bgpd/bgp_evpn_vty.h b/bgpd/bgp_evpn_vty.h
new file mode 100644 (file)
index 0000000..11e93a5
--- /dev/null
@@ -0,0 +1,29 @@
+/* EVPN VTY functions to EVPN
+   Copyright (C) 2017 6WIND
+
+This file is part of Free Range Routing.
+
+Free Range Routing is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Free Range Routing is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Free Range Routing; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#ifndef _FRR_BGP_EVPN_VTY_H
+#define _FRR_BGP_EVPN_VTY_H
+
+extern void bgp_ethernetvpn_init(void);
+
+#define L2VPN_HELP_STR        "Layer 2 Virtual Private Network\n"
+#define EVPN_HELP_STR        "Ethernet Virtual Private Network\n"
+
+#endif                         /* _QUAGGA_BGP_EVPN_VTY_H */
index 9607d381d9810230421abf72396ef6f6e5f45a6d..fbbcda59158beee4035b6f4ab4f1aede67ebffc1 100644 (file)
@@ -75,6 +75,7 @@ static const struct option longopts[] =
   { "vty_socket",  required_argument, NULL, OPTION_VTYSOCK },
   { "retain",      no_argument,       NULL, 'r'},
   { "no_kernel",   no_argument,       NULL, 'n'},
+  { "ecmp",        required_argument, NULL, 'e'},
   { "user",        required_argument, NULL, 'u'},
   { "group",       required_argument, NULL, 'g'},
   { "skip_runas",  no_argument,       NULL, 'S'},
@@ -176,6 +177,7 @@ redistribution between different routing protocols.\n\n\
     --vty_socket   Override vty socket path\n\
 -r, --retain       When program terminates, retain added route by bgpd.\n\
 -n, --no_kernel    Do not install route to kernel.\n\
+-e, --ecmp         Specify ECMP to use.\n\
 -u, --user         User to run as\n\
 -g, --group        Group to run as\n\
 -S, --skip_runas   Skip user and group run as\n\
@@ -468,6 +470,14 @@ main (int argc, char **argv)
        case 'A':
          vty_addr = optarg;
          break;
+        case 'e':
+          multipath_num = atoi (optarg);
+          if (multipath_num > MULTIPATH_NUM || multipath_num <= 0)
+            {
+              zlog_err ("Multipath Number specified must be less than %d and greater than 0", MULTIPATH_NUM);
+              return 1;
+            }
+          break;
        case 'P':
           /* Deal with atoi() returning 0 on failure, and bgpd not
              listening on bgp port... */
index f564ff16916df2804745d0983676523bd9d64b0b..a95c4a008efbec984410cae810181734c52a993f 100644 (file)
@@ -84,11 +84,11 @@ bgp_maximum_paths_unset (struct bgp *bgp, afi_t afi, safi_t safi,
   switch (peertype)
     {
     case BGP_PEER_IBGP:
-      bgp->maxpaths[afi][safi].maxpaths_ibgp = MULTIPATH_NUM;
+      bgp->maxpaths[afi][safi].maxpaths_ibgp = multipath_num;
       bgp->maxpaths[afi][safi].ibgp_flags = 0;
       break;
     case BGP_PEER_EBGP:
-      bgp->maxpaths[afi][safi].maxpaths_ebgp = MULTIPATH_NUM;
+      bgp->maxpaths[afi][safi].maxpaths_ebgp = multipath_num;
       break;
     default:
       return -1;
@@ -436,7 +436,7 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best,
   char path_buf[PATH_ADDPATH_STR_BUFFER];
 
   mpath_changed = 0;
-  maxpaths = MULTIPATH_NUM;
+  maxpaths = multipath_num;
   mpath_count = 0;
   cur_mpath = NULL;
   old_mpath_count = 0;
index cfdb9f3ce62d020c6ddb97678004cd9a1bc11cb0..d29fb26030907ea3d65fdf5fd69f2bb58dedddf8 100644 (file)
@@ -36,6 +36,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_mplsvpn.h"
 #include "bgpd/bgp_packet.h"
 #include "bgpd/bgp_vty.h"
+#include "bgpd/bgp_vpn.h"
 
 #if ENABLE_BGP_VNC
 #include "bgpd/rfapi/rfapi_backend.h"
@@ -146,7 +147,7 @@ decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip)
 
 #if ENABLE_BGP_VNC
 /* type == RD_TYPE_VNC_ETH */
-static void
+void
 decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth)
 {
   rd_vnc_eth->type = RD_TYPE_VNC_ETH;
@@ -288,12 +289,12 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr,
       if (attr)
         {
           bgp_update (peer, &p, addpath_id, attr, packet->afi, SAFI_MPLS_VPN,
-                      ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0);
+                      ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0, NULL);
         }
       else
         {
           bgp_withdraw (peer, &p, addpath_id, attr, packet->afi, SAFI_MPLS_VPN,
-                        ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt);
+                        ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, NULL);
         }
     }
   /* Packet length consistency check. */
@@ -470,7 +471,8 @@ DEFUN (vpnv4_network,
   int idx_ipv4_prefixlen = 1;
   int idx_ext_community = 3;
   int idx_word = 5;
-  return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, NULL);
+  return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg,
+                              argv[idx_word]->arg, NULL, 0, NULL, NULL, NULL, NULL);
 }
 
 DEFUN (vpnv4_network_route_map,
@@ -489,7 +491,8 @@ DEFUN (vpnv4_network_route_map,
   int idx_ext_community = 3;
   int idx_word = 5;
   int idx_word_2 = 7;
-  return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, argv[idx_word_2]->arg);
+  return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg,
+                              argv[idx_word_2]->arg, 0, NULL, NULL, NULL, NULL);
 }
 
 /* For testing purpose, static route of MPLS-VPN. */
@@ -507,7 +510,9 @@ DEFUN (no_vpnv4_network,
   int idx_ipv4_prefixlen = 2;
   int idx_ext_community = 4;
   int idx_word = 6;
-  return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg);
+  return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg,
+                                argv[idx_ext_community]->arg, argv[idx_word]->arg,
+                                0, NULL, NULL, NULL);
 }
 
 DEFUN (vpnv6_network,
@@ -527,9 +532,9 @@ DEFUN (vpnv6_network,
   int idx_word = 5;
   int idx_word_2 = 7;
   if (argv[idx_word_2])
-    return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, argv[idx_word_2]->arg);
+    return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, argv[idx_word_2]->arg, 0, NULL, NULL, NULL, NULL);
   else
-    return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, NULL);
+    return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, NULL, 0, NULL, NULL, NULL, NULL);
 }
 
 /* For testing purpose, static route of MPLS-VPN. */
@@ -547,178 +552,9 @@ DEFUN (no_vpnv6_network,
   int idx_ipv6_prefix = 2;
   int idx_ext_community = 4;
   int idx_word = 6;
-  return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg);
+  return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, 0, NULL, NULL, NULL);
 }
 
-#if defined(KEEP_OLD_VPN_COMMANDS)
-static int
-show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, u_char use_json, afi_t afi)
-{
-  struct bgp *bgp;
-  struct bgp_table *table;
-  struct bgp_node *rn;
-  struct bgp_node *rm;
-  struct attr *attr;
-  int rd_header;
-  int header = 1;
-  char v4_header[] = "   Network          Next Hop            Metric LocPrf Weight Path%s";
-  json_object *json = NULL;
-  json_object *json_scode = NULL;
-  json_object *json_ocode = NULL;
-  json_object *json_routes = NULL;
-  json_object *json_array = NULL;
-
-  bgp = bgp_get_default ();
-  if (bgp == NULL)
-    {
-      if (!use_json)
-        vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
-  if (use_json)
-    {
-      json_scode = json_object_new_object();
-      json_ocode = json_object_new_object();
-      json_routes = json_object_new_object();
-      json = json_object_new_object();
-
-      json_object_string_add(json_scode, "suppressed", "s");
-      json_object_string_add(json_scode, "damped", "d");
-      json_object_string_add(json_scode, "history", "h");
-      json_object_string_add(json_scode, "valid", "*");
-      json_object_string_add(json_scode, "best", ">");
-      json_object_string_add(json_scode, "internal", "i");
-
-      json_object_string_add(json_ocode, "igp", "i");
-      json_object_string_add(json_ocode, "egp", "e");
-      json_object_string_add(json_ocode, "incomplete", "?");
-    }
-
-  for (rn = bgp_table_top (bgp->rib[afi][SAFI_MPLS_VPN]); rn;
-       rn = bgp_route_next (rn))
-    {
-      if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
-        continue;
-
-      if ((table = rn->info) != NULL)
-        {
-          if (use_json)
-            json_array = json_object_new_array();
-          else
-            json_array = NULL;
-
-          rd_header = 1;
-
-          for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
-            {
-              if ((attr = rm->info) != NULL)
-                {
-                  if (header)
-                    {
-                      if (use_json)
-                        {
-                          json_object_int_add(json, "bgpTableVersion", 0);
-                          json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id));
-                          json_object_object_add(json, "bgpStatusCodes", json_scode);
-                          json_object_object_add(json, "bgpOriginCodes", json_ocode);
-                        }
-                      else
-                        {
-                          vty_out (vty, "BGP table version is 0, local router ID is %s%s",
-                                   inet_ntoa (bgp->router_id), VTY_NEWLINE);
-                          vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s",
-                                   VTY_NEWLINE);
-                          vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
-                                   VTY_NEWLINE, VTY_NEWLINE);
-                          vty_out (vty, v4_header, VTY_NEWLINE);
-                        }
-                      header = 0;
-                    }
-
-                  if (rd_header)
-                    {
-                      u_int16_t type;
-                      struct rd_as rd_as;
-                      struct rd_ip rd_ip = {0};
-#if ENABLE_BGP_VNC
-                      struct rd_vnc_eth rd_vnc_eth = {0};
-#endif
-                      u_char *pnt;
-
-                      pnt = rn->p.u.val;
-
-                      /* Decode RD type. */
-                      type = decode_rd_type (pnt);
-                      /* Decode RD value. */
-                      if (type == RD_TYPE_AS)
-                        decode_rd_as (pnt + 2, &rd_as);
-                      else if (type == RD_TYPE_AS4)
-                        decode_rd_as4 (pnt + 2, &rd_as);
-                      else if (type == RD_TYPE_IP)
-                        decode_rd_ip (pnt + 2, &rd_ip);
-#if ENABLE_BGP_VNC
-                      else if (type == RD_TYPE_VNC_ETH)
-                        decode_rd_vnc_eth (pnt, &rd_vnc_eth);
-#endif
-
-                      if (use_json)
-                        {
-                          char buffer[BUFSIZ];
-                          if (type == RD_TYPE_AS || type == RD_TYPE_AS4)
-                            sprintf (buffer, "%u:%d", rd_as.as, rd_as.val);
-                          else if (type == RD_TYPE_IP)
-                            sprintf (buffer, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
-                          json_object_string_add(json_routes, "routeDistinguisher", buffer);
-                        }
-                      else
-                        {
-                          vty_out (vty, "Route Distinguisher: ");
-
-                          if (type == RD_TYPE_AS || type == RD_TYPE_AS4)
-                            vty_out (vty, "%u:%d", rd_as.as, rd_as.val);
-                          else if (type == RD_TYPE_IP)
-                            vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
-#if ENABLE_BGP_VNC
-                          else if (type == RD_TYPE_VNC_ETH)
-                            vty_out (vty, "%u:%02x:%02x:%02x:%02x:%02x:%02x", 
-                                     rd_vnc_eth.local_nve_id, 
-                                     rd_vnc_eth.macaddr.octet[0],
-                                     rd_vnc_eth.macaddr.octet[1],
-                                     rd_vnc_eth.macaddr.octet[2],
-                                     rd_vnc_eth.macaddr.octet[3],
-                                     rd_vnc_eth.macaddr.octet[4],
-                                     rd_vnc_eth.macaddr.octet[5]);
-#endif
-
-                          vty_out (vty, "%s", VTY_NEWLINE);
-                        }
-                      rd_header = 0;
-                    }
-                  route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN, use_json, json_array);
-                }
-            }
-          if (use_json)
-            {
-              struct prefix *p;
-              char buf_a[BUFSIZ];
-              char buf_b[BUFSIZ];
-              p = &rm->p;
-              sprintf(buf_a, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf_b, BUFSIZ), p->prefixlen);
-              json_object_object_add(json_routes, buf_a, json_array);
-            }
-        }
-    }
-  if (use_json)
-    {
-      json_object_object_add(json, "routes", json_routes);
-      vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
-      json_object_free(json);
-    }
-  return CMD_SUCCESS;
-}
-#endif
-
 int
 bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd,
                   enum bgp_show_type type, void *output_arg, int tags, u_char use_json)
@@ -1281,8 +1117,7 @@ DEFUN (show_ip_bgp_vpn_all_neighbor_advertised_routes,
             vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
           return CMD_WARNING;
         }
-
-      return show_adj_route_vpn (vty, peer, NULL, uj, afi);
+      return show_adj_route_vpn (vty, peer, NULL, AFI_IP, SAFI_MPLS_VPN, uj);
     }
   return CMD_SUCCESS;
 }
@@ -1360,7 +1195,7 @@ DEFUN (show_ip_bgp_vpn_rd_neighbor_advertised_routes,
           return CMD_WARNING;
         }
 
-      return show_adj_route_vpn (vty, peer, &prd, uj, afi);
+      return show_adj_route_vpn (vty, peer, &prd, AFI_IP, SAFI_MPLS_VPN, uj);
     }
   return CMD_SUCCESS;
 }
index 148e5946f101ddbfa73140998921abb53b9bcf0b..518bf6143f5c1e69957b07bff3c2eb6ba87071ab 100644 (file)
@@ -100,7 +100,8 @@ extern void decode_rd_as (u_char *, struct rd_as *);
 extern void decode_rd_as4 (u_char *, struct rd_as *);
 extern void decode_rd_ip (u_char *, struct rd_ip *);
 #if ENABLE_BGP_VNC
-extern void decode_vnc_eth (u_char *, struct rd_vnc_eth *);
+extern void
+decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth);
 #endif
 extern int str2prefix_rd (const char *, struct prefix_rd *);
 extern int str2tag (const char *, u_char *);
index 7dbb439be1b7342706f716eb51bd6c41aeeb4040..51079f31e03b77be43d733e250f41177cf1226b2 100644 (file)
@@ -93,6 +93,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso
                   case AFI_IP6:
                     json_object_string_add(json_cap, "capabilityErrorMultiProtocolAfi", "IPv6");
                   break;
+                  case AFI_L2VPN:
+                    json_object_string_add(json_cap, "capabilityErrorMultiProtocolAfi", "L2VPN");
+                  break;
                   default:
                     json_object_int_add(json_cap, "capabilityErrorMultiProtocolAfiUnknown", ntohs (mpc.afi));
                   break;
@@ -111,6 +114,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso
                   case SAFI_ENCAP:
                     json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "encap");
                   break;
+                  case SAFI_EVPN:
+                    json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "EVPN");
+                  break;
                   default:
                     json_object_int_add(json_cap, "capabilityErrorMultiProtocolSafiUnknown", mpc.safi);
                   break;
@@ -127,6 +133,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso
                   case AFI_IP6:
                     vty_out (vty, "AFI IPv6, ");
                   break;
+                  case AFI_L2VPN:
+                    vty_out (vty, "AFI L2VPN, ");
+                  break;
                   default:
                     vty_out (vty, "AFI Unknown %d, ", ntohs (mpc.afi));
                   break;
@@ -145,6 +154,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso
                   case SAFI_ENCAP:
                     vty_out (vty, "SAFI ENCAP");
                   break;
+                  case SAFI_EVPN:
+                    vty_out (vty, "SAFI EVPN");
+                  break;
                   default:
                     vty_out (vty, "SAFI Unknown %d ", mpc.safi);
                   break;
@@ -1136,7 +1148,8 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability)
          && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST]
          && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST]
          && ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]
-         && ! peer->afc_nego[AFI_IP6][SAFI_ENCAP])
+         && ! peer->afc_nego[AFI_IP6][SAFI_ENCAP]
+         && ! peer->afc_nego[AFI_L2VPN][SAFI_EVPN])
        {
          zlog_err ("%s [Error] Configured AFI/SAFIs do not "
                    "overlap with received MP capabilities",
index 2df22ab568e9fcbb1c1c648f7f80d8c365c50c02..0dbf41a4a18202b2b94ba60ee1298ec279f116c2 100644 (file)
@@ -49,7 +49,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_lcommunity.h"
 #include "bgpd/bgp_network.h"
 #include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_evpn.h"
 #include "bgpd/bgp_encap.h"
+#include "bgpd/bgp_evpn.h"
 #include "bgpd/bgp_advertise.h"
 #include "bgpd/bgp_vty.h"
 #include "bgpd/bgp_updgrp.h"
@@ -246,13 +248,13 @@ bgp_write_packet (struct peer *peer)
                if (!(PAF_SUBGRP(paf))->t_coalesce &&
                    peer->afc_nego[afi][safi] && peer->synctime
                    && ! CHECK_FLAG (peer->af_sflags[afi][safi],
-                                    PEER_STATUS_EOR_SEND))
+                                    PEER_STATUS_EOR_SEND)
+                    && safi != SAFI_EVPN)
                  {
                    SET_FLAG (peer->af_sflags[afi][safi],
                              PEER_STATUS_EOR_SEND);
                    return bgp_update_packet_eor (peer, afi, safi);
                  }
-
              }
            continue;
          }
@@ -1327,19 +1329,24 @@ bgp_update_explicit_eors (struct peer *peer)
   bgp_check_update_delay(peer->bgp);
 }
 
-/* Frontend for NLRI parsing, to fan-out to AFI/SAFI specific parsers */
+/* Frontend for NLRI parsing, to fan-out to AFI/SAFI specific parsers 
+ * mp_withdraw, if set, is used to nullify attr structure on most of the calling safi function
+ * and for evpn, passed as parameter
+ */
 int
-bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
+bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet, int mp_withdraw)
 {
   switch (packet->safi)
     {
       case SAFI_UNICAST:
       case SAFI_MULTICAST:
-        return bgp_nlri_parse_ip (peer, attr, packet);
+        return bgp_nlri_parse_ip (peer, mp_withdraw?NULL:attr, packet);
       case SAFI_MPLS_VPN:
-        return bgp_nlri_parse_vpn (peer, attr, packet);
+        return bgp_nlri_parse_vpn (peer, mp_withdraw?NULL:attr, packet);
       case SAFI_ENCAP:
-        return bgp_nlri_parse_encap (peer, attr, packet);
+        return bgp_nlri_parse_encap (peer, mp_withdraw?NULL:attr, packet);
+      case SAFI_EVPN:
+        return bgp_nlri_parse_evpn (peer, attr, packet, mp_withdraw);
     }
   return -1;
 }
@@ -1531,11 +1538,11 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
         {
           case NLRI_UPDATE:
           case NLRI_MP_UPDATE:
-            nlri_ret = bgp_nlri_parse (peer, NLRI_ATTR_ARG, &nlris[i]);
+            nlri_ret = bgp_nlri_parse (peer, NLRI_ATTR_ARG, &nlris[i], 0);
             break;
           case NLRI_WITHDRAW:
           case NLRI_MP_WITHDRAW:
-            nlri_ret = bgp_nlri_parse (peer, NULL, &nlris[i]);
+            nlri_ret = bgp_nlri_parse (peer, &attr, &nlris[i], 1);
             break;
           default:
             nlri_ret = -1;
index 78855c342580f6d94d475b3eb80537aac2a829a7..ea5c7a8998077203a7a78b1e3b32f675b343f0af 100644 (file)
@@ -55,7 +55,7 @@ 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 *);
+extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *, int mp_withdraw);
 
 extern void bgp_update_restarted_peers (struct peer *);
 extern void bgp_update_implicit_eors (struct peer *);
index 0123ed17eaa360087cd20f2b1545406adcd92e6f..ced587e738437e4af9332ff1428f702864275ca6 100644 (file)
@@ -68,6 +68,11 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/rfapi/vnc_import_bgp.h"
 #include "bgpd/rfapi/vnc_export_bgp.h"
 #endif
+#include "bgpd/bgp_encap_types.h"
+#include "bgpd/bgp_encap_tlv.h"
+#include "bgpd/bgp_evpn.h"
+#include "bgpd/bgp_evpn_vty.h"
+
 
 /* Extern from bgp_dump.c */
 extern const char *bgp_origin_str[];
@@ -84,7 +89,8 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix
   if (!table)
     return NULL;
   
-  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
+  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) ||
+      (safi == SAFI_EVPN))
     {
       prn = bgp_node_get (table, (struct prefix *) prd);
 
@@ -97,7 +103,8 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix
 
   rn = bgp_node_get (table, p);
 
-  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
+  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) ||
+      (safi == SAFI_EVPN))
     rn->prn = prn;
 
   return rn;
@@ -1190,7 +1197,7 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
   struct bgp *bgp;
   struct attr *riattr;
   struct peer_af *paf;
-  char buf[SU_ADDRSTRLEN];
+  char buf[PREFIX_STRLEN];
   int ret;
   int transparent;
   int reflect;
@@ -1222,8 +1229,7 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
      * direct and direct_ext type routes originate internally even
      * though they can have peer pointers that reference other systems
      */
-    char    buf[BUFSIZ];
-    prefix2str(p, buf, BUFSIZ);
+    prefix2str(p, buf, PREFIX_STRLEN);
     zlog_debug("%s: pfx %s bgp_direct->vpn route peer safe", __func__, buf);
     samepeer_safe = 1;
   }
@@ -1293,11 +1299,9 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
       (IPV4_ADDR_SAME (&onlypeer->remote_id, &riattr->extra->originator_id)))
        {
           if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
-           zlog_debug ("%s [Update:SEND] %s/%d originator-id is same as "
+           zlog_debug ("%s [Update:SEND] %s originator-id is same as "
                  "remote router-id",
-                 onlypeer->host,
-                 inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
-                 p->prefixlen);
+                 onlypeer->host, prefix2str (p, buf, sizeof (buf)));
          return 0;
        }
 
@@ -1311,10 +1315,8 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
        if (prefix_list_apply (peer->orf_plist[afi][safi], p) == PREFIX_DENY)
          {
             if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
-              zlog_debug ("%s [Update:SEND] %s/%d is filtered via ORF",
-                          peer->host,
-                          inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
-                          p->prefixlen);
+              zlog_debug ("%s [Update:SEND] %s is filtered via ORF",
+                          peer->host, prefix2str (p, buf, sizeof (buf)));
            return 0;
          }
       }
@@ -1323,10 +1325,8 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
   if (bgp_output_filter (peer, p, riattr, afi, safi) == FILTER_DENY)
     {
       if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
-       zlog_debug ("%s [Update:SEND] %s/%d is filtered",
-             peer->host,
-             inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
-             p->prefixlen);
+       zlog_debug ("%s [Update:SEND] %s is filtered",
+             peer->host, prefix2str (p, buf, sizeof (buf)));
       return 0;
     }
 
@@ -2276,12 +2276,66 @@ info_make (int type, int sub_type, u_short instance, struct peer *peer, struct a
 }
 
 static void
-bgp_info_addpath_rx_str(u_int32_t addpath_id, char *buf)
+overlay_index_update(struct attr *attr, struct eth_segment_id *eth_s_id, union gw_addr *gw_ip)
 {
-  if (addpath_id)
-    sprintf(buf, " with addpath ID %d", addpath_id);
+  struct attr_extra *extra;
+
+  if(!attr)
+    return;
+  extra = bgp_attr_extra_get(attr);
+
+  if(eth_s_id == NULL)
+    {
+      memset(&(extra->evpn_overlay.eth_s_id),0, sizeof(struct eth_segment_id));
+    }
+  else
+    {
+      memcpy(&(extra->evpn_overlay.eth_s_id), eth_s_id, sizeof(struct eth_segment_id));
+    }
+  if(gw_ip == NULL)
+    {
+      memset(&(extra->evpn_overlay.gw_ip), 0, sizeof(union gw_addr));
+    }
+  else
+    {
+      memcpy(&(extra->evpn_overlay.gw_ip),gw_ip, sizeof(union gw_addr));
+    }
 }
 
+static bool
+overlay_index_equal(afi_t afi, struct bgp_info *info, struct eth_segment_id *eth_s_id, union gw_addr *gw_ip)
+{
+  struct eth_segment_id *info_eth_s_id, *info_eth_s_id_remote;
+  union gw_addr *info_gw_ip, *info_gw_ip_remote;
+  char temp[16];
+
+  if(afi != AFI_L2VPN)
+    return true;
+  if (!info->attr || !info->attr->extra)
+    {
+      memset(&temp, 0, 16);
+      info_eth_s_id = (struct eth_segment_id *)&temp;
+      info_gw_ip = (union gw_addr *)&temp;
+      if(eth_s_id == NULL && gw_ip == NULL)
+        return true;
+    }
+  else 
+    {
+      info_eth_s_id = &(info->attr->extra->evpn_overlay.eth_s_id);
+      info_gw_ip = &(info->attr->extra->evpn_overlay.gw_ip);
+    }
+  if(gw_ip == NULL)
+    info_gw_ip_remote = (union gw_addr *)&temp;
+  else
+    info_gw_ip_remote = gw_ip;
+  if(eth_s_id == NULL)
+    info_eth_s_id_remote =  (struct eth_segment_id *)&temp;
+  else
+    info_eth_s_id_remote =  eth_s_id;
+  if(!memcmp(info_gw_ip, info_gw_ip_remote, sizeof(union gw_addr)))
+    return false;
+  return !memcmp(info_eth_s_id, info_eth_s_id_remote, sizeof(struct eth_segment_id));
+}
 
 /* Check if received nexthop is valid or not. */
 static int
@@ -2339,7 +2393,7 @@ int
 bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
             struct attr *attr, afi_t afi, safi_t safi, int type,
             int sub_type, struct prefix_rd *prd, u_char *tag,
-            int soft_reconfig)
+            int soft_reconfig, struct bgp_route_evpn* evpn)
 {
   int ret;
   int aspath_loop_count = 0;
@@ -2351,8 +2405,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
   struct bgp_info *ri;
   struct bgp_info *new;
   const char *reason;
-  char buf[SU_ADDRSTRLEN];
-  char buf2[30];
+  char pfx_buf[BGP_PRD_PATH_STRLEN];
   int connected = 0;
   int do_loop_check = 1;
 #if ENABLE_BGP_VNC
@@ -2462,20 +2515,18 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
       /* Same attribute comes in. */
       if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED) 
-          && attrhash_cmp (ri->attr, attr_new))
+          && attrhash_cmp (ri->attr, attr_new)
+          && (overlay_index_equal(afi, ri, evpn==NULL?NULL:&evpn->eth_s_id,
+                                  evpn==NULL?NULL:&evpn->gw_ip)))
        {
          if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
              && peer->sort == BGP_PEER_EBGP
              && CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
            {
              if (bgp_debug_update(peer, p, NULL, 1))
-                {
-                  bgp_info_addpath_rx_str(addpath_id, buf2);
-                 zlog_debug ("%s rcvd %s/%d%s",
-                             peer->host,
-                             inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
-                             p->prefixlen, buf2);
-                }
+                zlog_debug ("%s rcvd %s", peer->host,
+                            bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+                                      addpath_id, pfx_buf, sizeof (pfx_buf)));
 
              if (bgp_damp_update (ri, rn, afi, safi) != BGP_DAMP_SUPPRESSED)
                {
@@ -2493,11 +2544,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                     peer->rcvd_attr_printed = 1;
                   }
 
-                  bgp_info_addpath_rx_str(addpath_id, buf2);
-                 zlog_debug ("%s rcvd %s/%d%s...duplicate ignored",
+                 zlog_debug ("%s rcvd %s...duplicate ignored",
                              peer->host,
-                             inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
-                             p->prefixlen, buf2);
+                              bgp_debug_rdpfxpath2str (prd, p, addpath_id ?
+                                1 : 0, addpath_id, pfx_buf, sizeof (pfx_buf)));
                 }
 
              /* graceful restart STALE flag unset. */
@@ -2518,25 +2568,18 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
       if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
         {
           if (bgp_debug_update(peer, p, NULL, 1))
-            {
-              bgp_info_addpath_rx_str(addpath_id, buf2);
-              zlog_debug ("%s rcvd %s/%d%s, flapped quicker than processing",
-                          peer->host,
-                          inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
-                          p->prefixlen, buf2);
-            }
+            zlog_debug ("%s rcvd %s, flapped quicker than processing",
+                        peer->host,
+                        bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+                                  addpath_id, pfx_buf, sizeof (pfx_buf)));
           bgp_info_restore (rn, ri);
         }
 
       /* Received Logging. */
       if (bgp_debug_update(peer, p, NULL, 1))
-        {
-          bgp_info_addpath_rx_str(addpath_id, buf2);
-         zlog_debug ("%s rcvd %s/%d%s",
-                   peer->host,
-                   inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
-                   p->prefixlen, buf2);
-        }
+         zlog_debug ("%s rcvd %s", peer->host,
+                      bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+                                        addpath_id, pfx_buf, sizeof (pfx_buf)));
 
       /* graceful restart STALE flag unset. */
       if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
@@ -2594,7 +2637,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
       ri->attr = attr_new;
 
       /* Update MPLS tag.  */
-      if (safi == SAFI_MPLS_VPN)
+      if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN)
         memcpy ((bgp_info_extra_get (ri))->tag, tag, 3);
 
 #if ENABLE_BGP_VNC
@@ -2615,6 +2658,12 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
             }
         }
 #endif
+      /* Update Overlay Index */
+      if(afi == AFI_L2VPN)
+        {
+          overlay_index_update(ri->attr, evpn==NULL?NULL:&evpn->eth_s_id,
+                               evpn==NULL?NULL:&evpn->gw_ip);
+        }
 
       /* Update bgp route dampening information.  */
       if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
@@ -2710,20 +2759,24 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
           peer->rcvd_attr_printed = 1;
         }
 
-      bgp_info_addpath_rx_str(addpath_id, buf2);
-      zlog_debug ("%s rcvd %s/%d%s",
-                 peer->host,
-                 inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
-                 p->prefixlen, buf2);
+      zlog_debug ("%s rcvd %s", peer->host,
+                  bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+                                 addpath_id, pfx_buf, sizeof (pfx_buf)));
     }
 
   /* Make new BGP info. */
   new = info_make(type, sub_type, 0, peer, attr_new, rn);
 
   /* Update MPLS tag. */
-  if (safi == SAFI_MPLS_VPN)
+  if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN)
     memcpy ((bgp_info_extra_get (new))->tag, tag, 3);
 
+  /* Update Overlay Index */
+  if(afi == AFI_L2VPN)
+    {
+      overlay_index_update(new->attr, evpn==NULL?NULL:&evpn->eth_s_id,
+                           evpn==NULL?NULL:&evpn->gw_ip);
+    }
   /* Nexthop reachability check. */
   if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST)
     {
@@ -2820,11 +2873,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
           peer->rcvd_attr_printed = 1;
         }
 
-      bgp_info_addpath_rx_str(addpath_id, buf2);
-      zlog_debug ("%s rcvd UPDATE about %s/%d%s -- DENIED due to: %s",
+      zlog_debug ("%s rcvd UPDATE about %s -- DENIED due to: %s",
                   peer->host,
-                  inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
-                  p->prefixlen, buf2, reason);
+                  bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+                             addpath_id, pfx_buf, sizeof (pfx_buf)), reason);
     }
 
   if (ri)
@@ -2849,11 +2901,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 int
 bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
               struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type,
-             struct prefix_rd *prd, u_char *tag)
+             struct prefix_rd *prd, u_char *tag, struct bgp_route_evpn *evpn)
 {
   struct bgp *bgp;
-  char buf[SU_ADDRSTRLEN];
-  char buf2[30];
+  char pfx_buf[BGP_PRD_PATH_STRLEN];
   struct bgp_node *rn;
   struct bgp_info *ri;
 
@@ -2883,10 +2934,10 @@ bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
     if (!bgp_adj_in_unset (rn, peer, addpath_id))
       {
         if (bgp_debug_update (peer, p, NULL, 1))
-          zlog_debug ("%s withdrawing route %s/%d "
-                     "not in adj-in", peer->host,
-                     inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
-                     p->prefixlen);
+          zlog_debug ("%s withdrawing route %s not in adj-in",
+                      peer->host,
+                      bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+                                       addpath_id, pfx_buf, sizeof (pfx_buf)));
         bgp_unlock_node (rn);
         return 0;
       }
@@ -2900,20 +2951,20 @@ bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
   /* Logging. */
   if (bgp_debug_update(peer, p, NULL, 1))
     {
-      bgp_info_addpath_rx_str(addpath_id, buf2);
-      zlog_debug ("%s rcvd UPDATE about %s/%d%s -- withdrawn",
-               peer->host,
-               inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
-               p->prefixlen, buf2);
+      zlog_debug ("%s rcvd UPDATE about %s -- withdrawn",
+                  peer->host,
+                  bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+                                   addpath_id, pfx_buf, sizeof (pfx_buf)));
     }
 
   /* Withdraw specified route from routing table. */
   if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
     bgp_rib_withdraw (rn, ri, peer, afi, safi, prd);
   else if (bgp_debug_update(peer, p, NULL, 1))
-    zlog_debug ("%s Can't find the route %s/%d", peer->host,
-               inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
-               p->prefixlen);
+    zlog_debug ("%s Can't find the route %s",
+                peer->host,
+                bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+                                    addpath_id, pfx_buf, sizeof (pfx_buf)));
 
   /* Unlock bgp_node_get() lock. */
   bgp_unlock_node (rn);
@@ -3047,7 +3098,7 @@ bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi,
 
            ret = bgp_update (peer, &rn->p, ain->addpath_rx_id, ain->attr,
                               afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                             prd, tag, 1);
+                             prd, tag, 1, NULL);
 
            if (ret < 0)
              {
@@ -3067,7 +3118,7 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
   if (peer->status != Established)
     return;
 
-  if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP))
+  if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP) && (safi != SAFI_EVPN))
     bgp_soft_reconfig_table (peer, afi, safi, NULL, NULL);
   else
     for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
@@ -3288,7 +3339,7 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
   if (!peer->clear_node_queue->thread)
     peer_lock (peer);
 
-  if (safi != SAFI_MPLS_VPN && safi != SAFI_ENCAP)
+  if (safi != SAFI_MPLS_VPN && safi != SAFI_ENCAP && safi != SAFI_EVPN)
     bgp_clear_route_table (peer, afi, safi, NULL);
   else
     for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
@@ -3421,40 +3472,56 @@ void
 bgp_cleanup_routes (struct bgp *bgp)
 {
   afi_t afi;
+  struct bgp_node *rn;
 
   for (afi = AFI_IP; afi < AFI_MAX; ++afi)
     {
-      struct bgp_node *rn;
-
+      if (afi == AFI_L2VPN)
+        continue;
       bgp_cleanup_table(bgp->rib[afi][SAFI_UNICAST], SAFI_UNICAST);
-
       /*
-       * VPN and ENCAP tables are two-level (RD is top level)
+       * VPN and ENCAP and EVPN tables are two-level (RD is top level)
        */
-      for (rn = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); rn;
-          rn = bgp_route_next (rn))
-       {
-         if (rn->info)
-           {
-             bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_MPLS_VPN);
-             bgp_table_finish ((struct bgp_table **)&(rn->info));
-             rn->info = NULL;
-             bgp_unlock_node(rn);
-           }
-       }
-
-      for (rn = bgp_table_top(bgp->rib[afi][SAFI_ENCAP]); rn;
-          rn = bgp_route_next (rn))
-       {
-         if (rn->info)
-           {
-             bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_ENCAP);
-             bgp_table_finish ((struct bgp_table **)&(rn->info));
-             rn->info = NULL;
-             bgp_unlock_node(rn);
-           }
+      if (afi != AFI_L2VPN)
+        {
+          safi_t safi;
+          safi = SAFI_MPLS_VPN;
+          for (rn = bgp_table_top(bgp->rib[afi][safi]); rn;
+               rn = bgp_route_next (rn))
+            {
+              if (rn->info)
+                {
+                  bgp_cleanup_table((struct bgp_table *)(rn->info), safi);
+                  bgp_table_finish ((struct bgp_table **)&(rn->info));
+                  rn->info = NULL;
+                  bgp_unlock_node(rn);
+                }
+            }
+          safi = SAFI_ENCAP;
+          for (rn = bgp_table_top(bgp->rib[afi][safi]); rn;
+               rn = bgp_route_next (rn))
+            {
+              if (rn->info)
+                {
+                  bgp_cleanup_table((struct bgp_table *)(rn->info), safi);
+                  bgp_table_finish ((struct bgp_table **)&(rn->info));
+                  rn->info = NULL;
+                  bgp_unlock_node(rn);
+                }
+            }
        }
     }
+  for (rn = bgp_table_top(bgp->rib[AFI_L2VPN][SAFI_EVPN]); rn;
+       rn = bgp_route_next (rn))
+    {
+      if (rn->info)
+        {
+          bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_EVPN);
+          bgp_table_finish ((struct bgp_table **)&(rn->info));
+          rn->info = NULL;
+          bgp_unlock_node(rn);
+        }
+    }
 }
 
 void
@@ -3597,10 +3664,10 @@ bgp_nlri_parse_ip (struct peer *peer, struct attr *attr,
       /* Normal process. */
       if (attr)
        ret = bgp_update (peer, &p, addpath_id, attr, afi, safi,
-                         ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0);
+                         ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0, NULL);
       else
        ret = bgp_withdraw (peer, &p, addpath_id, attr, afi, safi,
-                           ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL);
+                           ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, NULL);
 
       /* Address family configuration mismatch or maximum-prefix count
          overflow. */
@@ -3630,6 +3697,8 @@ bgp_static_free (struct bgp_static *bgp_static)
 {
   if (bgp_static->rmap.name)
     XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name);
+  if(bgp_static->eth_s_id)
+    XFREE(MTYPE_ATTR, bgp_static->eth_s_id);
   XFREE (MTYPE_BGP_STATIC, bgp_static);
 }
 
@@ -3925,6 +3994,7 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p,
 #if ENABLE_BGP_VNC
   u_int32_t        label = 0;
 #endif
+  union gw_addr add;
 
   assert (bgp_static);
 
@@ -3936,6 +4006,33 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p,
   attr.med = bgp_static->igpmetric;
   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
 
+  if ((safi == SAFI_EVPN) || (safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
+    {
+      if (bgp_static->igpnexthop.s_addr)
+        {
+          bgp_attr_extra_get (&attr)->mp_nexthop_global_in = bgp_static->igpnexthop;
+          bgp_attr_extra_get (&attr)->mp_nexthop_len = IPV4_MAX_BYTELEN;
+        }
+    }
+  if(afi == AFI_L2VPN)
+    {
+      if (bgp_static->gatewayIp.family == AF_INET)
+        add.ipv4.s_addr = bgp_static->gatewayIp.u.prefix4.s_addr;
+      else if (bgp_static->gatewayIp.family == AF_INET6)
+        memcpy( &(add.ipv6), &(bgp_static->gatewayIp.u.prefix6), sizeof (struct in6_addr));
+      overlay_index_update(&attr, bgp_static->eth_s_id, &add);
+      if (bgp_static->encap_tunneltype == BGP_ENCAP_TYPE_VXLAN)
+        {
+          struct bgp_encap_type_vxlan bet;
+          memset(&bet, 0, sizeof(struct bgp_encap_type_vxlan));
+          bet.vnid = p->u.prefix_evpn.eth_tag;
+          bgp_encap_type_vxlan_to_tlv(&bet, &attr);
+        }
+      if (bgp_static->router_mac)
+        {
+          bgp_add_routermac_ecom (&attr, bgp_static->router_mac);
+        }
+    }
   /* Apply route-map. */
   if (bgp_static->rmap.name)
     {
@@ -3979,7 +4076,10 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p,
 
   if (ri)
     {
+      union gw_addr add;
+      memset(&add, 0, sizeof(union gw_addr));
       if (attrhash_cmp (ri->attr, attr_new) &&
+          overlay_index_equal(afi, ri, bgp_static->eth_s_id, &add) &&
           !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
         {
           bgp_unlock_node (rn);
@@ -4037,7 +4137,6 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p,
 
   /* Register new BGP information. */
   bgp_info_add (rn, new);
-
   /* route_node_get lock */
   bgp_unlock_node (rn);
 
@@ -4209,7 +4308,7 @@ bgp_static_add (struct bgp *bgp)
       for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn))
        if (rn->info != NULL)
          {      
-           if (safi == SAFI_MPLS_VPN)
+           if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN))
              {
                table = rn->info;
 
@@ -4243,7 +4342,7 @@ bgp_static_delete (struct bgp *bgp)
       for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn))
        if (rn->info != NULL)
          {      
-           if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
+           if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN))
              {
                table = rn->info;
 
@@ -4341,7 +4440,8 @@ bgp_purge_static_redist_routes (struct bgp *bgp)
 int
 bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str,
                      const char *rd_str, const char *tag_str,
-                     const char *rmap_str)
+                     const char *rmap_str, int evpn_type, const char *esi, const char *gwip,
+                     const char *ethtag, const char *routermac)
 {
   VTY_DECLVAR_CONTEXT(bgp, bgp);
   int ret;
@@ -4353,7 +4453,14 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str,
   struct bgp_static *bgp_static;
   u_char tag[3];
   afi_t afi;
+  struct prefix gw_ip;
 
+  if(safi == SAFI_EVPN)
+    afi = AFI_L2VPN;
+  else
+    afi = AFI_IP;
+
+  /* validate ip prefix */
   ret = str2prefix (ip_str, &p);
   if (! ret)
     {
@@ -4361,6 +4468,12 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str,
       return CMD_WARNING;
     }
   apply_mask (&p);
+  if ( (afi == AFI_L2VPN) &&
+       (bgp_build_evpn_prefix ( evpn_type, ethtag!=NULL?atol(ethtag):0, &p)))
+    {
+      vty_out (vty, "%% L2VPN prefix could not be forged%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
 
   ret = str2prefix_rd (rd_str, &prd);
   if (! ret)
@@ -4369,20 +4482,47 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str,
       return CMD_WARNING;
     }
 
-  ret = str2tag (tag_str, tag);
-  if (! ret)
+  if (tag_str)
     {
-      vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE);
-      return CMD_WARNING;
+      ret = str2tag (tag_str, tag);
+      if (! ret)
+        {
+          vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
     }
-  if (p.family == AF_INET)
-    afi = AFI_IP;
-  else if (p.family == AF_INET6)
-    afi = AFI_IP6;
   else
     {
-      vty_out (vty, "%% Non Supported prefix%s", VTY_NEWLINE);
-      return CMD_WARNING;
+      encode_label (0, tag);
+    }
+  if (safi == SAFI_EVPN)
+    {
+      if( esi && str2esi (esi, NULL) == 0)
+        {
+          vty_out (vty, "%% Malformed ESI%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+      if( routermac && prefix_str2mac (routermac, NULL) == 0)
+        {
+          vty_out (vty, "%% Malformed Router MAC%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+      if (gwip)
+        {
+          memset (&gw_ip, 0, sizeof (struct prefix));
+          ret = str2prefix (gwip, &gw_ip);
+          if (! ret)
+            {
+              vty_out (vty, "%% Malformed GatewayIp%s", VTY_NEWLINE);
+              return CMD_WARNING;
+            }
+          if((gw_ip.family == AF_INET &&  (p.u.prefix_evpn.flags & IP_PREFIX_V6))
+             || (gw_ip.family == AF_INET6 &&  (p.u.prefix_evpn.flags & IP_PREFIX_V4)))
+            {
+              vty_out (vty, "%% GatewayIp family differs with IP prefix%s", VTY_NEWLINE);
+              return CMD_WARNING;
+            }
+        }
     }
   prn = bgp_node_get (bgp->route[afi][safi],
                        (struct prefix *)&prd);
@@ -4417,6 +4557,22 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str,
          bgp_static->rmap.name = strdup (rmap_str);
          bgp_static->rmap.map = route_map_lookup_by_name (rmap_str);
        }
+
+      if (safi == SAFI_EVPN)
+        {
+          if(esi)
+            {
+              bgp_static->eth_s_id = XCALLOC (MTYPE_ATTR, sizeof(struct eth_segment_id));
+              str2esi (esi, bgp_static->eth_s_id);
+            }
+          if( routermac)
+            {
+              bgp_static->router_mac = XCALLOC (MTYPE_ATTR, ETHER_ADDR_LEN+1);
+              prefix_str2mac (routermac, bgp_static->router_mac);
+            }
+          if (gwip)
+            prefix_copy (&bgp_static->gatewayIp, &gw_ip);
+        }
       rn->info = bgp_static;
 
       bgp_static->valid = 1;
@@ -4429,7 +4585,8 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str,
 /* Configure static BGP network. */
 int
 bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str,
-                      const char *rd_str, const char *tag_str)
+                      const char *rd_str, const char *tag_str,
+                      int evpn_type, const char *esi, const char *gwip, const char *ethtag)
 {
   VTY_DECLVAR_CONTEXT(bgp, bgp);
   int ret;
@@ -4440,6 +4597,12 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str,
   struct bgp_table *table;
   struct bgp_static *bgp_static;
   u_char tag[3];
+  afi_t afi;
+
+  if(safi == SAFI_EVPN)
+    afi = AFI_L2VPN;
+  else
+    afi = AFI_IP;
 
   /* Convert IP prefix string to struct prefix. */
   ret = str2prefix (ip_str, &p);
@@ -4449,7 +4612,12 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str,
       return CMD_WARNING;
     }
   apply_mask (&p);
-
+  if ( (afi == AFI_L2VPN) &&
+       (bgp_build_evpn_prefix ( evpn_type, ethtag!=NULL?atol(ethtag):0, &p)))
+    {
+      vty_out (vty, "%% L2VPN prefix could not be forged%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
   ret = str2prefix_rd (rd_str, &prd);
   if (! ret)
     {
@@ -4464,10 +4632,10 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str,
       return CMD_WARNING;
     }
 
-  prn = bgp_node_get (bgp->route[AFI_IP][safi],
+  prn = bgp_node_get (bgp->route[afi][safi],
                        (struct prefix *)&prd);
   if (prn->info == NULL)
-    prn->info = bgp_table_init (AFI_IP, safi);
+    prn->info = bgp_table_init (afi, safi);
   else
     bgp_unlock_node (prn);
   table = prn->info;
@@ -4476,7 +4644,7 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str,
 
   if (rn)
     {
-      bgp_static_withdraw_safi (bgp, &p, AFI_IP, safi, &prd, tag);
+      bgp_static_withdraw_safi (bgp, &p, afi, safi, &prd, tag);
 
       bgp_static = rn->info;
       bgp_static_free (bgp_static);
@@ -5099,7 +5267,7 @@ bgp_aggregate_increment (struct bgp *bgp, struct prefix *p,
   struct bgp_table *table;
 
   /* MPLS-VPN aggregation is not yet supported. */
-  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
+  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN))
     return;
 
   table = bgp->aggregate[afi][safi];
@@ -5136,7 +5304,7 @@ bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p,
   struct bgp_table *table;
 
   /* MPLS-VPN aggregation is not yet supported. */
-  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
+  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN))
     return;
 
   table = bgp->aggregate[afi][safi];
@@ -5795,6 +5963,11 @@ route_vty_out_route (struct prefix *p, struct vty *vty)
       else
         len += vty_out (vty, "/%d", p->prefixlen);
     }
+  else if (p->family == AF_ETHERNET)
+    {
+      prefix2str(p, buf, PREFIX_STRLEN);
+      len = vty_out (vty, "%s", buf);
+    }
   else
     len = vty_out (vty, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
                   p->prefixlen);
@@ -5924,7 +6097,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
        * neccessarily the same as the prefix address family.
        * Both SAFI_MPLS_VPN and SAFI_ENCAP use the MP nexthop field
        */
-      if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN))
+      if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN))
         {
          if (attr->extra)
             {
@@ -5956,7 +6129,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
             {
               json_nexthop_global = json_object_new_object();
 
-             if (safi == SAFI_MPLS_VPN)
+             if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN))
                 json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->extra->mp_nexthop_global_in));
               else
                 json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->nexthop));
@@ -5966,7 +6139,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
             }
           else
             {
-             if (safi == SAFI_MPLS_VPN)
+             if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN))
                vty_out (vty, "%-16s",
                          inet_ntoa (attr->extra->mp_nexthop_global_in));
              else
@@ -6180,9 +6353,10 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, struct attr *attr, safi_t
           if (p->family == AF_INET &&
               (safi == SAFI_MPLS_VPN ||
                safi == SAFI_ENCAP ||
+               safi == SAFI_EVPN ||
                !BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
             {
-              if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
+              if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN)
                 json_object_string_add(json_net, "nextHop", inet_ntoa (attr->extra->mp_nexthop_global_in));
               else
                 json_object_string_add(json_net, "nextHop", inet_ntoa (attr->nexthop));
@@ -6218,9 +6392,10 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, struct attr *attr, safi_t
           if (p->family == AF_INET &&
               (safi == SAFI_MPLS_VPN ||
                safi == SAFI_ENCAP ||
+               safi == SAFI_EVPN ||
                !BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
             {
-              if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
+              if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN)
                 vty_out (vty, "%-16s",
                          inet_ntoa (attr->extra->mp_nexthop_global_in));
               else
@@ -6281,7 +6456,7 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
   json_object *json_out = NULL;
   struct attr *attr;
   u_int32_t label = 0;
-  
+
   if (!binfo->extra)
     return;
 
@@ -6304,10 +6479,11 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
   attr = binfo->attr;
   if (attr) 
     {
-      if (p->family == AF_INET
-          && (safi == SAFI_MPLS_VPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
+      if (((p->family == AF_INET) && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
+          || (safi == SAFI_EVPN && p->family == AF_ETHERNET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
+          || (!BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
        {
-         if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
+         if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN)
             {
               if (json)
                 json_object_string_add(json_out, "mpNexthopGlobalIn", inet_ntoa (attr->extra->mp_nexthop_global_in));
@@ -6322,7 +6498,9 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
                 vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
             }
        }
-      else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr))
+      else if (((p->family == AF_INET6) && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
+               || (safi == SAFI_EVPN && p->family == AF_ETHERNET && BGP_ATTR_NEXTHOP_AFI_IP6(attr))
+               || (BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
        {
          assert (attr->extra);
          char buf_a[BUFSIZ];
@@ -6371,10 +6549,97 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
   else
     {
       vty_out (vty, "notag/%d", label);
+
       vty_out (vty, "%s", VTY_NEWLINE);
     }
 }  
 
+void
+route_vty_out_overlay (struct vty *vty, struct prefix *p,
+                       struct bgp_info *binfo, int display, json_object *json_paths)
+{
+  struct attr *attr;
+  char buf[BUFSIZ];
+  json_object *json_path = NULL;
+
+  if (json_paths)
+    json_path = json_object_new_object();
+
+  if (!binfo->extra)
+    return;
+
+  /* short status lead text */
+  route_vty_short_status_out (vty, binfo, json_path);
+
+  /* print prefix and mask */
+  if (! display)
+    route_vty_out_route (p, vty);
+  else
+    vty_out (vty, "%*s", 17, " ");
+
+  /* Print attribute */
+  attr = binfo->attr;
+  if (attr)
+    {
+      if (attr->extra)
+        {
+          char buf1[BUFSIZ];
+          int af = NEXTHOP_FAMILY(attr->extra->mp_nexthop_len);
+
+          switch (af) {
+          case AF_INET:
+            vty_out (vty, "%-16s", inet_ntop(af,
+                                             &attr->extra->mp_nexthop_global_in, buf, BUFSIZ));
+            break;
+          case AF_INET6:
+            vty_out (vty, "%s(%s)",
+                     inet_ntop (af,
+                                &attr->extra->mp_nexthop_global, buf, BUFSIZ),
+                     inet_ntop (af,
+                                &attr->extra->mp_nexthop_local, buf1, BUFSIZ));
+            break;
+          default:
+            vty_out(vty, "?");
+          }
+        } else {
+        vty_out(vty, "?");
+      }
+    }
+
+  if(attr->extra)
+    {
+      struct eth_segment_id *id = &(attr->extra->evpn_overlay.eth_s_id);
+      char *str = esi2str(id);
+      vty_out (vty, "%s", str);
+      XFREE (MTYPE_TMP, str);
+      if (p->u.prefix_evpn.flags & IP_PREFIX_V4)
+       {
+          vty_out (vty, "/%s", inet_ntoa (attr->extra->evpn_overlay.gw_ip.ipv4));
+       }
+      else if (p->u.prefix_evpn.flags & IP_PREFIX_V6)
+       {
+          vty_out (vty, "/%s",
+                   inet_ntop (AF_INET6, &(attr->extra->evpn_overlay.gw_ip.ipv6),
+                              buf, BUFSIZ));
+       }
+      if(attr->extra->ecommunity)
+        {
+          char *mac = NULL;
+          struct ecommunity_val *routermac = ecommunity_lookup (attr->extra->ecommunity,
+                                                                ECOMMUNITY_ENCODE_EVPN,
+                                                                ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC);
+          if(routermac)
+            mac = ecom_mac2str((char *)routermac->val);
+          if(mac)
+            {
+              vty_out (vty, "/%s",(char *)mac);
+              XFREE(MTYPE_TMP, mac);
+            }
+        }
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
 /* dampening route */
 static void
 damp_route_vty_out (struct vty *vty, struct prefix *p, struct bgp_info *binfo,
@@ -6717,9 +6982,10 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
       if (p->family == AF_INET &&
           (safi == SAFI_MPLS_VPN ||
            safi == SAFI_ENCAP ||
+           safi == SAFI_EVPN ||
            !BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
        {
-          if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
+          if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN)
             {
               if (json_paths)
                 json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->extra->mp_nexthop_global_in));
@@ -7656,11 +7922,15 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
     }
   else
     {
+      if (p->family == AF_ETHERNET)
+        prefix2str (p, buf2, INET6_ADDRSTRLEN);
+      else
+        inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN);
       vty_out (vty, "BGP routing table entry for %s%s%s/%d%s",
-              ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) ?
+              ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) ?
               prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""),
-              safi == SAFI_MPLS_VPN ? ":" : "",
-              inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN),
+              ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) ? ":" : "",
+              buf2,
               p->prefixlen, VTY_NEWLINE);
     }
 
@@ -7779,7 +8049,7 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
       json_paths = json_object_new_array();
     }
 
-  if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
+  if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN)
     {
       for (rn = bgp_table_top (rib); rn; rn = bgp_route_next (rn))
         {
@@ -8088,7 +8358,6 @@ DEFUN (show_ip_bgp,
        "Display route and more specific routes\n"
        JSON_STR)
 {
-  vrf_id_t vrf = VRF_DEFAULT;
   afi_t afi = AFI_IP6;
   safi_t safi = SAFI_UNICAST;
   int exact_match = 0;
@@ -8096,23 +8365,13 @@ DEFUN (show_ip_bgp,
   struct bgp *bgp = NULL;
   int idx = 0;
 
-  bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+  bgp_vty_find_and_parse_afi_safi_bgp (vty, argv, argc, &idx, &afi, &safi, &bgp);
   if (!idx)
     return CMD_WARNING;
 
   int uj = use_json (argc, argv);
   if (uj) argc--;
 
-  bgp = bgp_lookup_by_vrf_id (vrf);
-  if (bgp == NULL)
-    {
-      if (vrf == VRF_DEFAULT)
-        vty_out (vty, "Can't find BGP instance (default)%s", VTY_NEWLINE);
-      else
-        vty_out (vty, "Can't find BGP instance %d%s", vrf, VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
   if (argv_find(argv, argc, "cidr-only", &idx))
     return bgp_show (vty, bgp, afi, safi, bgp_show_type_cidr_only, NULL, uj);
 
@@ -8195,7 +8454,6 @@ DEFUN (show_ip_bgp_route,
 
   afi_t afi = AFI_IP6;
   safi_t safi = SAFI_UNICAST;
-  vrf_id_t vrf = VRF_DEFAULT;;
   char *prefix = NULL;
   struct bgp *bgp = NULL;
   enum bgp_path_type path_type;
@@ -8203,20 +8461,11 @@ DEFUN (show_ip_bgp_route,
 
   int idx = 0;
 
-  bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+  bgp_vty_find_and_parse_afi_safi_bgp (vty, argv, argc, &idx, &afi, &safi, &bgp);
   if (!idx)
     return CMD_WARNING;
 
-  if (vrf != VRF_ALL)
-    {
-      bgp = bgp_lookup_by_vrf_id (vrf);
-      if (bgp == NULL)
-        {
-          vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE);
-          return CMD_WARNING;
-        }
-    }
-  else
+  if (!bgp)
     {
       vty_out (vty, "Specified 'all' vrf's but this command currently only works per view/vrf%s", VTY_NEWLINE);
       return CMD_WARNING;
@@ -8264,12 +8513,12 @@ DEFUN (show_ip_bgp_regexp,
        "Display routes matching the AS path regular expression\n"
        "A regular-expression to match the BGP AS paths\n")
 {
-  vrf_id_t vrf = VRF_DEFAULT;
   afi_t afi = AFI_IP6;
   safi_t safi = SAFI_UNICAST;
+  struct bgp *bgp = NULL;
 
   int idx = 0;
-  bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+  bgp_vty_find_and_parse_afi_safi_bgp (vty, argv, argc, &idx, &afi, &safi, &bgp);
   if (!idx)
     return CMD_WARNING;
 
@@ -8294,12 +8543,12 @@ DEFUN (show_ip_bgp_instance_all,
        BGP_SAFI_HELP_STR
        JSON_STR)
 {
-  vrf_id_t vrf = VRF_DEFAULT;
   afi_t afi = AFI_IP;
   safi_t safi = SAFI_UNICAST;
+  struct bgp *bgp = NULL;
 
   int idx = 0;
-  bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+  bgp_vty_find_and_parse_afi_safi_bgp (vty, argv, argc, &idx, &afi, &safi, &bgp);
   if (!idx)
     return CMD_WARNING;
 
@@ -8983,41 +9232,19 @@ DEFUN (show_ip_bgp_instance_neighbor_prefix_counts,
        "Display detailed prefix count information\n"
        JSON_STR)
 {
-  vrf_id_t vrf = VRF_DEFAULT;
   afi_t afi = AFI_IP6;
   safi_t safi = SAFI_UNICAST;
   struct peer *peer;
   int idx = 0;
   struct bgp *bgp = NULL;
 
-  bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+  bgp_vty_find_and_parse_afi_safi_bgp (vty, argv, argc, &idx, &afi, &safi, &bgp);
   if (!idx)
     return CMD_WARNING;
 
   int uj = use_json (argc, argv);
   if (uj) argc--;
 
-  if (vrf != VRF_ALL)
-    {
-      bgp = bgp_lookup_by_vrf_id (vrf);
-      if (bgp == NULL)
-        {
-          if (uj)
-            {
-              json_object *json_no = NULL;
-              json_no = json_object_new_object();
-              json_object_string_add(json_no, "warning", "Can't find BGP view");
-              vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
-              json_object_free(json_no);
-            }
-          else
-            vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE);
-          return CMD_WARNING;
-        }
-    }
-  else
-    bgp = NULL;
-
   argv_find (argv, argc, "neighbors", &idx);
   peer = peer_lookup_in_view (vty, bgp, argv[idx+1]->arg, uj);
   if (! peer)
@@ -9079,7 +9306,27 @@ DEFUN (show_ip_bgp_vpn_all_route_prefix,
 }
 #endif /* KEEP_OLD_VPN_COMMANDS */
 
-static void
+DEFUN (show_ip_bgp_l2vpn_evpn_all_route_prefix,
+       show_ip_bgp_l2vpn_evpn_all_route_prefix_cmd,
+       "show [ip] bgp l2vpn evpn all <A.B.C.D|A.B.C.D/M> [json]",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       L2VPN_HELP_STR
+       EVPN_HELP_STR
+       "Display information about all EVPN NLRIs\n"
+       "Network in the BGP routing table to display\n"
+       "Network in the BGP routing table to display\n"
+       JSON_STR)
+{
+  int idx = 0;
+  char *network = NULL;
+  network = argv_find (argv, argc, "A.B.C.D", &idx) ? argv[idx]->arg : NULL;
+  network = argv_find (argv, argc, "A.B.C.D/M", &idx) ? argv[idx]->arg : NULL;
+  return bgp_show_route (vty, NULL, network, AFI_L2VPN, SAFI_EVPN, NULL, 0, BGP_PATH_ALL, use_json(argc, argv));
+}
+
+ static void
 show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
                 int in, const char *rmap_name, u_char use_json, json_object *json)
 {
@@ -9339,7 +9586,6 @@ DEFUN (show_ip_bgp_instance_neighbor_advertised_route,
        "Name of the route map\n"
        JSON_STR)
 {
-  vrf_id_t vrf = VRF_DEFAULT;
   afi_t afi = AFI_IP6;
   safi_t safi = SAFI_UNICAST;
   char *rmap_name = NULL;
@@ -9350,29 +9596,13 @@ DEFUN (show_ip_bgp_instance_neighbor_advertised_route,
 
   int idx = 0;
 
-  bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+  bgp_vty_find_and_parse_afi_safi_bgp (vty, argv, argc, &idx, &afi, &safi, &bgp);
   if (!idx)
     return CMD_WARNING;
 
   int uj = use_json (argc, argv);
   if (uj) argc--;
 
-  bgp = bgp_lookup_by_vrf_id (vrf);
-  if (bgp == NULL)
-    {
-      if (uj)
-       {
-         json_object *json_no = NULL;
-         json_no = json_object_new_object();
-         json_object_string_add(json_no, "warning", "Can't find BGP view");
-         vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
-         json_object_free(json_no);
-            }
-      else
-       vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
   /* neighbors <A.B.C.D|X:X::X:X|WORD> */
   argv_find (argv, argc, "neighbors", &idx);
   peerstr = argv[++idx]->arg;
@@ -9519,7 +9749,6 @@ DEFUN (show_ip_bgp_neighbor_routes,
        "Display routes learned from neighbor\n"
        JSON_STR)
 {
-  vrf_id_t vrf = VRF_DEFAULT;
   char *peerstr = NULL;
   struct bgp *bgp = NULL;
   afi_t afi = AFI_IP6;
@@ -9529,34 +9758,13 @@ DEFUN (show_ip_bgp_neighbor_routes,
 
   int idx = 0;
 
-  bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+  bgp_vty_find_and_parse_afi_safi_bgp (vty, argv, argc, &idx, &afi, &safi, &bgp);
   if (!idx)
     return CMD_WARNING;
 
   int uj = use_json (argc, argv);
   if (uj) argc--;
 
-  if (vrf != VRF_ALL)
-    {
-      bgp = bgp_lookup_by_vrf_id (vrf);
-      if (bgp == NULL)
-        {
-          if (uj)
-            {
-              json_object *json_no = NULL;
-              json_no = json_object_new_object();
-              json_object_string_add(json_no, "warning", "Can't find BGP view");
-              vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
-              json_object_free(json_no);
-            }
-          else
-            vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE);
-          return CMD_WARNING;
-        }
-    }
-  else
-    bgp = NULL;
-
   /* neighbors <A.B.C.D|X:X::X:X|WORD> */
   argv_find (argv, argc, "neighbors", &idx);
   peerstr = argv[++idx]->arg;
@@ -10054,7 +10262,7 @@ bgp_clear_damp_route (struct vty *vty, const char *view_name,
 
   match.family = afi2family (afi);
 
-  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
+  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN))
     {
       for (rn = bgp_table_top (bgp->rib[AFI_IP][safi]); rn; rn = bgp_route_next (rn))
         {
@@ -10217,6 +10425,57 @@ bgp_config_write_network_vpn (struct vty *vty, struct bgp *bgp,
   return 0;
 }
 
+static int
+bgp_config_write_network_evpn (struct vty *vty, struct bgp *bgp,
+                               afi_t afi, safi_t safi, int *write)
+{
+  struct bgp_node *prn;
+  struct bgp_node *rn;
+  struct bgp_table *table;
+  struct prefix *p;
+  struct prefix_rd *prd;
+  struct bgp_static *bgp_static;
+  char buf[PREFIX_STRLEN];
+  char buf2[SU_ADDRSTRLEN];
+  char rdbuf[RD_ADDRSTRLEN];
+
+  /* Network configuration. */
+  for (prn = bgp_table_top (bgp->route[afi][safi]); prn; prn = bgp_route_next (prn))
+    if ((table = prn->info) != NULL)
+      for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) 
+       if ((bgp_static = rn->info) != NULL)
+         {
+            char *macrouter = NULL;
+            char *esi = NULL;
+
+            if(bgp_static->router_mac)
+              macrouter = prefix_mac2str(bgp_static->router_mac, NULL, 0);
+            if(bgp_static->eth_s_id)
+              esi = esi2str(bgp_static->eth_s_id);
+           p = &rn->p;
+           prd = (struct prefix_rd *) &prn->p;
+
+           /* "address-family" display.  */
+           bgp_config_write_family_header (vty, afi, safi, write);
+
+           /* "network" configuration display.  */
+           prefix_rd2str (prd, rdbuf, RD_ADDRSTRLEN);
+
+            inet_ntop (AF_INET, &bgp_static->igpnexthop, buf2, SU_ADDRSTRLEN);
+
+            prefix2str (p, buf, sizeof (buf)),
+           vty_out (vty, " network %s rd %s ethtag %u tag %u esi %s gwip %s routermac %s",
+                    buf, rdbuf, p->u.prefix_evpn.eth_tag,
+                     decode_label (bgp_static->tag), esi, buf2 , macrouter);
+           vty_out (vty, "%s", VTY_NEWLINE);
+            if (macrouter)
+              XFREE (MTYPE_TMP, macrouter);
+            if (esi)
+              XFREE (MTYPE_TMP, esi);
+         }
+  return 0;
+}
+
 /* Configuration of static route announcement and aggregate
    information. */
 int
@@ -10232,6 +10491,9 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp,
   if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
     return bgp_config_write_network_vpn (vty, bgp, afi, safi, write);
 
+  if (afi == AFI_L2VPN && safi == SAFI_EVPN)
+    return bgp_config_write_network_evpn (vty, bgp, afi, safi, write);
+
   /* Network configuration. */
   for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) 
     if ((bgp_static = rn->info) != NULL)
@@ -10434,7 +10696,8 @@ bgp_route_init (void)
   install_element (VIEW_NODE, &show_ip_bgp_vpn_all_route_prefix_cmd);
 #endif /* KEEP_OLD_VPN_COMMANDS */
   install_element (VIEW_NODE, &show_bgp_afi_vpn_rd_route_cmd);
-
+  install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_route_prefix_cmd);
+  
  /* BGP dampening clear commands */
   install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd);
   install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd);
index 2103338b7d6d5ee41c0fdc7f4c83c1bed8038cf8..e75978d003fd8ee03d3786e510db762142bf1462 100644 (file)
@@ -25,6 +25,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgp_table.h"
 
 struct bgp_nexthop_cache;
+struct bgp_route_evpn;
 
 enum bgp_show_type
 {
@@ -93,7 +94,7 @@ struct bgp_info_extra
            struct in6_addr addr6;
          } un;                 /* cached un address */
          time_t create_time;
-         struct prefix aux_prefix; /* AFI_ETHER: the IP addr, if family set */
+         struct prefix aux_prefix; /* AFI_L2VPN: the IP addr, if family set */
       } import;
 
   } vnc;
@@ -202,6 +203,12 @@ struct bgp_static
 
   /* MPLS label.  */
   u_char tag[3];
+
+  /* EVPN */
+  struct eth_segment_id *eth_s_id;
+  struct ethaddr *router_mac;
+  uint16_t   encap_tunneltype;
+  struct prefix gatewayIp;
 };
 
 #define BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen) \
@@ -312,17 +319,20 @@ extern void bgp_static_update (struct bgp *, struct prefix *, struct bgp_static
 extern void bgp_static_withdraw (struct bgp *, struct prefix *, afi_t, safi_t);
                      
 extern int bgp_static_set_safi (safi_t safi, struct vty *vty, const char *,
-                          const char *, const char *, const char *);
+                                const char *, const char *, const char *,
+                                int, const char *, const char *, const char *, const char *);
 
 extern int bgp_static_unset_safi (safi_t safi, struct vty *, const char *,
-                            const char *, const char *);
+                                  const char *, const char *,
+                                  int, const char *, const char *, const char *);
 
 /* this is primarily for MPLS-VPN */
 extern int bgp_update (struct peer *, struct prefix *, u_int32_t, struct attr *,
-                      afi_t, safi_t, int, int, struct prefix_rd *, 
-                      u_char *, int);
+                      afi_t, safi_t, int, int, struct prefix_rd *,
+                      u_char *, int, struct bgp_route_evpn *);
 extern int bgp_withdraw (struct peer *, struct prefix *, u_int32_t, struct attr *,
-                        afi_t, safi_t, int, int, struct prefix_rd *, u_char *);
+                        afi_t, safi_t, int, int, struct prefix_rd *, u_char *, 
+                         struct bgp_route_evpn *);
 
 /* for bgp_nexthop and bgp_damp */
 extern void bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t);
@@ -350,6 +360,9 @@ extern safi_t bgp_node_safi (struct vty *);
 extern void route_vty_out (struct vty *, struct prefix *, struct bgp_info *, int, safi_t, json_object *);
 extern void route_vty_out_tag (struct vty *, struct prefix *, struct bgp_info *, int, safi_t, json_object *);
 extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, safi_t, u_char, json_object *);
+extern void
+route_vty_out_overlay (struct vty *vty, struct prefix *p,
+                       struct bgp_info *binfo, int display, json_object *json);
 
 extern int
 subgroup_process_announce_selected (struct update_subgroup *subgrp,
index 48f56a29b24fca6591ea522110a6624fad5ecc00..efb2046e1256a7b8e2e6655e0544cc809c1e7ffe 100644 (file)
@@ -605,6 +605,7 @@ subgroup_announce_table (struct update_subgroup *subgrp,
 
   if (safi != SAFI_MPLS_VPN
       && safi != SAFI_ENCAP
+      && safi != SAFI_EVPN
       && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
     subgroup_default_originate (subgrp, 0);
 
@@ -668,7 +669,8 @@ subgroup_announce_route (struct update_subgroup *subgrp)
     return;
 
   if (SUBGRP_SAFI (subgrp) != SAFI_MPLS_VPN &&
-      SUBGRP_SAFI (subgrp) != SAFI_ENCAP)
+      SUBGRP_SAFI (subgrp) != SAFI_ENCAP &&
+      SUBGRP_SAFI (subgrp) != SAFI_EVPN)
     subgroup_announce_table (subgrp, NULL);
   else
     for (rn = bgp_table_top (update_subgroup_rib (subgrp)); rn;
index 79c11358feab631a7e9bb4592cfedf5f7048de74..8839de391e12d5beabefe063ab5a6f58706a17ec 100644 (file)
@@ -53,6 +53,7 @@
 #include "bgpd/bgp_updgrp.h"
 #include "bgpd/bgp_nexthop.h"
 #include "bgpd/bgp_nht.h"
+#include "bgpd/bgp_mplsvpn.h"
 
 /********************
  * PRIVATE FUNCTIONS
@@ -546,7 +547,7 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf)
            }
 
           if (gnh_modified)
-            stream_put_in6_addr_at (s, vec->offset + 1 + (nhlen-IPV6_MAX_BYTELEN), mod_v6nhg);
+            stream_put_in6_addr_at (s, vec->offset + 1, mod_v6nhg);
           if (lnh_modified)
             stream_put_in6_addr_at (s, vec->offset + 1 + (nhlen-IPV6_MAX_BYTELEN), mod_v6nhl);
 
@@ -617,8 +618,11 @@ static void
 bgp_info_addpath_tx_str (int addpath_encode, u_int32_t addpath_tx_id,
                          char *buf)
 {
+  buf[0] = '\0';
   if (addpath_encode)
     sprintf(buf, " with addpath ID %d", addpath_tx_id);
+  else
+    buf[0] = '\0';
 }
 
 /* Make BGP update packet.  */
@@ -648,6 +652,7 @@ subgroup_update_packet (struct update_subgroup *subgrp)
   int num_pfx = 0;
   int addpath_encode = 0;
   u_int32_t addpath_tx_id = 0;
+  struct prefix_rd *prd = NULL;
 
   if (!subgrp)
     return NULL;
@@ -751,7 +756,6 @@ subgroup_update_packet (struct update_subgroup *subgrp)
       else
        {
          /* Encode the prefix in MP_REACH_NLRI attribute */
-         struct prefix_rd *prd = NULL;
          u_char *tag = NULL;
 
          if (rn->prn)
@@ -764,16 +768,16 @@ subgroup_update_packet (struct update_subgroup *subgrp)
                                          (peer_cap_enhe(peer) ? AFI_IP6 :
                                           AFI_MAX), /* get from NH */
                                          &vecarr, adv->baa->attr);
-          bgp_packet_mpattr_prefix (snlri, afi, safi, &rn->p, prd, tag,
-                                    addpath_encode, addpath_tx_id);
+
+          bgp_packet_mpattr_prefix (snlri, afi, safi, &rn->p, prd,
+                                    tag, addpath_encode, addpath_tx_id, adv->baa->attr);
        }
 
       num_pfx++;
 
       if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0))
        {
-          char buf[INET6_BUFSIZ];
-          char tx_id_buf[30];
+          char pfx_buf[BGP_PRD_PATH_STRLEN];
 
           if (!send_attr_printed)
             {
@@ -782,11 +786,11 @@ subgroup_update_packet (struct update_subgroup *subgrp)
               send_attr_printed = 1;
             }
 
-          bgp_info_addpath_tx_str (addpath_encode, addpath_tx_id, tx_id_buf);
-          zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s",
+          zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s",
                       subgrp->update_group->id, subgrp->id,
-                      inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ),
-                      rn->p.prefixlen, tx_id_buf);
+                      bgp_debug_rdpfxpath2str (prd, &rn->p, addpath_encode,
+                                               addpath_tx_id,
+                                               pfx_buf, sizeof (pfx_buf)));
        }
 
       /* Synchnorize attribute.  */
@@ -863,6 +867,8 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
   int num_pfx = 0;
   int addpath_encode = 0;
   u_int32_t addpath_tx_id = 0;
+  struct prefix_rd *prd = NULL;
+
 
   if (!subgrp)
     return NULL;
@@ -905,8 +911,6 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
        stream_put_prefix_addpath (s, &rn->p, addpath_encode, addpath_tx_id);
       else
        {
-         struct prefix_rd *prd = NULL;
-
          if (rn->prn)
            prd = (struct prefix_rd *) &rn->prn->p;
 
@@ -921,20 +925,20 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
            }
 
          bgp_packet_mpunreach_prefix (s, &rn->p, afi, safi, prd, NULL,
-                                       addpath_encode, addpath_tx_id);
+                                       addpath_encode, addpath_tx_id, NULL);
        }
 
       num_pfx++;
 
       if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0))
        {
-          char buf[INET6_BUFSIZ];
-          char tx_id_buf[30];
-          bgp_info_addpath_tx_str (addpath_encode, addpath_tx_id, tx_id_buf);
-         zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s -- unreachable",
+          char pfx_buf[BGP_PRD_PATH_STRLEN];
+
+         zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s -- unreachable",
                       subgrp->update_group->id, subgrp->id,
-                      inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ),
-                      rn->p.prefixlen, tx_id_buf);
+                      bgp_debug_rdpfxpath2str (prd, &rn->p,
+                                               addpath_encode, addpath_tx_id,
+                                               pfx_buf, sizeof (pfx_buf)));
        }
 
       subgrp->scount--;
@@ -1010,16 +1014,16 @@ subgroup_default_update_packet (struct update_subgroup *subgrp,
   if (bgp_debug_update(NULL, &p, subgrp->update_group, 0))
     {
       char attrstr[BUFSIZ];
-      char buf[INET6_BUFSIZ];
+      char buf[PREFIX_STRLEN];
       char tx_id_buf[30];
       attrstr[0] = '\0';
 
       bgp_dump_attr (peer, attr, attrstr, BUFSIZ);
       bgp_info_addpath_tx_str (addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, tx_id_buf);
-      zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s %s",
+      zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s%s %s",
                   (SUBGRP_UPDGRP (subgrp))->id, subgrp->id,
-                  inet_ntop (p.family, &(p.u.prefix), buf, INET6_BUFSIZ),
-                  p.prefixlen, tx_id_buf, attrstr);
+                  prefix2str (&p, buf, sizeof (buf)),
+                  tx_id_buf, attrstr);
     }
 
   s = stream_new (BGP_MAX_PACKET_SIZE);
@@ -1084,14 +1088,13 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp)
 
   if (bgp_debug_update(NULL, &p, subgrp->update_group, 0))
     {
-      char buf[INET6_BUFSIZ];
+      char buf[PREFIX_STRLEN];
       char tx_id_buf[INET6_BUFSIZ];
 
       bgp_info_addpath_tx_str (addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, tx_id_buf);
-      zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s -- unreachable",
+      zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s%s -- unreachable",
                   (SUBGRP_UPDGRP (subgrp))->id, subgrp->id,
-                  inet_ntop (p.family, &(p.u.prefix), buf, INET6_BUFSIZ),
-                  p.prefixlen, tx_id_buf);
+                  prefix2str (&p, buf, sizeof (buf)), tx_id_buf);
     }
 
   s = stream_new (BGP_MAX_PACKET_SIZE);
@@ -1126,7 +1129,7 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp)
       mplen_pos = bgp_packet_mpunreach_start (s, afi, safi);
       bgp_packet_mpunreach_prefix (s, &p, afi, safi, NULL, NULL,
                                    addpath_encode,
-                                   BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
+                                   BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, NULL);
 
       /* Set the mp_unreach attr's length */
       bgp_packet_mpunreach_end (s, mplen_pos);
diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c
new file mode 100644 (file)
index 0000000..edc5891
--- /dev/null
@@ -0,0 +1,200 @@
+/* VPN Related functions
+   Copyright (C) 2017 6WIND
+
+This file is part of Free Range Routing
+
+Free Range Routing is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Free Range Routing is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Free Range Routing; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+#include "command.h"
+#include "prefix.h"
+#include "lib/json.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_vpn.h"
+
+int
+show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd,
+                    afi_t afi, safi_t safi, u_char use_json)
+{
+  struct bgp *bgp;
+  struct bgp_table *table;
+  struct bgp_node *rn;
+  struct bgp_node *rm;
+  struct attr *attr;
+  int rd_header;
+  int header = 1;
+  char v4_header[] = "   Network          Next Hop            Metric LocPrf Weight Path%s";
+  json_object *json = NULL;
+  json_object *json_scode = NULL;
+  json_object *json_ocode = NULL;
+  json_object *json_routes = NULL;
+  json_object *json_array = NULL;
+
+  bgp = bgp_get_default ();
+  if (bgp == NULL)
+    {
+      if (!use_json)
+        vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (use_json)
+    {
+      json_scode = json_object_new_object();
+      json_ocode = json_object_new_object();
+      json_routes = json_object_new_object();
+      json = json_object_new_object();
+
+      json_object_string_add(json_scode, "suppressed", "s");
+      json_object_string_add(json_scode, "damped", "d");
+      json_object_string_add(json_scode, "history", "h");
+      json_object_string_add(json_scode, "valid", "*");
+      json_object_string_add(json_scode, "best", ">");
+      json_object_string_add(json_scode, "internal", "i");
+
+      json_object_string_add(json_ocode, "igp", "i");
+      json_object_string_add(json_ocode, "egp", "e");
+      json_object_string_add(json_ocode, "incomplete", "?");
+    }
+
+  for (rn = bgp_table_top (bgp->rib[afi][SAFI_MPLS_VPN]); rn;
+       rn = bgp_route_next (rn))
+    {
+      if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
+        continue;
+
+      if ((table = rn->info) != NULL)
+        {
+          if (use_json)
+            json_array = json_object_new_array();
+          else
+            json_array = NULL;
+
+          rd_header = 1;
+
+          for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
+            {
+              if ((attr = rm->info) != NULL)
+                {
+                  if (header)
+                    {
+                      if (use_json)
+                        {
+                          json_object_int_add(json, "bgpTableVersion", 0);
+                          json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id));
+                          json_object_object_add(json, "bgpStatusCodes", json_scode);
+                          json_object_object_add(json, "bgpOriginCodes", json_ocode);
+                        }
+                      else
+                        {
+                          vty_out (vty, "BGP table version is 0, local router ID is %s%s",
+                                   inet_ntoa (bgp->router_id), VTY_NEWLINE);
+                          vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s",
+                                   VTY_NEWLINE);
+                          vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
+                                   VTY_NEWLINE, VTY_NEWLINE);
+                          vty_out (vty, v4_header, VTY_NEWLINE);
+                        }
+                      header = 0;
+                    }
+
+                  if (rd_header)
+                    {
+                      u_int16_t type;
+                      struct rd_as rd_as;
+                      struct rd_ip rd_ip = {0};
+#if ENABLE_BGP_VNC
+                      struct rd_vnc_eth rd_vnc_eth = {0};
+#endif
+                      u_char *pnt;
+
+                      pnt = rn->p.u.val;
+
+                      /* Decode RD type. */
+                      type = decode_rd_type (pnt);
+                      /* Decode RD value. */
+                      if (type == RD_TYPE_AS)
+                        decode_rd_as (pnt + 2, &rd_as);
+                      else if (type == RD_TYPE_AS4)
+                        decode_rd_as4 (pnt + 2, &rd_as);
+                      else if (type == RD_TYPE_IP)
+                        decode_rd_ip (pnt + 2, &rd_ip);
+#if ENABLE_BGP_VNC
+                      else if (type == RD_TYPE_VNC_ETH)
+                        decode_rd_vnc_eth (pnt, &rd_vnc_eth);
+#endif
+
+                      if (use_json)
+                        {
+                          char buffer[BUFSIZ];
+                          if (type == RD_TYPE_AS || type == RD_TYPE_AS4)
+                            sprintf (buffer, "%u:%d", rd_as.as, rd_as.val);
+                          else if (type == RD_TYPE_IP)
+                            sprintf (buffer, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
+                          json_object_string_add(json_routes, "routeDistinguisher", buffer);
+                        }
+                      else
+                        {
+                          vty_out (vty, "Route Distinguisher: ");
+
+                          if (type == RD_TYPE_AS || type == RD_TYPE_AS4)
+                            vty_out (vty, "%u:%d", rd_as.as, rd_as.val);
+                          else if (type == RD_TYPE_IP)
+                            vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
+#if ENABLE_BGP_VNC
+                          else if (type == RD_TYPE_VNC_ETH)
+                            vty_out (vty, "%u:%02x:%02x:%02x:%02x:%02x:%02x", 
+                                     rd_vnc_eth.local_nve_id, 
+                                     rd_vnc_eth.macaddr.octet[0],
+                                     rd_vnc_eth.macaddr.octet[1],
+                                     rd_vnc_eth.macaddr.octet[2],
+                                     rd_vnc_eth.macaddr.octet[3],
+                                     rd_vnc_eth.macaddr.octet[4],
+                                     rd_vnc_eth.macaddr.octet[5]);
+#endif
+
+                          vty_out (vty, "%s", VTY_NEWLINE);
+                        }
+                      rd_header = 0;
+                    }
+                  route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN, use_json, json_array);
+                }
+            }
+          if (use_json)
+            {
+              struct prefix *p;
+              char buf_a[BUFSIZ];
+              char buf_b[BUFSIZ];
+              p = &rm->p;
+              sprintf(buf_a, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf_b, BUFSIZ), p->prefixlen);
+              json_object_object_add(json_routes, buf_a, json_array);
+            }
+        }
+    }
+  if (use_json)
+    {
+      json_object_object_add(json, "routes", json_routes);
+      vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+      json_object_free(json);
+    }
+  return CMD_SUCCESS;
+}
+
diff --git a/bgpd/bgp_vpn.h b/bgpd/bgp_vpn.h
new file mode 100644 (file)
index 0000000..a16914b
--- /dev/null
@@ -0,0 +1,30 @@
+/* VPN common functions to MP-BGP
+   Copyright (C) 2017 6WIND
+
+This file is part of Free Range Routing.
+
+Free Range Routing is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Free Range Routing is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Free Range Routing; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#ifndef _FRR_BGP_VPN_H
+#define _FRR_BGP_VPN_H
+
+#include <zebra.h>
+
+extern int
+show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd,
+                    afi_t afi, safi_t safi, u_char use_json);
+
+#endif /* _QUAGGA_BGP_VPN_H */
index b4425297b3645e57ee737dc90c5bb233c07a1f07..34c7691c265c316c3f452b5d503b5de0a18eda5b 100644 (file)
@@ -74,6 +74,9 @@ bgp_node_afi (struct vty *vty)
     case BGP_ENCAPV6_NODE:
       afi = AFI_IP6;
       break;
+    case BGP_EVPN_NODE:
+      afi = AFI_L2VPN;
+      break;
     default:
       afi = AFI_IP;
       break;
@@ -101,6 +104,9 @@ bgp_node_safi (struct vty *vty)
     case BGP_IPV6M_NODE:
       safi = SAFI_MULTICAST;
       break;
+    case BGP_EVPN_NODE:
+      safi = SAFI_EVPN;
+      break;
     default:
       safi = SAFI_UNICAST;
       break;
@@ -119,6 +125,9 @@ bgp_vty_afi_from_arg(const char *afi_str)
   else if (!strcmp(afi_str, "ipv6")) {
     afi = AFI_IP6;
   }
+  else if (!strcmp(afi_str, "l2vpn")) {
+    afi = AFI_L2VPN;
+  }
   return afi;
 }
 
@@ -195,14 +204,20 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t
       if (safi)
         *safi = SAFI_ENCAP;
     }
+  else if (argv_find (argv, argc, "evpn", index))
+    {
+      ret = 1;
+      if (safi)
+        *safi = SAFI_EVPN;
+    }
   return ret;
 }
 
 /*
- * bgp_vty_find_and_parse_afi_safi_vrf
+ * bgp_vty_find_and_parse_afi_safi_bgp
  *
- * For a given 'show ...' command, correctly parse the afi/safi/vrf out from it
- * This function *assumes* that the calling function pre-sets the afi/safi/vrf
+ * For a given 'show ...' command, correctly parse the afi/safi/bgp out from it
+ * This function *assumes* that the calling function pre-sets the afi/safi/bgp
  * to appropriate values for the calling function.  This is to allow the
  * calling function to make decisions appropriate for the show command
  * that is being parsed.
@@ -223,7 +238,7 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t
  * idx  -> The current place in the command, generally should be 0 for this function
  * afi  -> The parsed afi if it was included in the show command, returned here
  * safi -> The parsed safi if it was included in the show command, returned here
- * vrf  -> The parsed vrf id if it was included in the show command, returned here
+ * bgp  -> Pointer to the bgp data structure we need to fill in.
  *
  * The function returns the correct location in the parse tree for the
  * last token found.
@@ -232,14 +247,14 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t
  * it found the last token.
  */
 int
-bgp_vty_find_and_parse_afi_safi_vrf (struct vty *vty, struct cmd_token **argv, int argc, int *idx,
-                                     afi_t *afi, safi_t *safi, vrf_id_t *vrf)
+bgp_vty_find_and_parse_afi_safi_bgp (struct vty *vty, struct cmd_token **argv, int argc, int *idx,
+                                     afi_t *afi, safi_t *safi, struct bgp **bgp)
 {
   char *vrf_name = NULL;
 
   assert (afi);
   assert (safi);
-  assert (vrf && *vrf != VRF_UNKNOWN);
+  assert (bgp);
 
   if (argv_find (argv, argc, "ip", idx))
       *afi = AFI_IP;
@@ -248,26 +263,34 @@ bgp_vty_find_and_parse_afi_safi_vrf (struct vty *vty, struct cmd_token **argv, i
     {
       vrf_name = argv[*idx + 1]->arg;
       *idx += 2;
-    }
-
-  if (argv_find_and_parse_afi (argv, argc, idx, afi))
-    argv_find_and_parse_safi (argv, argc, idx, safi);
 
-  if (vrf_name)
-    {
-      if (strmatch(vrf_name, "all"))
-       *vrf = VRF_ALL;
+      if (strmatch (vrf_name, "all"))
+        *bgp = NULL;
       else
-       *vrf = vrf_name_to_id (vrf_name);
+        {
+          *bgp = bgp_lookup_by_name (vrf_name);
+          if (!*bgp)
+            {
+              vty_out (vty, "View/Vrf specified is unknown: %s%s", vrf_name, VTY_NEWLINE);
+              *idx = 0;
+              return 0;
+            }
+        }
     }
-
-  if (*vrf == VRF_UNKNOWN)
+  else
     {
-      vty_out (vty, "View/Vrf specified is unknown: %s", vrf_name);
-      *idx = 0;
-      return 0;
+      *bgp = bgp_get_default ();
+      if (!*bgp)
+        {
+          vty_out (vty, "Unable to find default BGP instance%s", VTY_NEWLINE);
+          *idx = 0;
+          return 0;
+        }
     }
 
+  if (argv_find_and_parse_afi (argv, argc, idx, afi))
+    argv_find_and_parse_safi (argv, argc, idx, safi);
+
   *idx += 1;
   return *idx;
 }
@@ -1129,6 +1152,13 @@ bgp_maxpaths_config_vty (struct vty *vty, int peer_type, const char *mpaths,
   if (set)
   {
     maxpaths = strtol(mpaths, NULL, 10);
+    if (maxpaths > multipath_num)
+      {
+        vty_out (vty,
+                 "%% Maxpaths Specified: %d is > than multipath num specified on bgp command line %d",
+                 maxpaths, multipath_num);
+        return CMD_WARNING;
+      }
     ret = bgp_maximum_paths_set (bgp, afi, safi, peer_type, maxpaths, options);
   }
   else
@@ -5695,6 +5725,18 @@ DEFUN (address_family_encapv6,
   return CMD_SUCCESS;
 }
 
+DEFUN (address_family_evpn,
+       address_family_evpn_cmd,
+       "address-family <l2vpn evpn>",
+       "Enter Address Family command mode\n"
+       "EVPN Address family\n"
+       "Layer2 VPN Address family\n"
+       "Ethernet Virtual Private Network Subsequent Address Family\n")
+{
+  vty->node = BGP_EVPN_NODE;
+  return CMD_SUCCESS;
+}
+
 DEFUN (exit_address_family,
        exit_address_family_cmd,
        "exit-address-family",
@@ -5707,7 +5749,8 @@ DEFUN (exit_address_family,
       || vty->node == BGP_IPV6M_NODE
       || vty->node == BGP_VPNV6_NODE
       || vty->node == BGP_ENCAP_NODE
-      || vty->node == BGP_ENCAPV6_NODE)
+      || vty->node == BGP_ENCAPV6_NODE
+      || vty->node == BGP_EVPN_NODE)
     vty->node = BGP_NODE;
   return CMD_SUCCESS;
 }
@@ -6662,7 +6705,7 @@ bgp_show_summary_afi_safi (struct vty *vty, struct bgp *bgp, int afi, int safi,
         }
       afi++;
       if (! afi_wildcard ||
-          afi == AFI_ETHER)       /* special case, not handled yet */
+          afi == AFI_L2VPN)       /* special case, not handled yet */
         afi = AFI_MAX;
     }
 
@@ -6806,6 +6849,8 @@ afi_safi_print (afi_t afi, safi_t safi)
     return "IPv6 VPN";
   else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
     return "IPv6 Encap";
+  else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
+    return "L2VPN EVPN";
   else
     return "Unknown";
 }
@@ -6829,6 +6874,8 @@ afi_safi_json (afi_t afi, safi_t safi)
     return "IPv6VPN";
   else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
     return "IPv6Encap";
+  else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
+    return "L2VPN EVPN";
   else
     return "Unknown";
 }
@@ -9966,6 +10013,13 @@ static struct cmd_node bgp_encapv6_node =
   1
 };
 
+static struct cmd_node bgp_evpn_node =
+{
+  BGP_EVPN_NODE,
+  "%s(config-router-evpn)# ",
+  1
+};
+
 static void community_list_vty (void);
 
 void
@@ -9981,6 +10035,7 @@ bgp_vty_init (void)
   install_node (&bgp_vpnv6_node, NULL);
   install_node (&bgp_encap_node, NULL);
   install_node (&bgp_encapv6_node, NULL);
+  install_node (&bgp_evpn_node, NULL);
 
   /* Install default VTY commands to new nodes.  */
   install_default (BGP_NODE);
@@ -9992,6 +10047,7 @@ bgp_vty_init (void)
   install_default (BGP_VPNV6_NODE);
   install_default (BGP_ENCAP_NODE);
   install_default (BGP_ENCAPV6_NODE);
+  install_default (BGP_EVPN_NODE);
 
   /* "bgp multiple-instance" commands. */
   install_element (CONFIG_NODE, &bgp_multiple_instance_cmd);
@@ -10205,6 +10261,7 @@ bgp_vty_init (void)
   install_element (BGP_VPNV6_NODE, &neighbor_activate_cmd);
   install_element (BGP_ENCAP_NODE, &neighbor_activate_cmd);
   install_element (BGP_ENCAPV6_NODE, &neighbor_activate_cmd);
+  install_element (BGP_EVPN_NODE, &neighbor_activate_cmd);
 
   /* "no neighbor activate" commands. */
   install_element (BGP_NODE, &no_neighbor_activate_cmd);
@@ -10216,6 +10273,7 @@ bgp_vty_init (void)
   install_element (BGP_VPNV6_NODE, &no_neighbor_activate_cmd);
   install_element (BGP_ENCAP_NODE, &no_neighbor_activate_cmd);
   install_element (BGP_ENCAPV6_NODE, &no_neighbor_activate_cmd);
+  install_element (BGP_EVPN_NODE, &no_neighbor_activate_cmd);
 
   /* "neighbor peer-group" set commands.
    * Long term we should only accept this command under BGP_NODE and not all of
@@ -10286,6 +10344,9 @@ bgp_vty_init (void)
   install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged_cmd);
   install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged_cmd);
 
+  install_element (BGP_EVPN_NODE, &neighbor_attr_unchanged_cmd);
+  install_element (BGP_EVPN_NODE, &no_neighbor_attr_unchanged_cmd);
+
   /* "nexthop-local unchanged" commands */
   install_element (BGP_IPV6_NODE, &neighbor_nexthop_local_unchanged_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_local_unchanged_cmd);
@@ -10828,6 +10889,8 @@ bgp_vty_init (void)
   install_element (BGP_NODE, &address_family_encap_cmd);
   install_element (BGP_NODE, &address_family_encapv6_cmd);
 
+  install_element (BGP_NODE, &address_family_evpn_cmd);
+
   /* "exit-address-family" command. */
   install_element (BGP_IPV4_NODE, &exit_address_family_cmd);
   install_element (BGP_IPV4M_NODE, &exit_address_family_cmd);
@@ -10837,6 +10900,7 @@ bgp_vty_init (void)
   install_element (BGP_VPNV6_NODE, &exit_address_family_cmd);
   install_element (BGP_ENCAP_NODE, &exit_address_family_cmd);
   install_element (BGP_ENCAPV6_NODE, &exit_address_family_cmd);
+  install_element (BGP_EVPN_NODE, &exit_address_family_cmd);
 
   /* "clear ip bgp commands" */
   install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd);
@@ -11044,6 +11108,8 @@ DEFUN (no_ip_community_list_standard_all,
 
   int ret = community_list_unset (bgp_clist, cl_name_or_number, str, direct, style, delete_all);
 
+  XFREE (MTYPE_TMP, str);
+
   if (ret < 0)
     {
       community_list_perror (vty, ret);
@@ -11121,6 +11187,8 @@ DEFUN (no_ip_community_list_expanded_all,
 
   int ret = community_list_unset (bgp_clist, cl_name_or_number, str, direct, style, delete_all);
 
+  XFREE (MTYPE_TMP, str);
+
   if (ret < 0)
     {
       community_list_perror (vty, ret);
index 13e67d112ee1beb73d1c47d5b7de05be9260029e..33d24d530e5db86c8b4438b6a2ff012f9a180efc 100644 (file)
@@ -64,6 +64,6 @@ extern int
 argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, safi_t *safi);
 
 extern int
-bgp_vty_find_and_parse_afi_safi_vrf (struct vty *vty, struct cmd_token **argv, int argc, int *idx,
-                                     afi_t *afi, safi_t *safi, vrf_id_t *vrf);
+bgp_vty_find_and_parse_afi_safi_bgp (struct vty *vty, struct cmd_token **argv, int argc, int *idx,
+                                     afi_t *afi, safi_t *safi, struct bgp **bgp);
 #endif /* _QUAGGA_BGP_VTY_H */
index 822f459c28f873c6ac8dd3cda6112e5e9a98c3de..2a513dda25619c60cc43e18f7bf46e3583c50190 100644 (file)
@@ -69,7 +69,7 @@ struct stream *bgp_ifindices_buf = NULL;
    Number of supported next-hops are finite, use of arrays should be ok. */
 struct attr attr_cp[MULTIPATH_NUM];
 struct attr_extra attr_extra_cp[MULTIPATH_NUM];
-int    attr_index = 0;
+unsigned int attr_index = 0;
 
 /* Once per address-family initialization of the attribute array */
 #define BGP_INFO_ATTR_BUF_INIT()\
@@ -82,7 +82,7 @@ do {\
 #define BGP_INFO_ATTR_BUF_COPY(info_src, info_dst)\
 do { \
   *info_dst = *info_src; \
-  assert(attr_index != MULTIPATH_NUM);\
+  assert(attr_index != multipath_num);\
   attr_cp[attr_index].extra = &attr_extra_cp[attr_index]; \
   bgp_attr_dup (&attr_cp[attr_index], info_src->attr); \
   bgp_attr_deep_dup (&attr_cp[attr_index], info_src->attr); \
index fc6968e9d9a4ce103d9d14740a04d4ab7665e259..5592749b286217ed0054a7b7e05794fe109c2be9 100644 (file)
@@ -66,6 +66,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
 #include "bgpd/rfapi/rfapi_backend.h"
 #endif
+#include "bgpd/bgp_evpn.h"
 #include "bgpd/bgp_advertise.h"
 #include "bgpd/bgp_network.h"
 #include "bgpd/bgp_vty.h"
@@ -77,6 +78,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_updgrp.h"
 #include "bgpd/bgp_bfd.h"
 #include "bgpd/bgp_memory.h"
+#include "bgpd/bgp_evpn_vty.h"
 
 DEFINE_QOBJ_TYPE(bgp_master)
 DEFINE_QOBJ_TYPE(bgp)
@@ -91,6 +93,8 @@ struct bgp_master *bm;
 /* BGP community-list.  */
 struct community_list_handler *bgp_clist;
 
+unsigned int multipath_num = MULTIPATH_NUM;
+
 static void bgp_if_init (struct bgp *bgp);
 static void bgp_if_finish (struct bgp *bgp);
 
@@ -1643,6 +1647,8 @@ peer_as_change (struct peer *peer, as_t as, int as_specified)
                  PEER_FLAG_REFLECTOR_CLIENT);
       UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_ENCAP],
                  PEER_FLAG_REFLECTOR_CLIENT);
+      UNSET_FLAG (peer->af_flags[AFI_L2VPN][SAFI_EVPN],
+                 PEER_FLAG_REFLECTOR_CLIENT);
     }
 
   /* local-as reset */
@@ -2520,7 +2526,7 @@ peer_group_delete (struct peer_group *group)
       list_delete (group->listen_range[afi]);
     }
 
-  XFREE(MTYPE_BGP_PEER_HOST, group->name);
+  XFREE(MTYPE_PEER_GROUP_HOST, group->name);
   group->name = NULL;
 
   group->conf->group = NULL;
@@ -2914,8 +2920,8 @@ bgp_create (as_t *as, const char *name, enum bgp_instance_type inst_type)
        bgp->rib[afi][safi] = bgp_table_init (afi, safi);
 
         /* Enable maximum-paths */
-        bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_EBGP, MULTIPATH_NUM, 0);
-        bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_IBGP, MULTIPATH_NUM, 0);
+        bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_EBGP, multipath_num, 0);
+        bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_IBGP, multipath_num, 0);
       }
 
   bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
@@ -5454,7 +5460,7 @@ peer_prefix_list_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
       if (gfilter->plist[direct].name)
        {
          if (filter->plist[direct].name)
-           XSTRDUP(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
+           XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
          filter->plist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->plist[direct].name);
          filter->plist[direct].plist = gfilter->plist[direct].plist;
           peer_on_policy_change(peer, afi, safi,
@@ -7217,7 +7223,11 @@ bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi,
       else if (safi == SAFI_ENCAP)
         vty_out (vty, "ipv6 encap");
     }
-
+  else if (afi == AFI_L2VPN)
+    {
+      if (safi == SAFI_EVPN)
+       vty_out (vty, "l2vpn evpn");
+    }
   vty_out (vty, "%s", VTY_NEWLINE);
 
   *write = 1;
@@ -7518,6 +7528,9 @@ bgp_config_write (struct vty *vty)
       /* ENCAPv6 configuration.  */
       write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_ENCAP);
 
+      /* EVPN configuration.  */
+      write += bgp_config_write_family (vty, bgp, AFI_L2VPN, SAFI_EVPN);
+
 #if ENABLE_BGP_VNC
       write += bgp_rfapi_cfg_write(vty, bgp);
 #endif
@@ -7615,6 +7628,7 @@ bgp_init (void)
 #if ENABLE_BGP_VNC
   rfapi_init ();
 #endif
+  bgp_ethernetvpn_init ();
 
   /* Access list initialize. */
   access_list_init ();
index 2eef04e1d1ae511328910be868ff167d0f95ec7e..f0f2ed87bdc79e8c6fddf9a354ae70653f7e6baa 100644 (file)
@@ -73,6 +73,7 @@ enum bgp_af_index
   BGP_AF_IPV6_VPN,
   BGP_AF_IPV4_ENCAP,
   BGP_AF_IPV6_ENCAP,
+  BGP_AF_L2VPN_EVPN,
   BGP_AF_MAX
 };
 
@@ -1160,6 +1161,7 @@ typedef enum
 } bgp_policy_type_e;
 
 extern struct bgp_master *bm;
+extern unsigned int multipath_num;
 
 /* Prototypes. */
 extern void bgp_terminate (void);
@@ -1414,6 +1416,16 @@ afindex (afi_t afi, safi_t safi)
          break;
        }
       break;
+    case AFI_L2VPN:
+      switch (safi)
+        {
+        case SAFI_EVPN:
+          return BGP_AF_L2VPN_EVPN;
+          break;
+        default:
+          return BGP_AF_MAX;
+          break;
+        }
     default:
       return BGP_AF_MAX;
       break;
index 50693659b60d0f2fb881211177a5fb7993458586..71086c875871882468e162e88dd2dba88fdb4ee5 100644 (file)
@@ -4352,7 +4352,7 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
             ecommunity_cmp (rfg->rt_import_list, rfg->rt_export_list))
           {
             char *b = ecommunity_ecom2str (rfg->rt_import_list,
-                                           ECOMMUNITY_FORMAT_ROUTE_MAP);
+                                           ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
             vty_out (vty, "  rt both %s%s", b, VTY_NEWLINE);
             XFREE (MTYPE_ECOMMUNITY_STR, b);
           }
@@ -4361,14 +4361,14 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
             if (rfg->rt_import_list)
               {
                 char *b = ecommunity_ecom2str (rfg->rt_import_list,
-                                               ECOMMUNITY_FORMAT_ROUTE_MAP);
+                                               ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
                 vty_out (vty, "  rt import %s%s", b, VTY_NEWLINE);
                 XFREE (MTYPE_ECOMMUNITY_STR, b);
               }
             if (rfg->rt_export_list)
               {
                 char *b = ecommunity_ecom2str (rfg->rt_export_list,
-                                               ECOMMUNITY_FORMAT_ROUTE_MAP);
+                                               ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
                 vty_out (vty, "  rt export %s%s", b, VTY_NEWLINE);
                 XFREE (MTYPE_ECOMMUNITY_STR, b);
               }
@@ -4483,7 +4483,7 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
                 ecommunity_cmp (rfg->rt_import_list, rfg->rt_export_list))
               {
                 char *b = ecommunity_ecom2str (rfg->rt_import_list,
-                                               ECOMMUNITY_FORMAT_ROUTE_MAP);
+                                               ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
                 vty_out (vty, "   rt both %s%s", b, VTY_NEWLINE);
                 XFREE (MTYPE_ECOMMUNITY_STR, b);
               }
@@ -4492,14 +4492,14 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
                 if (rfg->rt_import_list)
                   {
                     char *b = ecommunity_ecom2str (rfg->rt_import_list,
-                                                   ECOMMUNITY_FORMAT_ROUTE_MAP);
+                                                   ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
                     vty_out (vty, "  rt import %s%s", b, VTY_NEWLINE);
                     XFREE (MTYPE_ECOMMUNITY_STR, b);
                   }
                 if (rfg->rt_export_list)
                   {
                     char *b = ecommunity_ecom2str (rfg->rt_export_list,
-                                                   ECOMMUNITY_FORMAT_ROUTE_MAP);
+                                                   ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
                     vty_out (vty, "  rt export %s%s", b, VTY_NEWLINE);
                     XFREE (MTYPE_ECOMMUNITY_STR, b);
                   }
@@ -4570,7 +4570,7 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
                             hc->default_rt_export_list))
           {
             char *b = ecommunity_ecom2str (hc->default_rt_import_list,
-                                           ECOMMUNITY_FORMAT_ROUTE_MAP);
+                                           ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
             vty_out (vty, "  rt both %s%s", b, VTY_NEWLINE);
             XFREE (MTYPE_ECOMMUNITY_STR, b);
           }
@@ -4579,14 +4579,14 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
             if (hc->default_rt_import_list)
               {
                 char *b = ecommunity_ecom2str (hc->default_rt_import_list,
-                                               ECOMMUNITY_FORMAT_ROUTE_MAP);
+                                               ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
                 vty_out (vty, "  rt import %s%s", b, VTY_NEWLINE);
                 XFREE (MTYPE_ECOMMUNITY_STR, b);
               }
             if (hc->default_rt_export_list)
               {
                 char *b = ecommunity_ecom2str (hc->default_rt_export_list,
-                                               ECOMMUNITY_FORMAT_ROUTE_MAP);
+                                               ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
                 vty_out (vty, "  rt export %s%s", b, VTY_NEWLINE);
                 XFREE (MTYPE_ECOMMUNITY_STR, b);
               }
@@ -4685,7 +4685,8 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
             ecommunity_cmp (rfg->rt_import_list, rfg->rt_export_list))
           {
             char *b = ecommunity_ecom2str (rfg->rt_import_list,
-                                           ECOMMUNITY_FORMAT_ROUTE_MAP);
+                                           ECOMMUNITY_FORMAT_ROUTE_MAP,
+                                           ECOMMUNITY_ROUTE_TARGET);
             vty_out (vty, "  rt both %s%s", b, VTY_NEWLINE);
             XFREE (MTYPE_ECOMMUNITY_STR, b);
           }
@@ -4694,14 +4695,15 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
             if (rfg->rt_import_list)
               {
                 char *b = ecommunity_ecom2str (rfg->rt_import_list,
-                                               ECOMMUNITY_FORMAT_ROUTE_MAP);
+                                               ECOMMUNITY_FORMAT_ROUTE_MAP,
+                                               ECOMMUNITY_ROUTE_TARGET);
                 vty_out (vty, "  rt import %s%s", b, VTY_NEWLINE);
                 XFREE (MTYPE_ECOMMUNITY_STR, b);
               }
             if (rfg->rt_export_list)
               {
                 char *b = ecommunity_ecom2str (rfg->rt_export_list,
-                                               ECOMMUNITY_FORMAT_ROUTE_MAP);
+                                               ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
                 vty_out (vty, "  rt export %s%s", b, VTY_NEWLINE);
                 XFREE (MTYPE_ECOMMUNITY_STR, b);
               }
index 3cf09e240e67430f8bcde79ebaa66d276297fafb..99d26cf13c87178dabcae8cadec5b406204776e5 100644 (file)
@@ -1451,7 +1451,7 @@ rfapi_open_inner (
 #define RFD_RTINIT(rh, ary) do {\
     RFD_RTINIT_AFI(rh, ary, AFI_IP);\
     RFD_RTINIT_AFI(rh, ary, AFI_IP6);\
-    RFD_RTINIT_AFI(rh, ary, AFI_ETHER);\
+    RFD_RTINIT_AFI(rh, ary, AFI_L2VPN);\
 } while(0)
 
   RFD_RTINIT(rfd, rfd->rib);
@@ -1733,7 +1733,7 @@ rfapi_query_inner (
                 __func__, rfd, buf, ppNextHopEntry);
 
     s = ecommunity_ecom2str(rfd->import_table->rt_import_list,
-        ECOMMUNITY_FORMAT_ROUTE_MAP);
+                            ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
     vnc_zlog_debug_verbose("%s rfd->import_table=%p, rfd->import_table->rt_import_list: %s",
         __func__, rfd->import_table, s); XFREE (MTYPE_ECOMMUNITY_STR, s);
   }
@@ -3809,7 +3809,7 @@ DEFUN (debug_rfapi_show_import,
   for (it = h->imports; it; it = it->next)
     {
       s = ecommunity_ecom2str (it->rt_import_list,
-                               ECOMMUNITY_FORMAT_ROUTE_MAP);
+                               ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
       vty_out (vty, "Import Table %p, RTs: %s%s", it, s, VTY_NEWLINE);
       XFREE (MTYPE_ECOMMUNITY_STR, s);
 
@@ -3835,7 +3835,7 @@ DEFUN (debug_rfapi_show_import,
                           &cursor))
         {
 
-          if (it->imported_vpn[AFI_ETHER])
+          if (it->imported_vpn[AFI_L2VPN])
             {
               lni = lni_as_ptr;
               if (first_l2)
@@ -3845,7 +3845,7 @@ DEFUN (debug_rfapi_show_import,
                   first_l2 = 0;
                 }
               snprintf (buf, BUFSIZ, "L2VPN LNI=%u", lni);
-              rfapiShowImportTable (vty, buf, it->imported_vpn[AFI_ETHER], 1);
+              rfapiShowImportTable (vty, buf, it->imported_vpn[AFI_L2VPN], 1);
             }
         }
     }
index 9ae3311e15f77312a68b0cbb060b37d0a4f6ea2c..4a05018d2358062e617f6e06ca33f1024a0d57a2 100644 (file)
@@ -1091,8 +1091,8 @@ rfapiEcommunitiesIntersect (struct ecommunity *e1, struct ecommunity *e2)
 
   {
     char *s1, *s2;
-    s1 = ecommunity_ecom2str (e1, ECOMMUNITY_FORMAT_DISPLAY);
-    s2 = ecommunity_ecom2str (e2, ECOMMUNITY_FORMAT_DISPLAY);
+    s1 = ecommunity_ecom2str (e1, ECOMMUNITY_FORMAT_DISPLAY, 0);
+    s2 = ecommunity_ecom2str (e2, ECOMMUNITY_FORMAT_DISPLAY, 0);
     vnc_zlog_debug_verbose ("%s: e1[%s], e2[%s]", __func__, s1, s2);
     XFREE (MTYPE_ECOMMUNITY_STR, s1);
     XFREE (MTYPE_ECOMMUNITY_STR, s2);
@@ -2077,7 +2077,7 @@ rfapiEthRouteTable2NextHopList (
 
 
   it = rfapiMacImportTableGet (bgp, logical_net_id);
-  rt = it->imported_vpn[AFI_ETHER];
+  rt = it->imported_vpn[AFI_L2VPN];
 
   for (rn = route_top (rt); rn; rn = route_next (rn))
     {
@@ -3607,7 +3607,7 @@ rfapiBgpInfoFilteredImportVPN (
   struct peer                  *peer,
   void                         *rfd,           /* set for looped back routes */
   struct prefix                        *p,
-  struct prefix                        *aux_prefix,    /* AFI_ETHER: optional IP */
+  struct prefix                        *aux_prefix,    /* AFI_L2VPN: optional IP */
   afi_t                                afi,
   struct prefix_rd             *prd,
   struct attr                  *attr,          /* part of bgp_info */
@@ -3702,7 +3702,7 @@ rfapiBgpInfoFilteredImportVPN (
     {
     case AFI_IP:
     case AFI_IP6:
-    case AFI_ETHER:
+    case AFI_L2VPN:
       rt = import_table->imported_vpn[afi];
       break;
 
@@ -3909,7 +3909,7 @@ rfapiBgpInfoFilteredImportVPN (
    * For ethernet routes, if there is an accompanying IP address,
    * save it in the bi
    */
-  if ((AFI_ETHER == afi) && aux_prefix)
+  if ((AFI_L2VPN == afi) && aux_prefix)
     {
 
       vnc_zlog_debug_verbose ("%s: setting BI's aux_prefix", __func__);
@@ -4178,7 +4178,7 @@ rfapiProcessUpdate (
            rfd,
            &pfx_mac_buf,       /* prefix */
            p,                  /* aux prefix: IP addr */
-           AFI_ETHER,
+           AFI_L2VPN,
            prd,
            attr,
            type,
@@ -4291,7 +4291,7 @@ rfapiProcessWithdraw (
 
 #if DEBUG_L2_EXTRA
           vnc_zlog_debug_verbose
-            ("%s: calling rfapiBgpInfoFilteredImportVPN(it=%p, afi=AFI_ETHER)",
+            ("%s: calling rfapiBgpInfoFilteredImportVPN(it=%p, afi=AFI_L2VPN)",
              __func__, it);
 #endif
 
@@ -4302,7 +4302,7 @@ rfapiProcessWithdraw (
            rfd,
            &pfx_mac_buf,       /* prefix */
            p,                  /* aux_prefix: IP */
-           AFI_ETHER,
+           AFI_L2VPN,
            prd,
            attr,
            type,
@@ -4808,7 +4808,7 @@ rfapiDeleteRemotePrefixesIt (
             vnc_zlog_debug_verbose ("%s: rn pfx=%s", __func__, buf_pfx);
           }
 
-          /* TBD is this valid for afi == AFI_ETHER? */
+          /* TBD is this valid for afi == AFI_L2VPN? */
           RFAPI_CHECK_REFCOUNT (rn, SAFI_MPLS_VPN, 1);
 
           for (bi = rn->info; bi; bi = next)
@@ -5166,10 +5166,10 @@ rfapiCountAllItRoutes (int *pALRcount,  /* active local routes */
            rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor))
         {
 
-          total_active_local += it->local_count[AFI_ETHER];
-          total_active_remote += it->remote_count[AFI_ETHER];
-          total_holddown += it->holddown_count[AFI_ETHER];
-          total_imported += it->imported_count[AFI_ETHER];
+          total_active_local += it->local_count[AFI_L2VPN];
+          total_active_remote += it->remote_count[AFI_L2VPN];
+          total_holddown += it->holddown_count[AFI_L2VPN];
+          total_imported += it->imported_count[AFI_L2VPN];
 
         }
     }
index c051b9b3e044eef8955039ffbdb69bbbd72c72ce..a9e6e4f934f386d4048d82305758b21d345710f8 100644 (file)
@@ -941,7 +941,7 @@ rfapiMonitorItNodeChanged (
               __func__, import_table, it_node, buf_prefix);
 #endif
 
-  if (AFI_ETHER == afi)
+  if (AFI_L2VPN == afi)
     {
       struct rfapi_monitor_eth *m;
       struct skiplist *sl;
@@ -1044,7 +1044,7 @@ rfapiMonitorItNodeChanged (
   /*
    * All-routes L2 monitors
    */
-  if (AFI_ETHER == afi)
+  if (AFI_L2VPN == afi)
     {
       struct rfapi_monitor_eth *e;
 
@@ -1305,7 +1305,7 @@ rfapiMonitorEthAttachImportHd (struct bgp *bgp, struct rfapi_descriptor *rfd)
       pfx_mac_buf.prefixlen = 48;
       pfx_mac_buf.u.prefix_eth = mon->macaddr;
 
-      rn = route_node_get (it->imported_vpn[AFI_ETHER], &pfx_mac_buf);
+      rn = route_node_get (it->imported_vpn[AFI_L2VPN], &pfx_mac_buf);
       assert (rn);
 
       (void) rfapiMonitorEthAttachImport (it, rn, mon);
@@ -1361,7 +1361,7 @@ rfapiMonitorEthDetachImport (
   pfx_mac_buf.prefixlen = 48;
   pfx_mac_buf.u.prefix_eth = mon->macaddr;
 
-  rn = route_node_get (it->imported_vpn[AFI_ETHER], &pfx_mac_buf);
+  rn = route_node_get (it->imported_vpn[AFI_L2VPN], &pfx_mac_buf);
   assert (rn);
 
 #if DEBUG_L2_EXTRA
@@ -1423,7 +1423,7 @@ rfapiMonitorEthAdd (
 
   if (!RFAPI_0_ETHERADDR (macaddr))
     {
-      rn = route_node_get (it->imported_vpn[AFI_ETHER], &pfx_mac_buf);
+      rn = route_node_get (it->imported_vpn[AFI_L2VPN], &pfx_mac_buf);
       assert (rn);
     }
 
@@ -1635,7 +1635,7 @@ rfapiMonitorCallbacksOff (struct bgp *bgp)
       /*
        * The actual route table
        */
-      rt = it->imported_vpn[AFI_ETHER];
+      rt = it->imported_vpn[AFI_L2VPN];
 
       /* 
        * Find non-0 monitors (i.e., actual addresses, not FTD monitors)
index 8ac2966bfeccee2de75e010193b1d6625573789c..a5e39705495ef3fc9005caca51991e35d42a0ed3 100644 (file)
@@ -133,7 +133,7 @@ struct rfapi_descriptor
   uint32_t                     flags;
 #define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_IP                0x00000001
 #define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_IP6       0x00000002
-#define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_ETHER     0x00000004
+#define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_L2VPN     0x00000004
 #define RFAPI_HD_FLAG_PROVISIONAL                      0x00000008
 #define RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY         0x00000010
 #define RFAPI_HD_FLAG_IS_VRF                           0x00000012
@@ -142,7 +142,7 @@ struct rfapi_descriptor
 #define RFAPI_QUEUED_FLAG(afi) (                                       \
     ((afi) == AFI_IP)? RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_IP:        \
     (((afi) == AFI_IP6)? RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_IP6:     \
-    (((afi) == AFI_ETHER)? RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_ETHER: \
+    (((afi) == AFI_L2VPN)? RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_L2VPN: \
     (assert(0), 0) )))
 
 
index 8e5d47415f00ceb4709de4bc66fd5b2dcde0f7b4..d633023dcf86e26cc60270569ef68a8a16b3d745 100644 (file)
@@ -916,7 +916,7 @@ process_pending_node (
   vnc_zlog_debug_verbose ("%s: afi=%d, %s pn->info=%p",
               __func__, afi, buf_prefix, pn->info);
 
-  if (AFI_ETHER != afi)
+  if (AFI_L2VPN != afi)
     {
       rfapiQprefix2Rprefix (&pn->p, &hp);
     }
@@ -1246,7 +1246,7 @@ callback:
           else
             {
               new->prefix = hp;
-              if (AFI_ETHER == afi)
+              if (AFI_L2VPN == afi)
                 {
                   /* hp is 0; need to set length to match AF of vn */
                   new->prefix.length =
@@ -1334,7 +1334,7 @@ callback:
               else
                 {
                   new->prefix = hp;
-                  if (AFI_ETHER == afi)
+                  if (AFI_L2VPN == afi)
                     {
                       /* hp is 0; need to set length to match AF of vn */
                       new->prefix.length =
@@ -1976,7 +1976,7 @@ rfapiRibPreload (
               continue;
             }
 
-          afi = AFI_ETHER;
+          afi = AFI_L2VPN;
           rfapiL2o2Qprefix (pL2o, &pfx);
         }
       else
@@ -2181,7 +2181,7 @@ rfapiRibPendingDeleteRoute (
   vnc_zlog_debug_verbose ("%s: entry, it=%p, afi=%d, it_node=%p, pfx=%s",
               __func__, it, afi, it_node, buf);
 
-  if (AFI_ETHER == afi)
+  if (AFI_L2VPN == afi)
     {
       /*
        * ethernet import tables are per-LNI and each ethernet monitor 
index 8ddb724f52aa3702760bad8ac5d81263a1f15787..1f3066b5c5c664084a469147237dc5ec66501ece 100644 (file)
@@ -472,7 +472,7 @@ rfapi_vty_out_vncinfo (
   if (bi->attr && bi->attr->extra && bi->attr->extra->ecommunity)
     {
       s = ecommunity_ecom2str (bi->attr->extra->ecommunity,
-                               ECOMMUNITY_FORMAT_ROUTE_MAP);
+                               ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
       vty_out (vty, " EC{%s}", s);
       XFREE (MTYPE_ECOMMUNITY_STR, s);
     }
@@ -676,7 +676,7 @@ rfapiPrintBi (void *stream, struct bgp_info *bi)
       if (bi->attr->extra->ecommunity)
         {
           s = ecommunity_ecom2str (bi->attr->extra->ecommunity,
-                                   ECOMMUNITY_FORMAT_ROUTE_MAP);
+                                   ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
           r = snprintf (p, REMAIN, " %s", s);
           INCP;
           XFREE (MTYPE_ECOMMUNITY_STR, s);
@@ -1329,7 +1329,7 @@ rfapiShowRemoteRegistrationsIt (
   int                          show_local,
   int                          show_remote,
   int                          show_imported,  /* either/or */
-  uint32_t                     *pLni)          /* AFI_ETHER only */
+  uint32_t                     *pLni)          /* AFI_L2VPN only */
 {
   afi_t afi;
   int printed_rtlist_hdr = 0;
@@ -1433,7 +1433,7 @@ rfapiShowRemoteRegistrationsIt (
                     }
 
                   s = ecommunity_ecom2str (it->rt_import_list,
-                                           ECOMMUNITY_FORMAT_ROUTE_MAP);
+                                           ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
 
                   if (pLni)
                     {
@@ -1807,7 +1807,7 @@ rfapiPrintDescriptor (struct vty *vty, struct rfapi_descriptor *rfd)
     {
       s =
         ecommunity_ecom2str (rfd->rt_export_list,
-                             ECOMMUNITY_FORMAT_ROUTE_MAP);
+                             ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
       vty_out (vty, " Export %s%s", s, HVTY_NEWLINE);
       XFREE (MTYPE_ECOMMUNITY_STR, s);
     }
@@ -1820,7 +1820,7 @@ rfapiPrintDescriptor (struct vty *vty, struct rfapi_descriptor *rfd)
   if (rfd->import_table)
     {
       s = ecommunity_ecom2str (rfd->import_table->rt_import_list,
-                               ECOMMUNITY_FORMAT_ROUTE_MAP);
+                               ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
       vty_out (vty, " Import %s%s", s, HVTY_NEWLINE);
       XFREE (MTYPE_ECOMMUNITY_STR, s);
     }
index f20e9ed67455e6bde500c63aea792d45c73f8dfe..9b2dc2582394c17fd099c93b7a628d576aebc643 100644 (file)
@@ -340,7 +340,7 @@ vnc_direct_bgp_add_route_ce (
               iattr,      /* bgp_update copies this attr */
               afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL,  /* RD not used for unicast */
               NULL,             /* tag not used for unicast */
-              0);
+              0, NULL);         /* EVPN not used */
   bgp_attr_unintern (&iattr);
 }
 
@@ -425,7 +425,7 @@ vnc_direct_bgp_del_route_ce (
                 0,                /* addpath_id */
                 NULL, /* attr, ignored */
                 afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL,        /* RD not used for unicast */
-                NULL);          /* tag not used for unicast */
+                NULL, NULL);          /* tag not used for unicast */
 
 }
 
@@ -534,7 +534,7 @@ vnc_direct_bgp_vpn_disable_ce (struct bgp *bgp, afi_t afi)
                             0,                /* addpath_id */
                             NULL,       /* ignored */
                             AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
-                            NULL);      /* tag not used for unicast */
+                            NULL, NULL);      /* tag not used for unicast */
             }
         }
     }
@@ -911,7 +911,7 @@ vnc_direct_bgp_add_prefix (
                       iattr,    /* bgp_update copies it */
                       afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL,  /* RD not used for unicast */
                       NULL,     /* tag not used for unicast */
-                      0);
+                      0, NULL); /* EVPN not used */
 
           bgp_attr_unintern (&iattr);
         }
@@ -1011,7 +1011,7 @@ vnc_direct_bgp_del_prefix (
                         0,                /* addpath_id */
                         NULL,   /* attr, ignored */
                         afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL,        /* RD not used for unicast */
-                        NULL);  /* tag not used for unicast */
+                        NULL, NULL);  /* tag not used for unicast */
         }
     }
 }
@@ -1150,7 +1150,7 @@ vnc_direct_bgp_add_nve (struct bgp *bgp, struct rfapi_descriptor *rfd)
                               iattr,    /* bgp_update copies it */
                               afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL,  /* RD not used for unicast */
                               NULL,     /* tag not used for unicast */
-                              0);
+                              0, NULL); /* EVPN not used */
 
                   bgp_attr_unintern (&iattr);
 
@@ -1250,7 +1250,7 @@ vnc_direct_bgp_del_nve (struct bgp *bgp, struct rfapi_descriptor *rfd)
                                 0,                      /* addpath_id */
                                 NULL,   /* attr, ignored */
                                 afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL,        /* RD not used for unicast */
-                                NULL);  /* tag not used for unicast */
+                                NULL, NULL);  /* tag not used for unicast */
 
                 }
             }
@@ -1377,7 +1377,7 @@ vnc_direct_bgp_add_group_afi (
                           iattr,        /* bgp_update copies it */
                           afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL,      /* RD not used for unicast */
                           NULL, /* tag not used for unicast */
-                          0);
+                          0, NULL); /* EVPN not used */
 
               bgp_attr_unintern (&iattr);
             }
@@ -1462,7 +1462,7 @@ vnc_direct_bgp_del_group_afi (
                             0,                  /* addpath_id */
                             NULL,       /* attr, ignored */
                             afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL,    /* RD not used for unicast */
-                            NULL);      /* tag not used for unicast */
+                            NULL, NULL);      /* tag not used for unicast */
 
             }
         }
@@ -1540,7 +1540,7 @@ vnc_direct_bgp_unexport_table (
                                 0,                      /* addpath_id */
                                 NULL,   /* attr, ignored */
                                 afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL,        /* RD not used for unicast */
-                                NULL);  /* tag not used for unicast */
+                                NULL, NULL);  /* tag not used for unicast, EVPN neither */
 
                 }
             }
@@ -1777,8 +1777,8 @@ vnc_direct_bgp_rh_add_route (
               0,                /* addpath_id */
               iattr,            /* bgp_update copies this attr */
               afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE, NULL,       /* RD not used for unicast */
-              NULL,             /* tag not used for unicast */
-              0);
+              NULL,             /* tag not used for unicast, EVPN neither */
+              0, NULL);         /* EVPN not used */
   bgp_attr_unintern (&iattr);
 
 }
@@ -1801,7 +1801,7 @@ vncExportWithdrawTimer (struct thread *t)
     eti->type,
     eti->subtype,
     NULL,                              /* RD not used for unicast */
-    NULL);                             /* tag not used for unicast */
+    NULL, NULL);                       /* tag not used for unicast, EVPN neither */
 
   /*
    * Free the eti
@@ -2019,8 +2019,8 @@ vnc_direct_bgp_rh_vpn_enable (struct bgp *bgp, afi_t afi)
                               0,                /* addpath_id */
                               iattr,    /* bgp_update copies it */
                               AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE, NULL,    /* RD not used for unicast */
-                              NULL,     /* tag not used for unicast */
-                              0);
+                              NULL,     /* tag not used for unicast, EVPN neither */
+                              0, NULL); /* EVPN not used */
                   bgp_attr_unintern (&iattr);
                 }
             }
@@ -2085,7 +2085,7 @@ vnc_direct_bgp_rh_vpn_disable (struct bgp *bgp, afi_t afi)
                             0,                  /* addpath_id */
                             NULL,       /* ignored */
                             AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE, NULL,      /* RD not used for unicast */
-                            NULL);      /* tag not used for unicast */
+                            NULL, NULL);      /* tag not used for unicast, EVPN neither */
             }
         }
     }
index 23b6e9dbb48856d1017f8ea640362e3fc897965b..84b299ce1d120d9e224d2d8c0730a24f69154d18 100644 (file)
@@ -547,6 +547,7 @@ vnc_zebra_route_msg (
       api.nexthop = nhp_ary;
       api.ifindex_num = 0;
       api.instance = 0;
+      api.safi = SAFI_UNICAST;
 
       if (BGP_DEBUG (zebra, ZEBRA))
         {
@@ -582,6 +583,7 @@ vnc_zebra_route_msg (
       api.ifindex_num = 1;
       api.ifindex = &ifindex;
       api.instance = 0;
+      api.safi = SAFI_UNICAST;
 
       if (BGP_DEBUG (zebra, ZEBRA))
         {
index 1436b2fc7c56ccf9f77f869ac49bd238b9f38fab..b1d9a1b69116574493a8987a90a84a81b4d9cc78 100755 (executable)
@@ -1651,14 +1651,6 @@ AC_SUBST(CFG_SYSCONF)
 AC_SUBST(CFG_SBIN)
 AC_SUBST(CFG_STATE)
 
-dnl -------------------------------
-dnl Quagga sources should always be 
-dnl current wrt interfaces. Dont
-dnl allow deprecated interfaces to
-dnl be exposed.
-dnl -------------------------------
-AC_DEFINE(QUAGGA_NO_DEPRECATED_INTERFACES, 1, Hide deprecated interfaces)
-
 dnl ---------------------------
 dnl Check htonl works correctly
 dnl ---------------------------
index cf03cd9de1d1cb771d441e1f123deba81fd6cc52..91e2a0f5b681f99174a59727003f5f58778132ff 100644 (file)
@@ -28,4 +28,5 @@ ospf6d=no
 ripd=no
 ripngd=no
 isisd=no
-
+pimd=no
+ldpd=no
index 8f3e1c1db687226f1365ca0c5f65e8e7254b7a1f..a4945f39ae7bf8687a1f1ebc7a5f2e7897f79cfc 100644 (file)
@@ -12,6 +12,7 @@ ripd_options="   --daemon -A 127.0.0.1"
 ripngd_options=" --daemon -A ::1"
 isisd_options="  --daemon -A 127.0.0.1"
 pimd_options="  --daemon -A 127.0.0.1"
+ldpd_options="  --daemon -A 127.0.0.1"
 
 # The list of daemons to watch is automatically generated by the init script.
 watchfrr_enable=yes
index 893c1decaae5dcb9cf8f0e20c6a4d495189a7df8..caded52075820c61dcc6f62db9802b3501cfd214 100644 (file)
@@ -93,5 +93,5 @@ See message #4525 from 2005-05-09 in the quagga-users mailing list.
 ===========================
 
 Check /etc/pam.d/frr, it probably denies access to your user. The passwords
-configured in /etc/frr/Frr.conf are only for telnet access.
+configured in /etc/frr/frr.conf are only for telnet access.
 
index abdaa7277b6bd7ce1cd385b14d9d1232e2b3178e..29162e3b56a92bab011cf527d0ed0d29a35280b7 100644 (file)
@@ -66,7 +66,7 @@ if [ "$1" = "install" ]; then
     fi
 
     # Exceptions for vtysh.
-    f=$d/Frr.conf
+    f=$d/frr.conf
     if [ -f $d/Zebra.conf ]; then
       mv $d/Zebra.conf $f
     fi
diff --git a/doc/Building_FRR_on_CentOS6.md b/doc/Building_FRR_on_CentOS6.md
new file mode 100644 (file)
index 0000000..ccb07fb
--- /dev/null
@@ -0,0 +1,160 @@
+Building FRR on CentOS 6 from Git Source
+========================================
+
+Instructions are tested with `CentOS 6.8` on `x86_64` platform
+
+CentOS 6 restrictions:
+----------------------
+
+- PIMd is not supported on `CentOS 6`. Upgrade to `CentOS 7` if PIMd is 
+  needed
+- MPLS is not supported on `CentOS 6`. MPLS requires Linux Kernel 4.5 or 
+  higher (LDP can be built, but may have limited use without MPLS)
+
+Install required packages
+-------------------------
+
+Add packages:
+
+    sudo yum install git autoconf automake libtool make gawk readline-devel \
+      texinfo net-snmp-devel groff pkgconfig json-c-devel pam-devel \
+      flex pytest
+
+Install newer version of bison (CentOS 6 package source is too old) from 
+CentOS 7
+
+    curl -O http://vault.centos.org/7.0.1406/os/Source/SPackages/bison-2.7-4.el7.src.rpm
+    rpmbuild --rebuild ./bison-2.7-4.el7.src.rpm
+    sudo yum install ./rpmbuild/RPMS/x86_64/bison-2.7-4.el6.x86_64.rpm
+    rm -rf rpmbuild
+
+Install newer version of autoconf and automake (Package versions are too old)
+
+    curl -O http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
+    tar xvf autoconf-2.69.tar.gz
+    cd autoconf-2.69
+    ./configure --prefix=/usr
+    make
+    sudo make install
+    cd ..
+    
+    curl -O http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz
+    tar xvf automake-1.15.tar.gz
+    cd automake-1.15
+    ./configure --prefix=/usr
+    make
+    sudo make install
+    cd ..
+
+Install `Python 2.7` in parallel to default 2.6 (needed for `make check` to 
+run unittests). 
+Pick correct EPEL based on CentOS version used. Then install current `pytest`
+
+    rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
+    rpm -ivh https://centos6.iuscommunity.org/ius-release.rpm
+    yum install python27 python27-pip
+    pip2.7 install pytest
+
+Please note that `CentOS 6` needs to keep python pointing to version 2.6 
+for `yum` to keep working, so don't create a symlink for python2.7 to python
+    
+Get FRR, compile it and install it (from Git)
+---------------------------------------------
+
+**This assumes you want to build and install FRR from source and not using 
+any packages**
+
+### Add frr groups and user
+
+    sudo groupadd -g 92 frr
+    sudo groupadd -r -g 85 frrvt
+    sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
+      -c "FRR FreeRangeRouting suite" -d /var/run/frr frr
+
+### Download Source, configure and compile it
+(You may prefer different options on configure statement. These are just 
+an example.)
+
+You may want to pay special attention to `/usr/lib64` paths and change 
+them if you are not building on a x86_64 architecture
+
+    git clone https://github.com/freerangerouting/frr.git frr
+    cd frr
+    git checkout stable/2.0
+    ./bootstrap.sh
+    ./configure \
+        --sysconfdir=/etc/frr \
+        --libdir=/usr/lib64/frr \
+        --libexecdir=/usr/lib64/frr \
+        --localstatedir=/var/run/frr \
+        --disable-pimd \
+        --enable-snmp=agentx \
+        --enable-multipath=64 \
+        --enable-ospfclient=yes \
+        --enable-ospfapi=yes \
+        --enable-user=frr \
+        --enable-group=frr \
+        --enable-vty-group=frrvt \
+        --enable-rtadv \
+        --disable-exampledir \
+        --enable-watchfrr \
+        --enable-tcp-zebra \
+        --enable-fpm \
+        --with-pkg-git-version \
+        --with-pkg-extra-version=-MyOwnFRRVersion   
+    make
+    make check PYTHON=/usr/bin/python2.7
+    sudo make install
+
+### Create empty FRR configuration files
+    sudo mkdir /var/log/frr
+    sudo mkdir /etc/frr
+    sudo touch /etc/frr/zebra.conf
+    sudo touch /etc/frr/bgpd.conf
+    sudo touch /etc/frr/ospfd.conf
+    sudo touch /etc/frr/ospf6d.conf
+    sudo touch /etc/frr/isisd.conf
+    sudo touch /etc/frr/ripd.conf
+    sudo touch /etc/frr/ripngd.conf
+    sudo chown -R frr:frr /etc/frr/
+    sudo touch /etc/frr/vtysh.conf
+    sudo chown frr:frrvt /etc/frr/vtysh.conf
+    sudo chmod 640 /etc/frr/*.conf
+
+### Enable IP & IPv6 forwarding
+
+Edit `/etc/sysctl.conf` and set the following values (ignore the other 
+settings)
+
+    # Controls IP packet forwarding
+    net.ipv4.ip_forward = 1
+    net.ipv6.conf.all.forwarding=1
+
+    # Controls source route verification
+    net.ipv4.conf.default.rp_filter = 0
+
+**Reboot** or use `sysctl` to apply the same config to the running system
+
+### Add init.d startup files
+    sudo cp redhat/bgpd.init /etc/init.d/bgpd
+    sudo cp redhat/isisd.init /etc/init.d/isisd
+    sudo cp redhat/ospfd.init /etc/init.d/ospfd
+    sudo cp redhat/ospf6d.init /etc/init.d/ospf6d
+    sudo cp redhat/ripngd.init /etc/init.d/ripngd
+    sudo cp redhat/ripd.init /etc/init.d/ripd
+    sudo cp redhat/zebra.init /etc/init.d/zebra
+    sudo chkconfig --add zebra 
+    sudo chkconfig --add ripd
+    sudo chkconfig --add ripngd
+    sudo chkconfig --add ospf6d
+    sudo chkconfig --add ospfd
+    sudo chkconfig --add bgpd
+    sudo chkconfig --add isisd
+
+### Enable required daemons at startup
+Only enable zebra and the daemons which are needed for your setup
+
+    sudo chkconfig zebra on
+    sudo chkconfig ospfd on
+    sudo chkconfig bgpd on
+    [...] etc (as needed)
diff --git a/doc/Building_FRR_on_CentOS7.md b/doc/Building_FRR_on_CentOS7.md
new file mode 100644 (file)
index 0000000..cd10a91
--- /dev/null
@@ -0,0 +1,123 @@
+Building FRR on CentOS 7 from Git Source
+========================================
+
+CentOS 7 restrictions:
+----------------------
+
+- MPLS is not supported on `CentOS 7` with default kernel. MPLS requires 
+  Linux Kernel 4.5 or higher (LDP can be built, but may have limited use 
+  without MPLS)
+  
+Install required packages
+-------------------------
+        
+Add packages:
+
+    sudo yum install git autoconf automake libtool make gawk readline-devel \
+      texinfo net-snmp-devel groff pkgconfig json-c-devel pam-devel \
+      bison flex pytest
+
+Get FRR, compile it and install it (from Git)
+---------------------------------------------
+
+**This assumes you want to build and install FRR from source and not using 
+any packages**
+
+### Add frr groups and user
+
+    sudo groupadd -g 92 frr
+    sudo groupadd -r -g 85 frrvt
+    sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
+      -c "FRR FreeRangeRouting suite" -d /var/run/frr frr
+
+### Download Source, configure and compile it
+(You may prefer different options on configure statement. These are just 
+an example.)
+
+You may want to pay special attention to `/usr/lib64` paths and change 
+them if you are not building on a x86_64 architecture
+
+    git clone https://github.com/freerangerouting/frr.git frr
+    cd frr
+    git checkout stable/2.0
+    ./bootstrap.sh
+    ./configure \
+        --sysconfdir=/etc/frr \
+        --libdir=/usr/lib64/frr \
+        --libexecdir=/usr/lib64/frr \
+        --localstatedir=/var/run/frr \
+        --enable-snmp=agentx \
+        --enable-multipath=64 \
+        --enable-ospfclient=yes \
+        --enable-ospfapi=yes \
+        --enable-user=frr \
+        --enable-group=frr \
+        --enable-vty-group=frrvt \
+        --enable-rtadv \
+        --disable-exampledir \
+        --enable-watchfrr \
+        --enable-tcp-zebra \
+        --enable-fpm \
+        --with-pkg-git-version \
+        --with-pkg-extra-version=-MyOwnFRRVersion   
+    make
+    make check
+    sudo make install
+
+### Create empty FRR configuration files
+    sudo mkdir /var/log/frr
+    sudo mkdir /etc/frr
+    sudo touch /etc/frr/zebra.conf
+    sudo touch /etc/frr/bgpd.conf
+    sudo touch /etc/frr/ospfd.conf
+    sudo touch /etc/frr/ospf6d.conf
+    sudo touch /etc/frr/isisd.conf
+    sudo touch /etc/frr/ripd.conf
+    sudo touch /etc/frr/ripngd.conf
+    sudo touch /etc/frr/pimd.conf
+    sudo chown -R frr:frr /etc/frr/
+    sudo touch /etc/frr/vtysh.conf
+    sudo chown frr:frrvt /etc/frr/vtysh.conf
+    sudo chmod 640 /etc/frr/*.conf
+
+### Enable IP & IPv6 forwarding
+
+Create a new file `/etc/sysctl.d/90-routing-sysctl.conf` with the 
+following content:
+
+    # Sysctl for routing
+    #
+    # Routing: We need to forward packets
+    net.ipv4.conf.all.forwarding=1
+    net.ipv6.conf.all.forwarding=1
+
+**Reboot** or use `sysctl` to apply the same config to the running system
+
+### Install Service files 
+    sudo install -p -m 644 redhat/zebra.service /usr/lib/systemd/system/zebra.service
+    sudo install -p -m 644 redhat/isisd.service /usr/lib/systemd/system/isisd.service
+    sudo install -p -m 644 redhat/ripd.service /usr/lib/systemd/system/ripd.service
+    sudo install -p -m 644 redhat/ospfd.service /usr/lib/systemd/system/ospfd.service
+    sudo install -p -m 644 redhat/bgpd.service /usr/lib/systemd/system/bgpd.service
+    sudo install -p -m 644 redhat/ospf6d.service /usr/lib/systemd/system/ospf6d.service
+    sudo install -p -m 644 redhat/ripngd.service /usr/lib/systemd/system/ripngd.service
+    sudo install -p -m 644 redhat/pimd.service /usr/lib/systemd/system/pimd.service
+    sudo install -p -m 644 redhat/frr.sysconfig /etc/sysconfig/frr
+    sudo install -p -m 644 redhat/frr.logrotate /etc/logrotate.d/frr
+
+### Register the systemd files
+    sudo systemctl preset zebra.service
+    sudo systemctl preset ripd.service
+    sudo systemctl preset ospfd.service
+    sudo systemctl preset bgpd.service
+    sudo systemctl preset ospf6d.service
+    sudo systemctl preset ripngd.service
+    sudo systemctl preset pimd.service
+
+### Enable required daemons at startup
+Only enable zebra and the daemons which are needed for your setup
+
+    sudo systemctl enable zebra
+    sudo systemctl enable ospfd
+    sudo systemctl enable bgpd
+    [...] etc (as needed)
diff --git a/doc/Building_FRR_on_Debian8.md b/doc/Building_FRR_on_Debian8.md
new file mode 100644 (file)
index 0000000..902f8c6
--- /dev/null
@@ -0,0 +1,98 @@
+Building FRR on Debian 8 from Git Source
+========================================
+
+Debian 8 restrictions:
+----------------------
+
+- MPLS is not supported on `Debian 8` with default kernel. MPLS requires 
+  Linux Kernel 4.5 or higher (LDP can be built, but may have limited use 
+  without MPLS)
+
+Install required packages
+-------------------------
+        
+Add packages:
+
+    sudo apt-get install git autoconf automake libtool make gawk \
+       libreadline-dev texinfo libjson-c-dev pkg-config bison flex \
+       python-pip
+
+Install newer pytest (>3.0) from pip    
+
+    sudo pip install pytest    
+
+Get FRR, compile it and install it (from Git)
+---------------------------------------------
+
+**This assumes you want to build and install FRR from source and not using 
+any packages**
+
+### Add frr groups and user
+
+    sudo addgroup --system --gid 92 frr
+    sudo addgroup --system --gid 85 frrvty
+    sudo adduser --system --ingroup frr --groups frrvty --home /var/run/frr/ \
+       --gecos "FRR FreeRangeRouting suite" --shell /bin/false frr
+    sudo usermode
+
+### Download Source, configure and compile it
+(You may prefer different options on configure statement. These are just
+an example.)
+
+    git clone https://github.com/freerangerouting/frr.git frr
+    cd frr
+    git checkout stable/2.0
+    ./bootstrap.sh
+    ./configure \
+        --enable-exampledir=/usr/share/doc/frr/examples/ \
+        --localstatedir=/var/run/frr \
+        --sbindir=/usr/lib/frr \
+        --sysconfdir=/etc/frr \
+        --enable-vtysh \
+        --enable-isisd \
+        --enable-pimd \
+        --enable-watchfrr \
+        --enable-ospfclient=yes \
+        --enable-ospfapi=yes \
+        --enable-multipath=64 \
+        --enable-user=frr \
+        --enable-group=frr \
+        --enable-vty-group=frrvty \
+        --enable-configfile-mask=0640 \
+        --enable-logfile-mask=0640 \
+        --enable-rtadv \
+        --enable-tcp-zebra \
+        --enable-fpm \
+        --with-pkg-git-version \
+        --with-pkg-extra-version=-MyOwnFRRVersion   
+    make
+    make check
+    sudo make install
+
+### Create empty FRR configuration files
+    sudo install -m 755 -o frr -g frr -d /var/log/frr
+    sudo install -m 775 -o frr -g frrvty -d /etc/frr
+    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
+    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
+    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
+    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
+    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
+    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
+    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
+    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
+    sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
+
+### Enable IP & IPv6 forwarding
+
+Edit `/etc/sysctl.conf` and uncomment the following values (ignore the 
+other settings)
+
+    # Uncomment the next line to enable packet forwarding for IPv4
+    net.ipv4.ip_forward=1
+
+    # Uncomment the next line to enable packet forwarding for IPv6
+    #  Enabling this option disables Stateless Address Autoconfiguration
+    #  based on Router Advertisements for this host
+    net.ipv6.conf.all.forwarding=1
+
+**Reboot** or use `sysctl` to apply the same config to the running system
diff --git a/doc/Building_FRR_on_Fedora24.md b/doc/Building_FRR_on_Fedora24.md
new file mode 100644 (file)
index 0000000..9617afc
--- /dev/null
@@ -0,0 +1,134 @@
+Building FRR on Fedora 24 from Git Source
+=========================================
+
+Install required packages
+-------------------------
+
+Add packages:
+
+    sudo dnf install git autoconf automake libtool make gawk \
+       readline-devel texinfo net-snmp-devel groff pkgconfig \
+       json-c-devel pam-devel perl-XML-LibXML pytest
+
+Get FRR, compile it and install it (from Git)
+---------------------------------------------
+
+**This assumes you want to build and install FRR from source and not 
+using any packages**
+
+### Add frr groups and user
+
+    sudo groupadd -g 92 frr
+    sudo groupadd -r -g 85 frrvt
+    sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
+      -c "FRR FreeRangeRouting suite" -d /var/run/frr frr
+
+### Download Source, configure and compile it
+(You may prefer different options on configure statement. These are just 
+an example.)
+
+You may want to pay special attention to `/usr/lib64` paths and change 
+them if you are not building on a x86_64 architecture
+
+    git clone https://github.com/freerangerouting/frr.git frr
+    cd frr
+    git checkout stable/2.0
+    ./bootstrap.sh
+    ./configure \
+        --sysconfdir=/etc/frr \
+        --libdir=/usr/lib64/frr \
+        --libexecdir=/usr/lib64/frr \
+        --localstatedir=/var/run/frr \
+        --enable-pimd \
+        --enable-snmp=agentx \
+        --enable-multipath=64 \
+        --enable-ospfclient=yes \
+        --enable-ospfapi=yes \
+        --enable-user=frr \
+        --enable-group=frr \
+        --enable-vty-group=frrvt \
+        --enable-rtadv \
+        --disable-exampledir \
+        --enable-watchfrr \
+        --enable-tcp-zebra \
+        --enable-fpm \
+        --with-pkg-git-version \
+        --with-pkg-extra-version=-MyOwnFRRVersion    
+    make
+    make check
+    sudo make install
+
+### Create empty FRR configuration files
+    sudo mkdir /var/log/frr
+    sudo mkdir /etc/frr
+    sudo touch /etc/frr/zebra.conf
+    sudo touch /etc/frr/bgpd.conf
+    sudo touch /etc/frr/ospfd.conf
+    sudo touch /etc/frr/ospf6d.conf
+    sudo touch /etc/frr/isisd.conf
+    sudo touch /etc/frr/ripd.conf
+    sudo touch /etc/frr/ripngd.conf
+    sudo touch /etc/frr/pimd.conf
+    sudo touch /etc/frr/ldpd.conf
+    sudo chown -R frr:frr /etc/frr/
+    sudo touch /etc/frr/vtysh.conf
+    sudo chown frr:frrvt /etc/frr/vtysh.conf
+    sudo chmod 640 /etc/frr/*.conf
+
+### Enable IP & IPv6 forwarding (and MPLS)
+
+Create a new file `/etc/sysctl.d/90-routing-sysctl.conf` with the 
+following content:
+(Please make sure to list all interfaces with required MPLS similar 
+to `net.mpls.conf.eth0.input=1`)
+
+    # Sysctl for routing
+    #
+    # Routing: We need to forward packets
+    net.ipv4.conf.all.forwarding=1
+    net.ipv6.conf.all.forwarding=1
+    #
+    # Enable MPLS Label processing on all interfaces
+    net.mpls.conf.eth0.input=1
+    net.mpls.conf.eth1.input=1
+    net.mpls.conf.eth2.input=1
+    net.mpls.platform_labels=100000
+
+Create a new file `/etc/modules-load.d/mpls.conf` with the following content:
+
+    # Load MPLS Kernel Modules
+    mpls-router
+    mpls-iptunnel
+
+**Reboot** or use `sysctl` to apply the same config to the running system
+
+### Install Service files 
+    install -p -m 644 redhat/zebra.service /usr/lib/systemd/system/zebra.service
+    install -p -m 644 redhat/isisd.service /usr/lib/systemd/system/isisd.service
+    install -p -m 644 redhat/ripd.service /usr/lib/systemd/system/ripd.service
+    install -p -m 644 redhat/ospfd.service /usr/lib/systemd/system/ospfd.service
+    install -p -m 644 redhat/bgpd.service /usr/lib/systemd/system/bgpd.service
+    install -p -m 644 redhat/ospf6d.service /usr/lib/systemd/system/ospf6d.service
+    install -p -m 644 redhat/ripngd.service /usr/lib/systemd/system/ripngd.service
+    install -p -m 644 redhat/pimd.service /usr/lib/systemd/system/pimd.service
+    install -p -m 644 redhat/pimd.service /usr/lib/systemd/system/ldpd.service
+    install -p -m 644 redhat/frr.sysconfig /etc/sysconfig/frr
+    install -p -m 644 redhat/frr.logrotate /etc/logrotate.d/frr
+
+### Register the systemd files
+    systemctl preset zebra.service
+    systemctl preset ripd.service
+    systemctl preset ospfd.service
+    systemctl preset bgpd.service
+    systemctl preset ospf6d.service
+    systemctl preset ripngd.service
+    systemctl preset pimd.service
+    systemctl preset ldpd.service
+
+### Enable required daemons at startup
+Only enable zebra and the daemons which are needed for your setup
+
+    systemctl enable zebra
+    systemctl enable ospfd
+    systemctl enable bgpd
+    [...] etc (as needed)
diff --git a/doc/Building_FRR_on_FreeBSD10.md b/doc/Building_FRR_on_FreeBSD10.md
new file mode 100644 (file)
index 0000000..696b7d5
--- /dev/null
@@ -0,0 +1,96 @@
+Building FRR on FreeBSD 10 from Git Source
+==========================================
+
+FreeBSD 10 restrictions:
+------------------------
+
+- MPLS is not supported on `FreeBSD`. MPLS requires a Linux Kernel
+  (4.5 or higher). LDP can be built, but may have limited use 
+  without MPLS
+
+Install required packages
+-------------------------
+
+Add packages:
+(Allow the install of the package managment tool if this is first package 
+install and asked)  
+
+    pkg install git autoconf automake libtool gmake gawk json-c pkgconf \
+        bison flex py27-pytest
+
+Make sure there is no /usr/bin/flex preinstalled (and use the newly 
+installed in /usr/local/bin):
+(FreeBSD frequently provides a older flex as part of the base OS which 
+takes preference in path)
+
+    rm -f /usr/bin/flex
+
+Get FRR, compile it and install it (from Git)
+---------------------------------------------
+
+**This assumes you want to build and install FRR from source and not 
+using any packages**
+
+### Add frr group and user
+
+    pw groupadd frr -g 101
+    pw groupadd frrvty -g 102
+    pw adduser frr -g 101 -u 101 -G 102 -c "FRR suite" \
+        -d /usr/local/etc/frr -s /usr/sbin/nologin
+
+(You may prefer different options on configure statement. These are just 
+an example)
+
+    git clone https://github.com/freerangerouting/frr.git frr
+    cd frr
+    git checkout stable/2.0
+    ./bootstrap.sh
+    export MAKE=gmake
+    export LDFLAGS="-L/usr/local/lib"
+    export CPPFLAGS="-I/usr/local/include"
+    ./configure \
+        --sysconfdir=/usr/local/etc/frr \
+        --enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \
+        --localstatedir=/var/run/frr \
+        --prefix=/usr/local \
+        --enable-ospfclient=yes \
+        --enable-ospfapi=yes \
+        --enable-multipath=64 \
+        --enable-user=frr \
+        --enable-group=frr \
+        --enable-vty-group=frrvty \
+        --enable-configfile-mask=0640 \
+        --enable-logfile-mask=0640 \
+        --enable-rtadv \
+        --enable-tcp-zebra \
+        --enable-fpm \
+        --with-pkg-git-version \
+        --with-pkg-extra-version=-MyOwnFRRVersion   
+    gmake
+    gmake check
+    sudo gmake install
+
+### Create empty FRR configuration files
+    sudo mkdir /usr/local/etc/frr
+    sudo touch /usr/local/etc/frr/zebra.conf
+    sudo touch /usr/local/etc/frr/bgpd.conf
+    sudo touch /usr/local/etc/frr/ospfd.conf
+    sudo touch /usr/local/etc/frr/ospf6d.conf
+    sudo touch /usr/local/etc/frr/isisd.conf
+    sudo touch /usr/local/etc/frr/ripd.conf
+    sudo touch /usr/local/etc/frr/ripngd.conf
+    sudo touch /usr/local/etc/frr/pimd.conf
+    sudo chown -R frr:frr /usr/local/etc/frr
+    sudo touch /usr/local/etc/frr/vtysh.conf
+    sudo chown frr:frrvty /usr/local/etc/frr/vtysh.conf
+    sudo chmod 640 /usr/local/etc/frr/*.conf
+
+### Enable IP & IPv6 forwarding
+
+Add the following lines to the end of `/etc/sysctl.conf`:
+
+    # Routing: We need to forward packets
+    net.inet.ip.forwarding=1
+    net.inet6.ip6.forwarding=1
+
+**Reboot** or use `sysctl` to apply the same config to the running system
diff --git a/doc/Building_FRR_on_FreeBSD11.md b/doc/Building_FRR_on_FreeBSD11.md
new file mode 100644 (file)
index 0000000..d0b8a7b
--- /dev/null
@@ -0,0 +1,96 @@
+Building FRR on FreeBSD 11 from Git Source
+==========================================
+
+FreeBSD 11 restrictions:
+------------------------
+
+- MPLS is not supported on `FreeBSD`. MPLS requires a Linux Kernel
+  (4.5 or higher). LDP can be built, but may have limited use 
+  without MPLS
+
+Install required packages
+-------------------------
+
+Add packages:
+(Allow the install of the package managment tool if this is first package
+install and asked)  
+
+    pkg install git autoconf automake libtool gmake gawk json-c pkgconf \
+        bison flex py27-pytest
+
+Make sure there is no /usr/bin/flex preinstalled (and use the newly 
+installed in /usr/local/bin):
+(FreeBSD frequently provides a older flex as part of the base OS which
+takes preference in path)
+
+    rm -f /usr/bin/flex
+
+Get FRR, compile it and install it (from Git)
+---------------------------------------------
+
+**This assumes you want to build and install FRR from source and not 
+using any packages**
+
+### Add frr group and user
+
+    pw groupadd frr -g 101
+    pw groupadd frrvty -g 102
+    pw adduser frr -g 101 -u 101 -G 102 -c "FRR suite" \
+        -d /usr/local/etc/frr -s /usr/sbin/nologin
+
+(You may prefer different options on configure statement. These are just
+an example)
+
+    git clone https://github.com/freerangerouting/frr.git frr
+    cd frr
+    git checkout stable/2.0
+    ./bootstrap.sh
+    export MAKE=gmake
+    export LDFLAGS="-L/usr/local/lib"
+    export CPPFLAGS="-I/usr/local/include"
+    ./configure \
+        --sysconfdir=/usr/local/etc/frr \
+        --enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \
+        --localstatedir=/var/run/frr \
+        --prefix=/usr/local \
+        --enable-ospfclient=yes \
+        --enable-ospfapi=yes \
+        --enable-multipath=64 \
+        --enable-user=frr \
+        --enable-group=frr \
+        --enable-vty-group=frrvty \
+        --enable-configfile-mask=0640 \
+        --enable-logfile-mask=0640 \
+        --enable-rtadv \
+        --enable-tcp-zebra \
+        --enable-fpm \
+        --with-pkg-git-version \
+        --with-pkg-extra-version=-MyOwnFRRVersion   
+    gmake
+    gmake check
+    sudo gmake install
+
+### Create empty FRR configuration files
+    sudo mkdir /usr/local/etc/frr
+    sudo touch /usr/local/etc/frr/zebra.conf
+    sudo touch /usr/local/etc/frr/bgpd.conf
+    sudo touch /usr/local/etc/frr/ospfd.conf
+    sudo touch /usr/local/etc/frr/ospf6d.conf
+    sudo touch /usr/local/etc/frr/isisd.conf
+    sudo touch /usr/local/etc/frr/ripd.conf
+    sudo touch /usr/local/etc/frr/ripngd.conf
+    sudo touch /usr/local/etc/frr/pimd.conf
+    sudo chown -R frr:frr /usr/local/etc/frr
+    sudo touch /usr/local/etc/frr/vtysh.conf
+    sudo chown frr:frrvty /usr/local/etc/frr/vtysh.conf
+    sudo chmod 640 /usr/local/etc/frr/*.conf
+
+### Enable IP & IPv6 forwarding
+
+Add the following lines to the end of `/etc/sysctl.conf`:
+
+    # Routing: We need to forward packets
+    net.inet.ip.forwarding=1
+    net.inet6.ip6.forwarding=1
+
+**Reboot** or use `sysctl` to apply the same config to the running system
diff --git a/doc/Building_FRR_on_FreeBSD9.md b/doc/Building_FRR_on_FreeBSD9.md
new file mode 100644 (file)
index 0000000..d470d00
--- /dev/null
@@ -0,0 +1,96 @@
+Building FRR on FreeBSD 9 from Git Source
+=========================================
+
+FreeBSD 9 restrictions:
+-----------------------
+
+- MPLS is not supported on `FreeBSD`. MPLS requires a Linux Kernel
+  (4.5 or higher). LDP can be built, but may have limited use 
+  without MPLS
+  
+Install required packages
+-------------------------
+
+Add packages:
+(Allow the install of the package managment tool if this is first package 
+install and asked)  
+
+    pkg install -y git autoconf automake libtool gmake gawk \
+        pkgconf texinfo json-c bison flex py27-pytest
+
+Make sure there is no /usr/bin/flex preinstalled (and use the newly
+installed in /usr/local/bin):
+(FreeBSD frequently provides a older flex as part of the base OS which
+takes preference in path)
+
+    rm -f /usr/bin/flex
+
+Get FRR, compile it and install it (from Git)
+---------------------------------------------
+
+**This assumes you want to build and install FRR from source and not
+using any packages**
+
+### Add frr group and user
+
+    pw groupadd frr -g 101
+    pw groupadd frrvty -g 102
+    pw adduser frr -g 101 -u 101 -G 102 -c "FRR suite" \
+        -d /usr/local/etc/frr -s /usr/sbin/nologin
+
+(You may prefer different options on configure statement. These are just
+an example)
+
+    git clone https://github.com/freerangerouting/frr.git frr
+    cd frr
+    git checkout stable/2.0
+    ./bootstrap.sh
+    export MAKE=gmake
+    export LDFLAGS="-L/usr/local/lib"
+    export CPPFLAGS="-I/usr/local/include"
+    ./configure \
+        --sysconfdir=/usr/local/etc/frr \
+        --enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \
+        --localstatedir=/var/run/frr \
+        --prefix=/usr/local \
+        --enable-ospfclient=yes \
+        --enable-ospfapi=yes \
+        --enable-multipath=64 \
+        --enable-user=frr \
+        --enable-group=frr \
+        --enable-vty-group=frrvty \
+        --enable-configfile-mask=0640 \
+        --enable-logfile-mask=0640 \
+        --enable-rtadv \
+        --enable-tcp-zebra \
+        --enable-fpm \
+        --with-pkg-git-version \
+        --with-pkg-extra-version=-MyOwnFRRVersion   
+    gmake
+    gmake check
+    sudo gmake install
+
+### Create empty FRR configuration files
+    sudo mkdir /usr/local/etc/frr
+    sudo touch /usr/local/etc/frr/zebra.conf
+    sudo touch /usr/local/etc/frr/bgpd.conf
+    sudo touch /usr/local/etc/frr/ospfd.conf
+    sudo touch /usr/local/etc/frr/ospf6d.conf
+    sudo touch /usr/local/etc/frr/isisd.conf
+    sudo touch /usr/local/etc/frr/ripd.conf
+    sudo touch /usr/local/etc/frr/ripngd.conf
+    sudo touch /usr/local/etc/frr/pimd.conf
+    sudo chown -R frr:frr /usr/local/etc/frr
+    sudo touch /usr/local/etc/frr/vtysh.conf
+    sudo chown frr:frrvty /usr/local/etc/frr/vtysh.conf
+    sudo chmod 640 /usr/local/etc/frr/*.conf
+
+### Enable IP & IPv6 forwarding
+
+Add the following lines to the end of `/etc/sysctl.conf`:
+
+    # Routing: We need to forward packets
+    net.inet.ip.forwarding=1
+    net.inet6.ip6.forwarding=1
+
+**Reboot** or use `sysctl` to apply the same config to the running system
diff --git a/doc/Building_FRR_on_NetBSD6.md b/doc/Building_FRR_on_NetBSD6.md
new file mode 100644 (file)
index 0000000..03d04ce
--- /dev/null
@@ -0,0 +1,117 @@
+Building FRR on NetBSD 6 from Git Source
+========================================
+
+NetBSD 6 restrictions:
+----------------------
+
+- MPLS is not supported on `NetBSD`. MPLS requires a Linux Kernel
+  (4.5 or higher). LDP can be built, but may have limited use 
+  without MPLS
+
+Install required packages
+-------------------------
+Configure Package location:
+
+    PKG_PATH="ftp://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/`uname -m`/`uname -r`/All"
+    export PKG_PATH
+
+Add packages:
+
+    sudo pkg_add git autoconf automake libtool gmake gawk openssl \
+       pkg-config json-c p5-XML-LibXML python27 py27-test
+
+Install SSL Root Certificates (for git https access):
+
+    sudo pkg_add mozilla-rootcerts
+    sudo touch /etc/openssl/openssl.cnf
+    sudo mozilla-rootcerts install
+
+Select default Python and py.test
+
+    sudo ln -s /usr/pkg/bin/python2.7 /usr/bin/python
+    sudo ln -s /usr/pkg/bin/py.test-2.7 /usr/bin/py.test
+
+Get FRR, compile it and install it (from Git)
+------------------------------------------------
+
+### Add frr groups and user
+
+    sudo groupadd -g 92 frr
+    sudo groupadd -g 93 frrvty
+    sudo useradd -g 92 -u 92 -G frrvty -c "FRR suite" \
+        -d /nonexistent -s /sbin/nologin frr
+
+### Download Source, configure and compile it
+(You may prefer different options on configure statement. These are just 
+an example)
+
+    git clone https://github.com/freerangerouting/frr.git frr
+    cd frr
+    git checkout stable/2.0
+    ./bootstrap.sh
+    MAKE=gmake
+    export LDFLAGS="-L/usr/pkg/lib -R/usr/pkg/lib"
+    export CPPFLAGS="-I/usr/pkg/include"
+    ./configure \
+        --sysconfdir=/usr/pkg/etc/frr \
+        --enable-exampledir=/usr/pkg/share/examples/frr \
+        --enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \
+        --localstatedir=/var/run/frr \
+        --enable-ospfclient=yes \
+        --enable-ospfapi=yes \
+        --enable-multipath=64 \
+        --enable-user=frr \
+        --enable-group=frr \
+        --enable-vty-group=frrvty \
+        --enable-configfile-mask=0640 \
+        --enable-logfile-mask=0640 \
+        --enable-rtadv \
+        --enable-tcp-zebra \
+        --enable-fpm \
+        --with-pkg-git-version \
+        --with-pkg-extra-version=-MyOwnFRRVersion   
+    gmake
+    gmake check
+    sudo gmake install
+
+### Create empty FRR configuration files
+    sudo mkdir /var/log/frr
+    sudo mkdir /usr/pkg/etc/frr
+    sudo touch /usr/pkg/etc/frr/zebra.conf
+    sudo touch /usr/pkg/etc/frr/bgpd.conf
+    sudo touch /usr/pkg/etc/frr/ospfd.conf
+    sudo touch /usr/pkg/etc/frr/ospf6d.conf
+    sudo touch /usr/pkg/etc/frr/isisd.conf
+    sudo touch /usr/pkg/etc/frr/ripd.conf
+    sudo touch /usr/pkg/etc/frr/ripngd.conf
+    sudo touch /usr/pkg/etc/frr/pimd.conf
+    sudo chown -R frr:frr /usr/pkg/etc/frr
+    sudo touch /usr/local/etc/frr/vtysh.conf
+    sudo chown frr:frrvty /usr/pkg/etc/frr/*.conf
+    sudo chmod 640 /usr/pkg/etc/frr/*.conf
+
+### Enable IP & IPv6 forwarding
+
+Add the following lines to the end of `/etc/sysctl.conf`:
+
+    # Routing: We need to forward packets
+    net.inet.ip.forwarding=1
+    net.inet6.ip6.forwarding=1
+
+**Reboot** or use `sysctl` to apply the same config to the running system
+
+### Install rc.d init files
+    cp pkgsrc/*.sh /etc/rc.d/
+    chmod 555 /etc/rc.d/*.sh
+
+### Enable FRR processes
+(Enable the required processes only)
+
+    echo "zebra=YES" >> /etc/rc.conf
+    echo "bgpd=YES" >> /etc/rc.conf
+    echo "ospfd=YES" >> /etc/rc.conf
+    echo "ospf6d=YES" >> /etc/rc.conf
+    echo "isisd=YES" >> /etc/rc.conf
+    echo "ripngd=YES" >> /etc/rc.conf
+    echo "ripd=YES" >> /etc/rc.conf
+    echo "pimd=YES" >> /etc/rc.conf
diff --git a/doc/Building_FRR_on_NetBSD7.md b/doc/Building_FRR_on_NetBSD7.md
new file mode 100644 (file)
index 0000000..d9b4b47
--- /dev/null
@@ -0,0 +1,110 @@
+Building FRR on NetBSD 7 from Git Source
+========================================
+
+NetBSD 7 restrictions:
+----------------------
+
+- MPLS is not supported on `NetBSD`. MPLS requires a Linux Kernel
+  (4.5 or higher). LDP can be built, but may have limited use 
+  without MPLS
+
+Install required packages
+-------------------------
+
+    sudo pkgin install git autoconf automake libtool gmake gawk openssl \
+       pkg-config json-c p5-XML-LibXML python27 py27-test
+
+Install SSL Root Certificates (for git https access):
+
+    sudo pkgin install mozilla-rootcerts
+    sudo touch /etc/openssl/openssl.cnf
+    sudo mozilla-rootcerts install
+
+Select default Python and py.test
+
+    sudo ln -s /usr/pkg/bin/python2.7 /usr/bin/python
+    sudo ln -s /usr/pkg/bin/py.test-2.7 /usr/bin/py.test
+
+Get FRR, compile it and install it (from Git)
+------------------------------------------------
+
+### Add frr groups and user
+
+    sudo groupadd -g 92 frr
+    sudo groupadd -g 93 frrvty
+    sudo useradd -g 92 -u 92 -G frrvty -c "FRR suite" \
+        -d /nonexistent -s /sbin/nologin frr
+
+### Download Source, configure and compile it
+(You may prefer different options on configure statement. These are just
+an example)
+
+    git clone https://github.com/freerangerouting/frr.git frr
+    cd frr
+    git checkout stable/2.0
+    ./bootstrap.sh
+    MAKE=gmake
+    export LDFLAGS="-L/usr/pkg/lib -R/usr/pkg/lib"
+    export CPPFLAGS="-I/usr/pkg/include"
+    ./configure \
+        --sysconfdir=/usr/pkg/etc/frr \
+        --enable-exampledir=/usr/pkg/share/examples/frr \
+        --enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \
+        --localstatedir=/var/run/frr \
+        --enable-ospfclient=yes \
+        --enable-ospfapi=yes \
+        --enable-multipath=64 \
+        --enable-user=frr \
+        --enable-group=frr \
+        --enable-vty-group=frrvty \
+        --enable-configfile-mask=0640 \
+        --enable-logfile-mask=0640 \
+        --enable-rtadv \
+        --enable-tcp-zebra \
+        --enable-fpm \
+        --with-pkg-git-version \
+        --with-pkg-extra-version=-MyOwnFRRVersion   
+    gmake
+    gmake check
+    sudo gmake install
+
+### Create empty FRR configuration files
+    sudo mkdir /usr/pkg/etc/frr
+    sudo touch /usr/pkg/etc/frr/zebra.conf
+    sudo touch /usr/pkg/etc/frr/bgpd.conf
+    sudo touch /usr/pkg/etc/frr/ospfd.conf
+    sudo touch /usr/pkg/etc/frr/ospf6d.conf
+    sudo touch /usr/pkg/etc/frr/isisd.conf
+    sudo touch /usr/pkg/etc/frr/ripd.conf
+    sudo touch /usr/pkg/etc/frr/ripngd.conf
+    sudo touch /usr/pkg/etc/frr/pimd.conf
+    sudo chown -R frr:frr /usr/pkg/etc/frr
+    sudo touch /usr/local/etc/frr/vtysh.conf
+    sudo chown frr:frrvty /usr/pkg/etc/frr/*.conf
+    sudo chmod 640 /usr/pkg/etc/frr/*.conf
+
+### Enable IP & IPv6 forwarding
+
+Add the following lines to the end of `/etc/sysctl.conf`:
+
+    # Routing: We need to forward packets
+    net.inet.ip.forwarding=1
+    net.inet6.ip6.forwarding=1
+
+**Reboot** or use `sysctl` to apply the same config to the running system
+
+### Install rc.d init files
+    cp pkgsrc/*.sh /etc/rc.d/
+    chmod 555 /etc/rc.d/*.sh
+
+### Enable FRR processes
+(Enable the required processes only)
+
+    echo "zebra=YES" >> /etc/rc.conf
+    echo "bgpd=YES" >> /etc/rc.conf
+    echo "ospfd=YES" >> /etc/rc.conf
+    echo "ospf6d=YES" >> /etc/rc.conf
+    echo "isisd=YES" >> /etc/rc.conf
+    echo "ripngd=YES" >> /etc/rc.conf
+    echo "ripd=YES" >> /etc/rc.conf
+    echo "pimd=YES" >> /etc/rc.conf
diff --git a/doc/Building_FRR_on_OmniOS.md b/doc/Building_FRR_on_OmniOS.md
new file mode 100644 (file)
index 0000000..f158c80
--- /dev/null
@@ -0,0 +1,124 @@
+Building FRR on OmniOS (OpenSolaris) from Git Source
+====================================================
+
+OmniOS restrictions:
+--------------------
+
+- MPLS is not supported on `OmniOS` or `Solaris`. MPLS requires a Linux 
+  Kernel (4.5 or higher). LDP can be built, but may have limited use 
+  without MPLS
+
+### Enable IP & IPv6 forwarding
+
+    routeadm -e ipv4-forwarding
+    routeadm -e ipv6-forwarding 
+
+Install required packages
+-------------------------
+
+Add packages:
+
+    pkg install \
+      developer/build/autoconf \
+      developer/build/automake \
+      developer/lexer/flex \
+      developer/parser/bison \
+      developer/object-file \
+      developer/linker \
+      developer/library/lint \
+      developer/build/gnu-make \
+      developer/gcc51 \
+      library/idnkit \
+      library/idnkit/header-idnkit \
+      system/header \
+      system/library/math/header-math \
+      git libtool gawk pkg-config   
+
+Add additional Solaris packages:
+
+    pkgadd -d http://get.opencsw.org/now
+    /opt/csw/bin/pkgutil -U
+    /opt/csw/bin/pkgutil -y -i texinfo
+    /opt/csw/bin/pkgutil -y -i perl
+    /opt/csw/bin/pkgutil -y -i libjson_c_dev
+    /opt/csw/bin/pkgutil -y -i python27 py_pip
+
+Add libjson to Solaris equivalent of ld.so.conf
+
+    crle -l /opt/csw/lib -u
+
+Add Perl packages:
+
+    cpan
+    cpan[1]> install XML::LibXML
+    cpan[2]> exit
+
+Add pytest:
+
+    pip install pytest
+
+Select Python 2.7 as default (required for pytest)
+
+    rm -f /usr/bin/python
+    ln -s /opt/csw/bin/python2.7 /usr/bin/python
+        
+Fix PATH for all users and non-interactive sessions. Edit `/etc/default/login`
+and add the following default PATH:
+
+    PATH=/usr/gnu/bin:/usr/bin:/usr/sbin:/sbin:/opt/csw/bin
+
+Edit `~/.profile` and add the following default PATH:
+
+    PATH=/usr/gnu/bin:/usr/bin:/usr/sbin:/sbin:/opt/csw/bin
+
+Get FRR, compile it and install it (from Git)
+---------------------------------------------
+
+**This assumes you want to build and install FRR from source and not using
+any packages**
+
+### Add frr group and user
+
+    sudo groupadd -g 93 frr
+    sudo groupadd -g 94 frrvty
+    sudo useradd -g 93 -u 93 -G frrvty -c "FRR suite" \
+        -d /nonexistent -s /bin/false frr
+
+(You may prefer different options on configure statement. These are just
+an example)
+
+    git clone https://github.com/freerangerouting/frr.git frr
+    cd frr
+    git checkout stable/2.0
+    ./bootstrap.sh
+    export MAKE=gmake
+    export LDFLAGS="-L/opt/csw/lib"
+    export CPPFLAGS="-I/opt/csw/include"
+    ./configure \
+        --sysconfdir=/etc/frr \
+        --enable-exampledir=/usr/share/doc/frr/examples/ \
+        --localstatedir=/var/run/frr \
+        --sbindir=/usr/lib/frr \
+        --enable-vtysh \
+        --enable-watchfrr \
+        --enable-ospfclient=yes \
+        --enable-ospfapi=yes \
+        --enable-multipath=64 \
+        --enable-user=frr \
+        --enable-group=frr \
+        --enable-vty-group=frrvty \
+        --enable-configfile-mask=0640 \
+        --enable-logfile-mask=0640 \
+        --enable-rtadv \
+        --enable-tcp-zebra \
+        --enable-fpm \
+        --with-pkg-git-version \
+        --with-pkg-extra-version=-MyOwnFRRVersion   
+    gmake
+    gmake check
+    sudo gmake install
+
+### Enable IP & IPv6 forwarding
+
+    routeadm -e ipv4-forwarding
+    routeadm -e ipv6-forwarding 
diff --git a/doc/Building_FRR_on_OpenBSD6.md b/doc/Building_FRR_on_OpenBSD6.md
new file mode 100644 (file)
index 0000000..9e13d5c
--- /dev/null
@@ -0,0 +1,129 @@
+Building FRR on OpenBSD 6 from Git Source
+=========================================
+
+OpenBSD restrictions:
+---------------------
+
+- MPLS is not tested on `OpenBSD`. It may work as it shares the
+  sources with the LDPd on OpenBSD. Bug reports and fixes are welcome
+
+Install required packages
+-------------------------
+
+Configure PKG_PATH
+
+    export PKG_PATH=http://ftp5.usa.openbsd.org/pub/OpenBSD/$(uname -r)/packages/$(machine -a)/
+
+Add packages:
+
+    pkg_add git autoconf-2.69p2 automake-1.15p0 libtool
+    pkg_add gmake gawk dejagnu openssl json-c p5-XML-LibXML py-test
+
+Select Python2.7 as default (required for pytest)
+
+    ln -s /usr/local/bin/python2.7 /usr/local/bin/python
+
+Get FRR, compile it and install it (from Git)
+---------------------------------------------
+
+**This assumes you want to build and install FRR from source and not using
+any packages**
+
+### Add frr group and user
+
+    groupadd -g 525 _frr
+    groupadd -g 526 _frrvty
+    useradd -g 525 -u 525 -c "FRR suite" -G _frrvty \
+        -d /nonexistent -s /sbin/nologin _frr
+
+### Download Source, configure and compile it
+(You may prefer different options on configure statement. These are just 
+an example)
+
+    git clone https://github.com/freerangerouting/frr.git frr
+    cd frr
+    git checkout stable/2.0
+    ./bootstrap.sh
+    export LDFLAGS="-L/usr/local/lib"
+    export CPPFLAGS="-I/usr/local/include"
+    ./configure \
+        --sysconfdir=/etc/frr \
+        --localstatedir=/var/frr \
+        --enable-pimd \
+        --enable-ospfclient=yes \
+        --enable-ospfapi=yes \
+        --enable-multipath=64 \
+        --enable-user=_frr \
+        --enable-group=_frr \
+        --enable-vty-group=_frrvty \
+        --enable-configfile-mask=0640 \
+        --enable-logfile-mask=0640 \
+        --enable-rtadv \
+        --enable-tcp-zebra \
+        --enable-fpm \
+        --enable-ldpd \
+        --with-pkg-git-version \
+        --with-pkg-extra-version=-MyOwnFRRVersion   
+    gmake
+    gmake check
+    sudo gmake install
+
+### Create empty FRR configuration files
+
+    sudo mkdir /var/frr
+    sudo chown _frr:_frr /var/frr
+    sudo chmod 755 /var/frr
+    sudo mkdir /etc/frr
+    sudo touch /etc/frr/zebra.conf
+    sudo touch /etc/frr/bgpd.conf
+    sudo touch /etc/frr/ospfd.conf
+    sudo touch /etc/frr/ospf6d.conf
+    sudo touch /etc/frr/isisd.conf
+    sudo touch /etc/frr/ripd.conf
+    sudo touch /etc/frr/ripngd.conf
+    sudo touch /etc/frr/pimd.conf
+    sudo touch /etc/frr/ldpd.conf
+    sudo chown -R _frr:_frr /etc/frr
+    sudo touch /etc/frr/vtysh.conf
+    sudo chown -R _frr:_frrvty /etc/frr/vtysh.conf
+    sudo chmod 750 /etc/frr
+    sudo chmod 640 /etc/frr/*.conf
+
+### Enable IP & IPv6 forwarding
+
+Add the following lines to the end of `/etc/rc.conf`:
+
+    net.inet6.ip6.forwarding=1      # 1=Permit forwarding of IPv6 packets 
+    net.inet6.ip6.mforwarding=1     # 1=Permit forwarding of IPv6 multicast packets
+    net.inet6.ip6.multipath=1       # 1=Enable IPv6 multipath routing
+
+**Reboot** to apply the config to the system
+
+### Install rc.d init files
+(create them in /etc/rc.d - no example are included at this time with 
+FRR source)
+
+Example (for zebra - store as `/etc/rc.d/frr_zebra.sh`)
+
+    #!/bin/sh
+    #
+    # $OpenBSD: frr_zebra.rc,v 1.1 2013/04/18 20:29:08 sthen Exp $
+    
+    daemon="/usr/local/sbin/zebra -d"
+    
+    . /etc/rc.d/rc.subr
+    
+    rc_cmd $1
+
+### Enable FRR processes
+(Enable the required processes only)
+
+    echo "frr_zebra=YES" >> /etc/rc.conf
+    echo "frr_bgpd=YES" >> /etc/rc.conf
+    echo "frr_ospfd=YES" >> /etc/rc.conf
+    echo "frr_ospf6d=YES" >> /etc/rc.conf
+    echo "frr_isisd=YES" >> /etc/rc.conf
+    echo "frr_ripngd=YES" >> /etc/rc.conf
+    echo "frr_ripd=YES" >> /etc/rc.conf
+    echo "frr_pimd=YES" >> /etc/rc.conf
+    echo "frr_ldpd=YES" >> /etc/rc.conf
diff --git a/doc/Building_FRR_on_Ubuntu1204.md b/doc/Building_FRR_on_Ubuntu1204.md
new file mode 100644 (file)
index 0000000..3312a2c
--- /dev/null
@@ -0,0 +1,136 @@
+Building FRR on Ubuntu 12.04LTS from Git Source
+===============================================
+
+- MPLS is not supported on `Ubuntu 12.04` with default kernel. MPLS requires 
+  Linux Kernel 4.5 or higher (LDP can be built, but may have limited use 
+  without MPLS)
+  For an updated Ubuntu Kernel, see http://kernel.ubuntu.com/~kernel-ppa/mainline/
+
+Install required packages
+-------------------------
+
+Add packages:
+
+    apt-get install git autoconf automake libtool make gawk libreadline-dev \
+       texinfo libpam0g-dev dejagnu libjson0 pkg-config libpam0g-dev \
+       libjson0-dev flex python-pip
+
+Install newer bison from 14.04 package source (Ubuntu 12.04 package source
+is too old)
+
+    mkdir builddir
+    cd builddir
+    wget http://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.0.2.dfsg-2.dsc
+    wget http://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.0.2.dfsg.orig.tar.bz2
+    wget http://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.0.2.dfsg-2.debian.tar.gz
+    tar -jxvf bison_3.0.2.dfsg.orig.tar.bz2 
+    cd bison-3.0.2.dfsg/
+    tar xzf ../bison_3.0.2.dfsg-2.debian.tar.gz 
+    sudo apt-get build-dep bison
+    debuild -b -uc -us
+    cd ..
+    sudo dpkg -i ./libbison-dev_3.0.2.dfsg-2_amd64.deb ./bison_3.0.2.dfsg-2_amd64.deb 
+    cd ..
+    rm -rf builddir
+
+Install newer version of autoconf and automake:
+
+    wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
+    tar xvf autoconf-2.69.tar.gz
+    cd autoconf-2.69
+    ./configure --prefix=/usr
+    make
+    sudo make install
+    cd ..
+    
+    wget http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz
+    tar xvf automake-1.15.tar.gz
+    cd automake-1.15
+    ./configure --prefix=/usr
+    make
+    sudo make install
+    cd ..
+
+Install pytest:
+
+    pip install pytest
+
+Get FRR, compile it and install it (from Git)
+---------------------------------------------
+
+**This assumes you want to build and install FRR from source and not using
+any packages**
+
+### Add frr groups and user
+
+    sudo groupadd -g 92 frr
+    sudo groupadd -r -g 85 frrvty
+    sudo adduser --system --ingroup frr --groups frrvty --home /var/run/frr/ \
+       --gecos "FRR suite" --shell /sbin/nologin frr
+
+### Download Source, configure and compile it
+(You may prefer different options on configure statement. These are just
+an example.)
+
+    git clone https://github.com/freerangerouting/frr.git frr
+    cd frr
+    git checkout stable/2.0
+    ./bootstrap.sh
+    ./configure \
+        --enable-exampledir=/usr/share/doc/frr/examples/ \
+        --localstatedir=/var/run/frr \
+        --sbindir=/usr/lib/frr \
+        --sysconfdir=/etc/frr \
+        --enable-pimd \
+        --enable-watchfrr \
+        --enable-ospfclient=yes \
+        --enable-ospfapi=yes \
+        --enable-multipath=64 \
+        --enable-user=frr \
+        --enable-group=frr \
+        --enable-vty-group=frrvty \
+        --enable-configfile-mask=0640 \
+        --enable-logfile-mask=0640 \
+        --enable-rtadv \
+        --enable-tcp-zebra \
+        --enable-fpm \
+        --enable-ldpd \
+        --with-pkg-git-version \
+        --with-pkg-extra-version=-MyOwnFRRVersion   
+    make
+    make check
+    sudo make install
+
+### Create empty FRR configuration files
+
+    sudo mkdir /var/log/frr
+    sudo chown frr:fee /var/log/frr
+    sudo mkdir /etc/frr
+    sudo touch /etc/frr/etc/zebra.conf
+    sudo touch /etc/frr/etc/bgpd.conf
+    sudo touch /etc/frr/etc/ospfd.conf
+    sudo touch /etc/frr/etc/ospf6d.conf
+    sudo touch /etc/frr/etc/isisd.conf
+    sudo touch /etc/frr/etc/ripd.conf
+    sudo touch /etc/frr/etc/ripngd.conf
+    sudo touch /etc/frr/etc/pimd.conf
+    sudo touch /etc/frr/etc/ldpd.conf
+    sudo chown frr:frr /etc/frr/
+    sudo touch /etc/frr/etc/vtysh.conf
+    sudo chown frr:frrvty /etc/frr/etc/vtysh.conf
+    sudo chmod 640 /etc/frr/*.conf
+
+### Enable IP & IPv6 forwarding
+
+Edit `/etc/sysctl.conf` and uncomment the following values (ignore the 
+other settings)
+
+    # Uncomment the next line to enable packet forwarding for IPv4
+    net.ipv4.ip_forward=1
+
+    # Uncomment the next line to enable packet forwarding for IPv6
+    #  Enabling this option disables Stateless Address Autoconfiguration
+    #  based on Router Advertisements for this host
+    net.ipv6.conf.all.forwarding=1
+
+**Reboot** or use `sysctl` to apply the same config to the running system
diff --git a/doc/Building_FRR_on_Ubuntu1404.md b/doc/Building_FRR_on_Ubuntu1404.md
new file mode 100644 (file)
index 0000000..ac0a45a
--- /dev/null
@@ -0,0 +1,94 @@
+Building FRR on Ubuntu 14.04LTS from Git Source
+===============================================
+
+- MPLS is not supported on `Ubuntu 14.04` with default kernel. MPLS requires 
+  Linux Kernel 4.5 or higher (LDP can be built, but may have limited use 
+  without MPLS)
+  For an updated Ubuntu Kernel, see http://kernel.ubuntu.com/~kernel-ppa/mainline/
+
+Install required packages
+-------------------------
+        
+Add packages:
+
+    apt-get install git autoconf automake libtool make gawk libreadline-dev \
+       texinfo dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex \
+       python-pytest
+
+Get FRR, compile it and install it (from Git)
+---------------------------------------------
+
+**This assumes you want to build and install FRR from source and not using
+any packages**
+
+### Add frr groups and user
+
+    sudo groupadd -g 92 frr
+    sudo groupadd -r -g 85 frrvty
+    sudo adduser --system --ingroup frr --groups frrvty --home /var/run/frr/ \
+       --gecos "FRR suite" --shell /sbin/nologin frr
+
+### Download Source, configure and compile it
+(You may prefer different options on configure statement. These are just 
+an example.)
+
+    git clone https://github.com/freerangerouting/frr.git frr
+    cd frr
+    git checkout stable/2.0
+    ./bootstrap.sh
+    ./configure \
+        --enable-exampledir=/usr/share/doc/frr/examples/ \
+        --localstatedir=/var/run/frr \
+        --sbindir=/usr/lib/frr \
+        --sysconfdir=/etc/frr \
+        --enable-pimd \
+        --enable-watchfrr \
+        --enable-ospfclient=yes \
+        --enable-ospfapi=yes \
+        --enable-multipath=64 \
+        --enable-user=frr \
+        --enable-group=frr \
+        --enable-vty-group=frrvty \
+        --enable-configfile-mask=0640 \
+        --enable-logfile-mask=0640 \
+        --enable-rtadv \
+        --enable-tcp-zebra \
+        --enable-fpm \
+        --with-pkg-git-version \
+        --with-pkg-extra-version=-MyOwnFRRVersion   
+    make
+    make check
+    sudo make install
+
+### Create empty FRR configuration files
+
+    sudo mkdir /var/log/frr
+    sudo chown frr:fee /var/log/frr
+    sudo mkdir /etc/frr
+    sudo touch /etc/frr/etc/zebra.conf
+    sudo touch /etc/frr/etc/bgpd.conf
+    sudo touch /etc/frr/etc/ospfd.conf
+    sudo touch /etc/frr/etc/ospf6d.conf
+    sudo touch /etc/frr/etc/isisd.conf
+    sudo touch /etc/frr/etc/ripd.conf
+    sudo touch /etc/frr/etc/ripngd.conf
+    sudo touch /etc/frr/etc/pimd.conf
+    sudo chown frr:frr /etc/frr/
+    sudo touch /etc/frr/etc/vtysh.conf
+    sudo chown frr:frrvty /etc/frr/etc/vtysh.conf
+    sudo chmod 640 /etc/frr/*.conf
+
+### Enable IP & IPv6 forwarding
+
+Edit `/etc/sysctl.conf` and uncomment the following values (ignore the 
+other settings)
+
+    # Uncomment the next line to enable packet forwarding for IPv4
+    net.ipv4.ip_forward=1
+
+    # Uncomment the next line to enable packet forwarding for IPv6
+    #  Enabling this option disables Stateless Address Autoconfiguration
+    #  based on Router Advertisements for this host
+    net.ipv6.conf.all.forwarding=1
+
+**Reboot** or use `sysctl` to apply the same config to the running system
diff --git a/doc/Building_FRR_on_Ubuntu1604.md b/doc/Building_FRR_on_Ubuntu1604.md
new file mode 100644 (file)
index 0000000..d1e1a37
--- /dev/null
@@ -0,0 +1,116 @@
+Building FRR on Ubuntu 16.04LTS from Git Source
+===============================================
+
+- MPLS is not supported on `Ubuntu 16.04` with default kernel. MPLS requires 
+  Linux Kernel 4.5 or higher (LDP can be built, but may have limited use 
+  without MPLS)
+  For an updated Ubuntu Kernel, see 
+    http://kernel.ubuntu.com/~kernel-ppa/mainline/
+
+Install required packages
+-------------------------
+
+Add packages:
+
+    apt-get install git autoconf automake libtool make gawk libreadline-dev \
+       texinfo dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex \
+       python-pytest
+
+Get FRR, compile it and install it (from Git)
+---------------------------------------------
+
+**This assumes you want to build and install FRR from source and not using 
+any packages**
+
+### Add frr groups and user
+
+    sudo groupadd -g 92 frr
+    sudo groupadd -r -g 85 frrvty
+    sudo adduser --system --ingroup frr --groups frrvty --home /var/run/frr/ \
+       --gecos "FRR suite" --shell /sbin/nologin frr
+
+### Download Source, configure and compile it
+(You may prefer different options on configure statement. These are just 
+an example.)
+
+    git clone https://github.com/freerangerouting/frr.git frr
+    cd frr
+    git checkout stable/2.0
+    ./bootstrap.sh
+    ./configure \
+        --enable-exampledir=/usr/share/doc/frr/examples/ \
+        --localstatedir=/var/run/frr \
+        --sbindir=/usr/lib/frr \
+        --sysconfdir=/etc/frr \
+        --enable-pimd \
+        --enable-watchfrr \
+        --enable-ospfclient=yes \
+        --enable-ospfapi=yes \
+        --enable-multipath=64 \
+        --enable-user=frr \
+        --enable-group=frr \
+        --enable-vty-group=frrvty \
+        --enable-configfile-mask=0640 \
+        --enable-logfile-mask=0640 \
+        --enable-rtadv \
+        --enable-tcp-zebra \
+        --enable-fpm \
+        --enable-ldpd \
+        --with-pkg-git-version \
+        --with-pkg-extra-version=-MyOwnFRRVersion   
+    make
+    make check
+    sudo make install
+
+### Create empty FRR configuration files
+
+    sudo mkdir /var/log/frr
+    sudo chown frr:fee /var/log/frr
+    sudo mkdir /etc/frr
+    sudo touch /etc/frr/etc/zebra.conf
+    sudo touch /etc/frr/etc/bgpd.conf
+    sudo touch /etc/frr/etc/ospfd.conf
+    sudo touch /etc/frr/etc/ospf6d.conf
+    sudo touch /etc/frr/etc/isisd.conf
+    sudo touch /etc/frr/etc/ripd.conf
+    sudo touch /etc/frr/etc/ripngd.conf
+    sudo touch /etc/frr/etc/pimd.conf
+    sudo touch /etc/frr/etc/ldpd.conf
+    sudo chown frr:frr /etc/frr/
+    sudo touch /etc/frr/etc/vtysh.conf
+    sudo chown frr:frrvty /etc/frr/etc/vtysh.conf
+    sudo chmod 640 /etc/frr/*.conf
+
+### Enable IP & IPv6 forwarding
+
+Edit `/etc/sysctl.conf` and uncomment the following values (ignore the 
+other settings)
+
+    # Uncomment the next line to enable packet forwarding for IPv4
+    net.ipv4.ip_forward=1
+
+    # Uncomment the next line to enable packet forwarding for IPv6
+    #  Enabling this option disables Stateless Address Autoconfiguration
+    #  based on Router Advertisements for this host
+    net.ipv6.conf.all.forwarding=1
+
+### Enable MPLS Forwarding (with Linux Kernel >= 4.5)
+
+Edit `/etc/sysctl.conf` and the following lines. Make sure to add a line 
+equal to `net.mpls.conf.eth0.input` or each interface used with MPLS
+
+    # Enable MPLS Label processing on all interfaces
+    net.mpls.conf.eth0.input=1
+    net.mpls.conf.eth1.input=1
+    net.mpls.conf.eth2.input=1
+    net.mpls.platform_labels=100000
+
+### Add MPLS kernel modules
+
+Add the following lines to `/etc/modules-load.d/modules.conf`:
+
+    # Load MPLS Kernel Modules
+    mpls-router
+    mpls-iptunnel
+
+**Reboot** or use `sysctl` to apply the same config to the running system
diff --git a/doc/cli.md b/doc/cli.md
new file mode 100644 (file)
index 0000000..559f75a
--- /dev/null
@@ -0,0 +1,356 @@
+FRR Command Line Interface
+==========================
+
+Definition Grammar
+------------------
+
+This is a reference for the syntax used when defining new CLI commands.  An
+example definition is:
+
+DEFUN (command_name,
+       command_name_cmd,
+-->    "example <command|line [interface]> DEFINITION...",
+       <..doc strings..>)
+
+The arrowed part is the definition string.
+
+Explicit syntax rules in Flex and Bison may be found in lib/command_lex.l and
+lib/command_parse.y, respectively. If you can read BNF and regex those will be
+more useful than this document.
+
+If the parser is throwing syntax or other errors and you can't figure out why,
+it's unlikely to be a bug in the parser. If the error message is not useful,
+please file a bug for a better error message. If all else fails, read the token
+definitions in the lexer source and the Bison BNF in the parser source.
+
+Characters allowed in each token type:
+
+Tokens
+------
+* WORD          -- A token that begins with +, -, or a lowercase letter. It is
+                   an unchanging part of the command and will only match itself.
+                   Example: "show ip bgp", every token is a WORD.
+* IPV4          -- 'A.B.C.D', matches an IPv4 address.
+* IPV6          -- 'X:X::X:X', matches an IPv6 address.
+* IPV4_PREFIX   -- 'A.B.C.D/M', matches an IPv4 prefix in CIDR notation.
+* IPV6_PREFIX   -- 'X:X::X:X/M', matches an IPv6 prefix in CIDR notation.
+* VARIABLE      -- Begins with a capital letter. Matches any input.
+* RANGE         -- Numeric range delimited by parentheses, e.g. (-100 - 100) or
+                   (10-20). Will only match numbers in the range.
+
+Rules
+-----
+* <angle|brackets>  -- Contain sequences of tokens separated by pipes and
+                       provide mutual exclusion.  Sequences may contain
+                       <mutual|exclusion> but not as the first token.
+                       Disallowed: "example <<a|b> c|d>"
+                       Allowed:   "example <a c|b c|d>
+* [square brackets] -- Contains sequences of tokens that are optional (can be
+                       omitted).
+* {curly|braces}    -- similar to angle brackets, but instead of mutual
+                       exclusion, curly braces indicate that one or more of the
+                       pipe-separated sequences may be provided in any order.
+* VARIADICS...      -- Any token which accepts input (so anything except WORD)
+                       and that occurs as the last token of a line may be
+                       followed by an ellipsis, which indicates that input
+                       matching the token may be repeated an unlimited number
+                       of times.
+
+Some general notes:
+
+* Options are allowed at the beginning of the command. The developer is
+  entreated to use these extremely sparingly. They are most useful for
+  implementing the 'no' form of configuration commands. Please think carefully
+  before using them for anything else. There is usually a better solution, even
+  if it is just separating out the command definition into separate ones.
+
+* The developer should judiciously apply separation of concerns when defining
+  CLI. CLI definitions for two unrelated or vaguely related commands or
+  configuration items should be defined in separate commands. Clarity is
+  preferred over LOC (within reason).
+
+Doc Strings
+-----------
+Each token in a command definition should be documented with a brief doc
+string that informs a user of the meaning and/or purpose of the subsequent
+command tree. These strings are provided as the last parameter to DEFUN macros,
+concatenated together and separated by an escaped newline ('\n'). These are
+best explained by example.
+
+DEFUN (config_terminal,
+       config_terminal_cmd,
+       "configure terminal",
+       "Configuration from vty interface\n"
+       "Configuration terminal\n")
+
+The last parameter is split into two lines for readability. Two newline
+delimited doc strings are present, one for each token in the command. The
+second string documents the functionality of the 'terminal' command in the
+'configure' tree.
+
+Note that the first string, for 'configure' does not contain documentation for
+'terminal'. This is because the CLI is best envisioned as a tree, with tokens
+defining branches. An imaginary 'start' token is the root of every command in a
+CLI node. Each subsequent written token descends into a subtree, so the
+documentation for that token ideally summarizes all the functionality contained
+in the subtree.
+
+A consequence of this structure is that the developer must be careful to use
+the same doc strings when defining multiple commands that are part of the same
+tree. Commands which share prefixes must share the same doc strings for those
+prefixes. On startup the parser will generate warnings if it notices
+inconsistent doc strings. Behavior is undefined; the same token may show up
+twice in completions, with different doc strings, or it may show up once with a
+random doc string. Parser warnings should be heeded and fixed to avoid
+confusing users.
+
+The number of doc strings provided must be equal to the amount of tokens
+present in the command definition, read left to right, ignoring any special
+constructs.
+
+In the examples below, each arrowed token needs a doc string.
+
+  "show ip bgp"
+   ^    ^  ^
+
+  "command <foo|bar> [example]"
+   ^        ^   ^     ^
+
+Data Structures
+---------------
+On startup, the CLI parser sequentially parses each command string definition
+and constructs a directed graph with each token forming a node. This graph is
+the basis of the entire CLI system. It is used to match user input in order to
+generate command completions and match commands to functions.
+
+There is one graph per CLI node (not the same as a graph node in the CLI
+graph). The CLI node struct keeps a reference to its graph (see lib/command.h).
+
+While most of the graph maintains the form of a tree, special constructs
+outlined in the Rules section introduce some quirks. <>, [] and {} form
+self-contained 'subgraphs'. Each subgraph is a tree except that all of the
+'leaves' actually share a child node. This helps with minimizing graph size and
+debugging.
+
+As an example, the subgraph generated by <foo|bar> looks like this:
+
+                      .
+                      .
+                      |
+                 +----+---+
+           +--- -+  FORK  +----+
+           |     +--------+    |
+        +--v---+            +--v---+
+        | foo  |            | bar  |
+        +--+---+            +--+---+
+           |      +------+     |
+           +------> JOIN <-----+
+                  +---+--+
+                      |
+                      .
+                      .
+
+FORK and JOIN nodes are plumbing nodes that don't correspond to user input.
+They're necessary in order to deduplicate these constructs where applicable.
+
+Options follow the same form, except that there is an edge from the FORK node
+to the JOIN node.
+
+Keywords follow the same form, except that there is an edge from JOIN to FORK.
+Because of this the CLI graph cannot be called acyclic. There is special logic
+in the input matching code that keeps a stack of paths already taken through
+the node in order to disallow following the same path more than once.
+
+Variadics are a bit special; they have an edge back to themselves, which allows
+repeating the same input indefinitely.
+
+The leaves of the graph are nodes that have no out edges. These nodes are
+special; their data section does not contain a token, as most nodes do, or
+NULL, as in FORK/JOIN nodes, but instead has a pointer to a cmd_element. All
+paths through the graph that terminate on a leaf are guaranteed to be defined
+by that command. When a user enters a complete command, the command matcher
+tokenizes the input and executes a DFS on the CLI graph. If it is
+simultaneously able to exhaust all input (one input token per graph node), and
+then find exactly one leaf connected to the last node it reaches, then the
+input has matched the corresponding command and the command is executed. If it
+finds more than one node, then the command is ambiguous (more on this in
+deduplication). If it cannot exhaust all input, the command is unknown. If it
+exhausts all input but does not find an edge node, the command is incomplete.
+
+The parser uses an incremental strategy to build the CLI graph for a node. Each
+command is parsed into its own graph, and then this graph is merged into the
+overall graph. During this merge step, the parser makes a best-effort attempt
+to remove duplicate nodes. If it finds a node in the overall graph that is
+equal to a node in the corresponding position in the command graph, it will
+intelligently merge the properties from the node in the command graph into the
+already-existing node. Subgraphs are also checked for isomorphism and merged
+where possible. The definition of whether two nodes are 'equal' is based on the
+equality of some set of token properties; read the parser source for the most
+up-to-date definition of equality.
+
+When the parser is unable to deduplicate some complicated constructs, this
+can result in two identical paths through separate parts of the graph. If
+this occurs and the user enters input that matches these paths, they will
+receive an 'ambiguous command' error and will be unable to execute the command.
+Most of the time the parser can detect and warn about duplicate commands, but
+it will not always be able to do this. Hence care should be taken before
+defining a new command to ensure it is not defined elsewhere.
+
+
+Command handlers
+----------------
+The block that follows a CLI definition is executed when a user enters input
+that matches the definition. Its function signature looks like this:
+
+int (*func) (const struct cmd_element *, struct vty *, int, struct cmd_token *[]);
+
+The first argument is the command definition struct. The last argument is an
+ordered array of tokens that correspond to the path taken through the graph,
+and the argument just prior to that is the length of the array.
+
+The arrangement of the token array has changed from the prior incarnation of
+the CLI system. In the old system, missing arguments were padded with NULLs so
+that the same parts of a command would show up at the same indices regardless
+of what was entered. The new system does not perform such padding and therefore
+it is generally _incorrect_ to assume consistent indices in this array. As a
+simple example:
+
+Command definition:
+  command [foo] <bar|baz>
+
+User enters:
+  command foo bar
+
+Array:
+  [0] -> command
+  [1] -> foo
+  [2] -> bar
+
+User enters:
+  command baz
+
+Array:
+  [0] -> command
+  [1] -> baz
+
+
+
+Command abbreviation & matching priority
+----------------------------------------
+As in the prior implementation, it is possible for users to elide parts of
+tokens when the CLI matcher does not need them to make an unambiguous match.
+This is best explained by example.
+
+Command definitions:
+  command dog cow
+  command dog crow
+
+User input:
+  c d c         -> ambiguous command
+  c d co        -> match "command dog cow"
+
+In the new implementation, this functionality has improved. Where previously
+the parser would stop at the first ambiguous token, it will now look ahead and
+attempt to disambiguate based on tokens later on in the input string.
+
+Command definitions:
+  show ip bgp A.B.C.D
+  show ipv6 bgp X:X::X:X
+
+User enters:
+  s i b 4.3.2.1         -> match "show ip bgp A.B.C.D"
+  s i b ::e0            -> match "show ipv6 bgp X:X::X:X"
+
+Previously both of these commands would be ambiguous since 'i' does not
+explicitly select either 'ip' or 'ipv6'. However, since the user later provides
+a token that matches only one of the commands (an IPv4 or IPv6 address) the
+parser is able to look ahead and select the appropriate command. This has some
+implications for parsing the argv*[] that is passed to the command handler.
+
+Now consider a command definition such as:
+  command <foo|VAR>
+
+'foo' only matches the string 'foo', but 'VAR' matches any input, including
+'foo'. Who wins? In situations like this the matcher will always choose the
+'better' match, so 'foo' will win.
+
+Consider also:
+  show <ip|ipv6> foo
+
+User input:
+  show ip foo
+
+'ip' partially matches 'ipv6' but exactly matches 'ip', so 'ip' will win.
+
+
+struct cmd_token
+----------------
+
+/* Command token struct. */
+struct cmd_token
+{
+  enum cmd_token_type type;     // token type
+  u_char attr;                  // token attributes
+  bool allowrepeat;             // matcher allowed to match token repetitively?
+
+  char *text;                   // token text
+  char *desc;                   // token description
+  long long min, max;           // for ranges
+  char *arg;                    // user input that matches this token
+};
+
+This struct is used in the CLI graph to match input against. It is also used to
+pass user input to command handler functions, as it is frequently useful for
+handlers to have access to that information. When a command is matched, the
+sequence of cmd_tokens that form the matching path are duplicated and placed in
+order into argv*[]. Before this happens the ->arg field is set to point at the
+snippet of user input that matched it.
+
+For most nontrivial commands the handler function will need to determine which
+of the possible matching inputs was entered. Previously this was done by
+looking at the first few characters of input. This is now considered an
+anti-pattern and should be avoided. Instead, the ->type or ->text fields for
+this logic. The ->type field can be used when the possible inputs differ in
+type. When the possible types are the same, use the ->text field. This field
+has the full text of the corresponding token in the definition string and using
+it makes for much more readable code. An example is helpful.
+
+Command definition:
+  command <(1-10)|foo|BAR>
+
+In this example, the user may enter any one of:
+  * an integer between 1 and 10
+  * "foo"
+  * anything at all
+
+If the user enters "command f", then:
+
+argv[1]->type == WORD_TKN
+argv[1]->arg  == "f"
+argv[1]->text == "foo"
+
+Range tokens have some special treatment; a token with ->type == RANGE_TKN will
+have the ->min and ->max fields set to the bounding values of the range.
+
+
+Permutations
+------------
+Finally, it is sometimes useful to check all the possible combinations of input
+that would match an arbitrary definition string. There is a tool in tools/
+called 'permutations' that reads CLI definition strings on stdin and prints out
+all matching input permutations. It also dumps a text representation of the
+graph, which is more useful for debugging than anything else. It looks like
+this:
+
+$ ./permutations "show [ip] bgp [<view|vrf> WORD]"
+
+show ip bgp view WORD
+show ip bgp vrf WORD
+show ip bgp
+show bgp view WORD
+show bgp vrf WORD
+show bgp
+
+This functionality is also built into VTY/VTYSH; the 'list permutations'
+command will list all possible matching input permutations in the current CLI
+node.
index 7b5d4f132e4d8010bbfce0544d71165e1fc80bf8..ba8f3df72021653e9177af43f0d0f950c3b257a1 100644 (file)
@@ -73,7 +73,7 @@ The default location of the
 .B vtysh
 config file.
 .TP
-.BI @CFG_SYSCONF@/Frr.conf
+.BI @CFG_SYSCONF@/frr.conf
 The default location of the integrated @PACKAGE_FULLNAME@ routing engine config file
 if integrated config file is in use (not default).
 .TP
index f3ebc26a128bf6f52d1ff734ca370de93c348406..de681c8013a28b8f3c876f4a8c9ba12889c306d0 100644 (file)
@@ -61,13 +61,13 @@ at all.
 @section Integrated configuration mode
 
 Integrated configuration mode uses a single configuration file,
-@file{Frr.conf}, for all daemons.  This replaces the individual files like
+@file{frr.conf}, for all daemons.  This replaces the individual files like
 @file{zebra.conf} or @file{bgpd.conf}.
 
-@file{Frr.conf} is located in @file{@value{INSTALL_PREFIX_ETC}}.  All
+@file{frr.conf} is located in @file{@value{INSTALL_PREFIX_ETC}}.  All
 daemons check for the existence of this file at startup, and if it exists
 will not load their individual configuration files.  Instead,
-@command{vtysh -b} must be invoked to process @file{Frr.conf} and apply
+@command{vtysh -b} must be invoked to process @file{frr.conf} and apply
 its settings to the individual daemons.
 
 @quotation Warning
@@ -76,7 +76,7 @@ its settings to the individual daemons.
 
 @subsection Configuration saving, file ownership and permissions
 
-The @file{Frr.conf} file is not written by any of the daemons; instead
+The @file{frr.conf} file is not written by any of the daemons; instead
 @command{vtysh} contains the neccessary logic to collect configuration from
 all of the daemons, combine it and write it out.
 
@@ -90,7 +90,7 @@ Since the @command{vtysh} command may be running as ordinary user on the
 system, configuration writes will be tried through @command{watchfrr},
 using the @command{write integrated} command internally.  Since
 @command{watchfrr} is running as superuser, @command{vtysh} is able to
-ensure correct ownership and permissions on @file{Frr.conf}.
+ensure correct ownership and permissions on @file{frr.conf}.
 
 If @command{watchfrr} is not running or the configuration write fails,
 @command{vtysh} will attempt to directly write to the file.  This is likely
@@ -102,7 +102,7 @@ Writing the configuration can be triggered directly by invoking
 should be run as either the superuser or the Frr user.
 
 We recommend you do not mix the use of the two types of files. Further, it
-is better not to use the integrated Frr.conf file, as any syntax error in
+is better not to use the integrated frr.conf file, as any syntax error in
 it can lead to /all/ of your daemons being unable to start up. Per daemon
 files are more robust as impact of errors in configuration are limited to
 the daemon in whose file the error is made.
@@ -110,7 +110,7 @@ the daemon in whose file the error is made.
 @deffn {Command} {service integrated-vtysh-config} {}
 @deffnx {Command} {no service integrated-vtysh-config} {}
 
-Control whether integrated @file{Frr.conf} file is written when
+Control whether integrated @file{frr.conf} file is written when
 'write file' is issued.
 
 These commands need to be placed in @file{vtysh.conf} to have any effect.
@@ -122,18 +122,18 @@ This command has 3 states:
 @item
 @command{service integrated-vtysh-config}
 
-@command{vtysh} will always write @file{Frr.conf}.
+@command{vtysh} will always write @file{frr.conf}.
 
 @item
 @command{no service integrated-vtysh-config}
 
-@command{vtysh} will never write @file{Frr.conf}; instead it will ask
+@command{vtysh} will never write @file{frr.conf}; instead it will ask
 daemons to write their individual configuration files.
 
 @item
 Neither option present (default)
 
-@command{vtysh} will check whether @file{Frr.conf} exists.  If it does,
+@command{vtysh} will check whether @file{frr.conf} exists.  If it does,
 configuration writes will update that file.  Otherwise, writes are performed
 through the individual daemons.
 @end itemize
@@ -146,7 +146,7 @@ installations.
 @deffn {Command} {write integrated} {}
 
 Unconditionally (regardless of @command{service integrated-vtysh-config}
-setting) write out integrated @file{Frr.conf} file through
+setting) write out integrated @file{frr.conf} file through
 @command{watchfrr}.  If @command{watchfrr} is not running, this command
 is unavailable.
 
@@ -156,6 +156,6 @@ is unavailable.
 
 Configuration changes made while some daemon is not running will be invisible
 to that daemon.  The daemon will start up with its saved configuration
-(either in its individual configuration file, or in @file{Frr.conf}).
+(either in its individual configuration file, or in @file{frr.conf}).
 This is particularly troublesome for route-maps and prefix lists, which would
 otherwise be synchronized between daemons.
index a038028d226a9fdd629b33adf7196bdfb2b65d47..56676edaf13a79bd8dcfe1a70ff2b348ae2f2fb5 100644 (file)
@@ -649,6 +649,7 @@ dnode_t *dict_delete(dict_t *dict, dnode_t *delete)
 
     if (delete->left != nil && delete->right != nil) {
        dnode_t *next = dict_next(dict, delete);
+       assert (next);
        dnode_t *nextparent = next->parent;
        dnode_color_t nextcolor = next->color;
 
index b138b8950c9b6ca0cb5e24a2c4985230a5d9c532..6207ae189aeb28c612328c72705bf85f06f26ae9 100644 (file)
@@ -306,12 +306,12 @@ isis_circuit_del_addr (struct isis_circuit *circuit,
       else
        {
          prefix2str (connected->address, buf, sizeof (buf));
-         zlog_warn ("Nonexitant ip address %s removal attempt from \
+         zlog_warn ("Nonexistant ip address %s removal attempt from \
                       circuit %d", buf, circuit->circuit_id);
          zlog_warn ("Current ip addresses on %s:", circuit->interface->name);
          for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, ip))
            {
-             prefix2str((struct prefix*)ip, (char *)buf, BUFSIZ);
+             prefix2str(ip, buf, sizeof(buf));
              zlog_warn("  %s", buf);
            }
          zlog_warn("End of addresses");
index da24a7f0d39e26c4e37d722f28378998386a1efd..f633a8fb78fb062602b684dcb1ef1aa11b25e0aa 100644 (file)
@@ -156,7 +156,6 @@ lsp_destroy (struct isis_lsp *lsp)
     }
 
   isis_spf_schedule (lsp->area, lsp->level);
-  isis_spf_schedule6 (lsp->area, lsp->level);
 
   if (lsp->pdu)
     stream_free (lsp->pdu);
@@ -425,7 +424,6 @@ lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)
                     ntohs (lsp->lsp_header->pdu_len) - 12, 12);
 
   isis_spf_schedule (lsp->area, lsp->level);
-  isis_spf_schedule6 (lsp->area, lsp->level);
 
   return;
 }
@@ -640,7 +638,6 @@ lsp_insert (struct isis_lsp *lsp, dict_t * lspdb)
   if (lsp->lsp_header->seq_num != 0)
     {
       isis_spf_schedule (lsp->area, lsp->level);
-      isis_spf_schedule6 (lsp->area, lsp->level);
     }
 }
 
@@ -2460,8 +2457,7 @@ lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level)
   int lvl;
   struct isis_area *area = circuit->area;
 
-  if (circuit == NULL ||
-      circuit->circ_type != CIRCUIT_T_BROADCAST ||
+  if (circuit->circ_type != CIRCUIT_T_BROADCAST ||
       circuit->state != C_STATE_UP)
     return ISIS_OK;
 
index e111a17deeef37628b3b3a21252e812ead37ce43..5fbf6c194ea72281d1e7729aa93503d73542e471 100644 (file)
@@ -2408,7 +2408,7 @@ send_lan_l1_hello (struct thread *thread)
     }
 
   if (circuit->u.bc.run_dr_elect[0])
-    retval = isis_dr_elect (circuit, 1);
+    isis_dr_elect (circuit, 1);
 
   retval = send_hello (circuit, 1);
 
@@ -2438,7 +2438,7 @@ send_lan_l2_hello (struct thread *thread)
     }
 
   if (circuit->u.bc.run_dr_elect[1])
-    retval = isis_dr_elect (circuit, 2);
+    isis_dr_elect (circuit, 2);
 
   retval = send_hello (circuit, 2);
 
index b2b858feb7deb43c9864339b159ee551ab455ff4..e3256f2d027ddd54072e9cf86b620e282fc97838 100644 (file)
@@ -570,6 +570,13 @@ isis_route_validate_merge (struct isis_area *area, int family)
     table = area->route_table[0];
   else if (family == AF_INET6)
     table = area->route_table6[0];
+  else
+    {
+      zlog_warn ("ISIS-Rte (%s) %s called for unknown family %d",
+                 area->area_tag, __func__, family);
+      route_table_finish(merge);
+      return;
+    }
 
   for (rnode = route_top (table); rnode; rnode = route_next (rnode))
     {
index c1fb062e5506b2d988fe9e23eba91d78f3c5ebc6..db46078f20c5ce06ed6c9d9f3752a3509ec56f83 100644 (file)
@@ -33,6 +33,7 @@
 #include "hash.h"
 #include "if.h"
 #include "table.h"
+#include "spf_backoff.h"
 
 #include "isis_constants.h"
 #include "isis_common.h"
@@ -50,9 +51,6 @@
 #include "isis_route.h"
 #include "isis_csm.h"
 
-int isis_run_spf_l1 (struct thread *thread);
-int isis_run_spf_l2 (struct thread *thread);
-
 /* 7.2.7 */
 static void
 remove_excess_adjs (struct list *adjs)
@@ -266,14 +264,12 @@ isis_spftree_new (struct isis_area *area)
   tree->last_run_timestamp = 0;
   tree->last_run_duration = 0;
   tree->runcount = 0;
-  tree->pending = 0;
   return tree;
 }
 
 void
 isis_spftree_del (struct isis_spftree *spftree)
 {
-  THREAD_TIMER_OFF (spftree->t_spf);
 
   spftree->tents->del = (void (*)(void *)) isis_vertex_del;
   list_delete (spftree->tents);
@@ -1240,7 +1236,6 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
 
 out:
   isis_route_validate (area);
-  spftree->pending = 0;
   spftree->runcount++;
   spftree->last_run_timestamp = time (NULL);
   monotime(&time_now);
@@ -1248,11 +1243,10 @@ out:
   end_time = (end_time * 1000000) + time_now.tv_usec;
   spftree->last_run_duration = end_time - start_time;
 
-
   return retval;
 }
 
-int
+static int
 isis_run_spf_l1 (struct thread *thread)
 {
   struct isis_area *area;
@@ -1261,8 +1255,7 @@ isis_run_spf_l1 (struct thread *thread)
   area = THREAD_ARG (thread);
   assert (area);
 
-  area->spftree[0]->t_spf = NULL;
-  area->spftree[0]->pending = 0;
+  area->spf_timer[0] = NULL;
 
   if (!(area->is_type & IS_LEVEL_1))
     {
@@ -1277,11 +1270,13 @@ isis_run_spf_l1 (struct thread *thread)
 
   if (area->ip_circuits)
     retval = isis_run_spf (area, 1, AF_INET, isis->sysid);
+  if (area->ipv6_circuits)
+    retval = isis_run_spf (area, 1, AF_INET6, isis->sysid);
 
   return retval;
 }
 
-int
+static int
 isis_run_spf_l2 (struct thread *thread)
 {
   struct isis_area *area;
@@ -1290,8 +1285,7 @@ isis_run_spf_l2 (struct thread *thread)
   area = THREAD_ARG (thread);
   assert (area);
 
-  area->spftree[1]->t_spf = NULL;
-  area->spftree[1]->pending = 0;
+  area->spf_timer[1] = NULL;
 
   if (!(area->is_type & IS_LEVEL_2))
     {
@@ -1305,6 +1299,8 @@ isis_run_spf_l2 (struct thread *thread)
 
   if (area->ip_circuits)
     retval = isis_run_spf (area, 2, AF_INET, isis->sysid);
+  if (area->ipv6_circuits)
+    retval = isis_run_spf (area, 2, AF_INET6, isis->sysid);
 
   return retval;
 }
@@ -1323,126 +1319,55 @@ isis_spf_schedule (struct isis_area *area, int level)
     zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
                 area->area_tag, level, diff);
 
-  if (spftree->pending)
-    return ISIS_OK;
-
-  THREAD_TIMER_OFF (spftree->t_spf);
-
-  /* wait configured min_spf_interval before doing the SPF */
-  if (diff >= area->min_spf_interval[level-1])
-      return isis_run_spf (area, level, AF_INET, isis->sysid);
-
-  if (level == 1)
-    THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
-                     area->min_spf_interval[0] - diff);
-  else
-    THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
-                     area->min_spf_interval[1] - diff);
-
-  if (isis->debugs & DEBUG_SPF_EVENTS)
-    zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
-                area->area_tag, level, area->min_spf_interval[level-1] - diff);
-
-  spftree->pending = 1;
-
-  return ISIS_OK;
-}
-
-static int
-isis_run_spf6_l1 (struct thread *thread)
-{
-  struct isis_area *area;
-  int retval = ISIS_OK;
-
-  area = THREAD_ARG (thread);
-  assert (area);
-
-  area->spftree6[0]->t_spf = NULL;
-  area->spftree6[0]->pending = 0;
-
-  if (!(area->is_type & IS_LEVEL_1))
+  if (area->spf_delay_ietf[level - 1])
     {
-      if (isis->debugs & DEBUG_SPF_EVENTS)
-        zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
-      return ISIS_WARNING;
-    }
-
-  if (isis->debugs & DEBUG_SPF_EVENTS)
-    zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
-
-  if (area->ipv6_circuits)
-    retval = isis_run_spf (area, 1, AF_INET6, isis->sysid);
+      /* Need to call schedule function also if spf delay is running to
+       * restart holdoff timer - compare draft-ietf-rtgwg-backoff-algo-04 */
+      long delay = spf_backoff_schedule(area->spf_delay_ietf[level -1]);
+      if (area->spf_timer[level - 1])
+        return ISIS_OK;
 
-  return retval;
-}
-
-static int
-isis_run_spf6_l2 (struct thread *thread)
-{
-  struct isis_area *area;
-  int retval = ISIS_OK;
-
-  area = THREAD_ARG (thread);
-  assert (area);
-
-  area->spftree6[1]->t_spf = NULL;
-  area->spftree6[1]->pending = 0;
-
-  if (!(area->is_type & IS_LEVEL_2))
-    {
-      if (isis->debugs & DEBUG_SPF_EVENTS)
-        zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
-      return ISIS_WARNING;
+      if (level == 1)
+        {
+          THREAD_TIMER_MSEC_ON(master, area->spf_timer[0],
+                               isis_run_spf_l1, area, delay);
+        }
+      else
+        {
+          THREAD_TIMER_MSEC_ON(master, area->spf_timer[1],
+                               isis_run_spf_l2, area, delay);
+        }
+      return ISIS_OK;
     }
 
-  if (isis->debugs & DEBUG_SPF_EVENTS)
-    zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area->area_tag);
-
-  if (area->ipv6_circuits)
-    retval = isis_run_spf (area, 2, AF_INET6, isis->sysid);
-
-  return retval;
-}
-
-int
-isis_spf_schedule6 (struct isis_area *area, int level)
-{
-  int retval = ISIS_OK;
-  struct isis_spftree *spftree = area->spftree6[level - 1];
-  time_t now = time (NULL);
-  time_t diff = now - spftree->last_run_timestamp;
-
-  assert (diff >= 0);
-  assert (area->is_type & level);
-
-  if (isis->debugs & DEBUG_SPF_EVENTS)
-    zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %lld sec ago",
-                area->area_tag, level, (long long)diff);
-
-  if (spftree->pending)
+  if (area->spf_timer[level -1])
     return ISIS_OK;
 
-  THREAD_TIMER_OFF (spftree->t_spf);
-
   /* wait configured min_spf_interval before doing the SPF */
   if (diff >= area->min_spf_interval[level-1])
-      return isis_run_spf (area, level, AF_INET6, isis->sysid);
+    {
+      int retval = ISIS_OK;
+
+      if (area->ip_circuits)
+        retval = isis_run_spf (area, level, AF_INET, isis->sysid);
+      if (area->ipv6_circuits)
+        retval = isis_run_spf (area, level, AF_INET6, isis->sysid);
+
+      return retval;
+    }
 
   if (level == 1)
-    THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
+    THREAD_TIMER_ON (master, area->spf_timer[0], isis_run_spf_l1, area,
                      area->min_spf_interval[0] - diff);
   else
-    THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
+    THREAD_TIMER_ON (master, area->spf_timer[1], isis_run_spf_l2, area,
                      area->min_spf_interval[1] - diff);
 
   if (isis->debugs & DEBUG_SPF_EVENTS)
-    zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %lld sec from now",
-                area->area_tag, level,
-               (long long)(area->min_spf_interval[level-1] - diff));
-
-  spftree->pending = 1;
+    zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
+                area->area_tag, level, area->min_spf_interval[level-1] - diff);
 
-  return retval;
+  return ISIS_OK;
 }
 
 static void
index 0e42cac81f0506772c388d7f3cb3747e7a44642d..fb534542d05dabde70039e96a2bab9bbe0d5f12a 100644 (file)
@@ -60,11 +60,9 @@ struct isis_vertex
 
 struct isis_spftree
 {
-  struct thread *t_spf;                /* spf threads */
   struct list *paths;          /* the SPT */
   struct list *tents;          /* TENT */
   struct isis_area *area;       /* back pointer to area */
-  int pending;                 /* already scheduled */
   unsigned int runcount;        /* number of runs since uptime */
   time_t last_run_timestamp;    /* last run timestamp for scheduling */
   time_t last_run_duration;     /* last run duration in msec */
@@ -80,5 +78,4 @@ void spftree_area_adj_del (struct isis_area *area,
                            struct isis_adjacency *adj);
 int isis_spf_schedule (struct isis_area *area, int level);
 void isis_spf_cmds_init (void);
-int isis_spf_schedule6 (struct isis_area *area, int level);
 #endif /* _ZEBRA_ISIS_SPF_H */
index 34cd8397f43670a169e383a1e7bf9f24cca22629..830ccb37c6d2cf8a673628fbbd56f3697b6417a4 100644 (file)
@@ -985,17 +985,15 @@ show_vty_unknown_tlv (struct vty *vty, struct subtlv_header *tlvh)
 void
 mpls_te_print_detail(struct vty *vty, struct te_is_neigh *te)
 {
-  struct subtlv_header *tlvh, *next;
+  struct subtlv_header *tlvh;
   u_int16_t sum = 0;
 
   zlog_debug ("ISIS MPLS-TE: Show database TE detail");
 
   tlvh = (struct subtlv_header *)te->sub_tlvs;
 
-  for (; sum < te->sub_tlvs_length; tlvh = (next ? next : SUBTLV_HDR_NEXT (tlvh)))
+  for (; sum < te->sub_tlvs_length; tlvh = SUBTLV_HDR_NEXT (tlvh))
     {
-      next = NULL;
-
       switch (tlvh->type)
       {
       case TE_SUBTLV_ADMIN_GRP:
@@ -1223,13 +1221,10 @@ DEFUN (show_isis_mpls_te_router,
     {
       vty_out (vty, "--- MPLS-TE router parameters ---%s", VTY_NEWLINE);
 
-      if (vty != NULL)
-        {
-          if (ntohs (isisMplsTE.router_id.s_addr) != 0)
-            vty_out (vty, "  Router-Address: %s%s", inet_ntoa (isisMplsTE.router_id), VTY_NEWLINE);
-          else
-            vty_out (vty, "  N/A%s", VTY_NEWLINE);
-        }
+      if (ntohs (isisMplsTE.router_id.s_addr) != 0)
+        vty_out (vty, "  Router-Address: %s%s", inet_ntoa (isisMplsTE.router_id), VTY_NEWLINE);
+      else
+        vty_out (vty, "  N/A%s", VTY_NEWLINE);
     }
   else
     vty_out (vty, "  MPLS-TE is disable on this router%s", VTY_NEWLINE);
index 848c56a6acf606a6024ff01cf62e49a9151fc1cd..721959859a0cb46b31f1d154091b6c0d500778f5 100644 (file)
@@ -22,7 +22,9 @@
  */
 
 #include <zebra.h>
-#include <command.h>
+
+#include "command.h"
+#include "spf_backoff.h"
 
 #include "isis_circuit.h"
 #include "isis_csm.h"
@@ -1707,6 +1709,63 @@ DEFUN (no_spf_interval_l2,
   return CMD_SUCCESS;
 }
 
+DEFUN (no_spf_delay_ietf,
+       no_spf_delay_ietf_cmd,
+       "no spf-delay-ietf",
+       NO_STR
+       "IETF SPF delay algorithm\n")
+{
+  VTY_DECLVAR_CONTEXT (isis_area, area);
+
+  spf_backoff_free(area->spf_delay_ietf[0]);
+  spf_backoff_free(area->spf_delay_ietf[1]);
+  area->spf_delay_ietf[0] = NULL;
+  area->spf_delay_ietf[1] = NULL;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (spf_delay_ietf,
+       spf_delay_ietf_cmd,
+       "spf-delay-ietf init-delay (0-60000) short-delay (0-60000) long-delay (0-60000) holddown (0-60000) time-to-learn (0-60000)",
+       "IETF SPF delay algorithm\n"
+       "Delay used while in QUIET state\n"
+       "Delay used while in QUIET state in milliseconds\n"
+       "Delay used while in SHORT_WAIT state\n"
+       "Delay used while in SHORT_WAIT state in milliseconds\n"
+       "Delay used while in LONG_WAIT\n"
+       "Delay used while in LONG_WAIT state in milliseconds\n"
+       "Time with no received IGP events before considering IGP stable\n"
+       "Time with no received IGP events before considering IGP stable (in milliseconds)\n"
+       "Maximum duration needed to learn all the events related to a single failure\n"
+       "Maximum duration needed to learn all the events related to a single failure (in milliseconds)\n")
+{
+  VTY_DECLVAR_CONTEXT (isis_area, area);
+
+  long init_delay = atol(argv[2]->arg);
+  long short_delay = atol(argv[4]->arg);
+  long long_delay = atol(argv[6]->arg);
+  long holddown = atol(argv[8]->arg);
+  long timetolearn = atol(argv[10]->arg);
+
+  size_t bufsiz = strlen(area->area_tag) + sizeof("IS-IS  Lx");
+  char *buf = XCALLOC(MTYPE_TMP, bufsiz);
+
+  snprintf(buf, bufsiz, "IS-IS %s L1", area->area_tag);
+  spf_backoff_free(area->spf_delay_ietf[0]);
+  area->spf_delay_ietf[0] = spf_backoff_new(master, buf, init_delay,
+                                            short_delay, long_delay,
+                                            holddown, timetolearn);
+
+  snprintf(buf, bufsiz, "IS-IS %s L2", area->area_tag);
+  spf_backoff_free(area->spf_delay_ietf[1]);
+  area->spf_delay_ietf[1] = spf_backoff_new(master, buf, init_delay,
+                                            short_delay, long_delay,
+                                            holddown, timetolearn);
+
+  XFREE(MTYPE_TMP, buf);
+  return CMD_SUCCESS;
+}
 
 static int
 area_max_lsp_lifetime_set(struct vty *vty, int level,
@@ -2096,4 +2155,8 @@ isis_vty_init (void)
   install_element (ISIS_NODE, &domain_passwd_md5_cmd);
   install_element (ISIS_NODE, &domain_passwd_clear_cmd);
   install_element (ISIS_NODE, &no_area_passwd_cmd);
+
+  install_element (ISIS_NODE, &spf_delay_ietf_cmd);
+  install_element (ISIS_NODE, &no_spf_delay_ietf_cmd);
+
 }
index 9bef25088308ac353e9dca3e6128569251c97c62..2863d2f67885cbd0c7bd81a3289292d834204bad 100644 (file)
@@ -35,6 +35,7 @@
 #include "prefix.h"
 #include "table.h"
 #include "qobj.h"
+#include "spf_backoff.h"
 
 #include "isisd/dict.h"
 #include "isisd/isis_constants.h"
@@ -245,6 +246,12 @@ isis_area_destroy (struct vty *vty, const char *area_tag)
 
   spftree_area_del (area);
 
+  THREAD_TIMER_OFF(area->spf_timer[0]);
+  THREAD_TIMER_OFF(area->spf_timer[1]);
+
+  spf_backoff_free(area->spf_delay_ietf[0]);
+  spf_backoff_free(area->spf_delay_ietf[1]);
+
   /* invalidate and validate would delete all routes from zebra */
   isis_route_invalidate (area);
   isis_route_validate (area);
@@ -856,6 +863,7 @@ config_write_debug (struct vty *vty)
       vty_out (vty, "debug isis lsp-sched%s", VTY_NEWLINE);
       write++;
     }
+  write += spf_backoff_write_config(vty);
 
   return write;
 }
@@ -1273,6 +1281,57 @@ vty_out_timestr(struct vty *vty, time_t uptime)
   vty_out (vty, " ago");
 }
 
+DEFUN (show_isis_spf_ietf,
+       show_isis_spf_ietf_cmd,
+       "show isis spf-delay-ietf",
+       SHOW_STR
+       "IS-IS information\n"
+       "IS-IS SPF delay IETF information\n")
+{
+  if (!isis)
+    {
+      vty_out (vty, "ISIS is not running%s", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  struct listnode *node;
+  struct isis_area *area;
+
+  for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
+    {
+      vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
+               VTY_NEWLINE);
+
+      for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
+        {
+          if ((area->is_type & level) == 0)
+            continue;
+
+          vty_out (vty, "  Level-%d:%s", level, VTY_NEWLINE);
+          vty_out (vty, "    SPF delay status: ");
+          if (area->spf_timer[level -1])
+            {
+              struct timeval remain = thread_timer_remain(area->spf_timer[level - 1]);
+              vty_out(vty, "Pending, due in %ld msec%s",
+                      remain.tv_sec * 1000 + remain.tv_usec / 1000,
+                      VTY_NEWLINE);
+            }
+          else
+            {
+              vty_out(vty, "Not scheduled%s", VTY_NEWLINE);
+            }
+
+          if (area->spf_delay_ietf[level - 1]) {
+            vty_out(vty,  "    Using draft-ietf-rtgwg-backoff-algo-04%s", VTY_NEWLINE);
+            spf_backoff_show(area->spf_delay_ietf[level - 1], vty, "    ");
+          } else {
+            vty_out(vty,  "    Using legacy backoff algo%s", VTY_NEWLINE);
+          }
+        }
+    }
+  return CMD_SUCCESS;
+}
+
 DEFUN (show_isis_summary,
        show_isis_summary_cmd,
        "show isis summary",
@@ -1327,14 +1386,18 @@ DEFUN (show_isis_summary,
 
       vty_out (vty, "  Level-%d:%s", level, VTY_NEWLINE);
       spftree = area->spftree[level - 1];
-      if (spftree->pending)
-        vty_out (vty, "    IPv4 SPF: (pending)%s", VTY_NEWLINE);
+      if (area->spf_timer[level - 1])
+        vty_out (vty, "    SPF: (pending)%s", VTY_NEWLINE);
       else
-        vty_out (vty, "    IPv4 SPF:%s", VTY_NEWLINE);
+        vty_out (vty, "    SPF:%s", VTY_NEWLINE);
 
-      vty_out (vty, "      minimum interval  : %d%s",
-          area->min_spf_interval[level - 1], VTY_NEWLINE);
+      vty_out (vty, "      minimum interval  : %d",
+          area->min_spf_interval[level - 1]);
+      if (area->spf_delay_ietf[level - 1])
+         vty_out (vty, " (not used, IETF SPF delay activated)");
+      vty_out (vty, VTY_NEWLINE);
 
+      vty_out (vty, "    IPv4 route computation:%s", VTY_NEWLINE);
       vty_out (vty, "      last run elapsed  : ");
       vty_out_timestr(vty, spftree->last_run_timestamp);
       vty_out (vty, "%s", VTY_NEWLINE);
@@ -1346,13 +1409,7 @@ DEFUN (show_isis_summary,
           spftree->runcount, VTY_NEWLINE);
 
       spftree = area->spftree6[level - 1];
-      if (spftree->pending)
-        vty_out (vty, "    IPv6 SPF: (pending)%s", VTY_NEWLINE);
-      else
-        vty_out (vty, "    IPv6 SPF:%s", VTY_NEWLINE);
-
-      vty_out (vty, "      minimum interval  : %d%s",
-          area->min_spf_interval[level - 1], VTY_NEWLINE);
+      vty_out (vty, "    IPv6 route computation:%s", VTY_NEWLINE);
 
       vty_out (vty, "      last run elapsed  : ");
       vty_out_timestr(vty, spftree->last_run_timestamp);
@@ -1651,6 +1708,7 @@ area_resign_level (struct isis_area *area, int level)
       isis_spftree_del (area->spftree6[level - 1]);
       area->spftree6[level - 1] = NULL;
     }
+  THREAD_TIMER_OFF(area->spf_timer[level - 1]);
   if (area->route_table[level - 1])
     {
       route_table_finish (area->route_table[level - 1]);
@@ -2010,6 +2068,20 @@ isis_config_write (struct vty *vty)
                write++;
              }
          }
+
+       /* IETF SPF interval */
+       if (area->spf_delay_ietf[0])
+         {
+           vty_out (vty, " spf-delay-ietf init-delay %ld short-delay %ld long-delay %ld holddown %ld time-to-learn %ld%s",
+                    spf_backoff_init_delay(area->spf_delay_ietf[0]),
+                    spf_backoff_short_delay(area->spf_delay_ietf[0]),
+                    spf_backoff_long_delay(area->spf_delay_ietf[0]),
+                    spf_backoff_holddown(area->spf_delay_ietf[0]),
+                    spf_backoff_timetolearn(area->spf_delay_ietf[0]),
+                    VTY_NEWLINE);
+           write++;
+         }
+
        /* Authentication passwords. */
        if (area->area_passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
          {
@@ -2097,6 +2169,8 @@ isis_init ()
 
   install_element (VIEW_NODE, &show_isis_summary_cmd);
 
+  install_element (VIEW_NODE, &show_isis_spf_ietf_cmd);
+
   install_element (VIEW_NODE, &show_isis_interface_cmd);
   install_element (VIEW_NODE, &show_isis_interface_detail_cmd);
   install_element (VIEW_NODE, &show_isis_interface_arg_cmd);
@@ -2182,4 +2256,6 @@ isis_init ()
 
   install_element (ISIS_NODE, &log_adj_changes_cmd);
   install_element (ISIS_NODE, &no_log_adj_changes_cmd);
+
+  spf_backoff_cmd_init();
 }
index efbfafc5fbd7803f8a27dd2cd571f14032eb9978..e1d3a69f8dcc5e4ac7bf8ab6f71b9cfdf80ccf35 100644 (file)
@@ -127,6 +127,9 @@ struct isis_area
                                     [ZEBRA_ROUTE_MAX + 1][ISIS_LEVELS];
   struct route_table *ext_reach[REDIST_PROTOCOL_COUNT][ISIS_LEVELS];
 
+  struct spf_backoff *spf_delay_ietf[ISIS_LEVELS]; /*Structure with IETF SPF algo parameters*/
+  struct thread *spf_timer[ISIS_LEVELS];
+
   QOBJ_FIELDS
 };
 DECLARE_QOBJ_TYPE(isis_area)
index 1c4c116f216f7ecd6d1cad73a473620bd88dec35..ad23ca690bf5eacdee4249932063d0ebd719f29e 100644 (file)
 
 static void     send_address(struct nbr *, int, struct if_addr_head *,
                    unsigned int, int);
-static int      gen_address_list_tlv(struct ibuf *, uint16_t, int,
-                   struct if_addr_head *, unsigned int);
+static int      gen_address_list_tlv(struct ibuf *, int, struct if_addr_head *,
+                   unsigned int);
+static int      gen_mac_list_tlv(struct ibuf *, uint8_t *);
 static void     address_list_add(struct if_addr_head *, struct if_addr *);
 static void     address_list_clr(struct if_addr_head *);
+static void     log_msg_address(int, uint16_t, struct nbr *, int,
+                   union ldpd_addr *);
+static void     log_msg_mac_withdrawal(int, struct nbr *, uint8_t *);
 
 static void
 send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
@@ -83,8 +87,7 @@ send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
                size -= LDP_HDR_SIZE;
                err |= gen_msg_hdr(buf, msg_type, size);
                size -= LDP_MSG_SIZE;
-               err |= gen_address_list_tlv(buf, size, af, addr_list,
-                   tlv_addr_count);
+               err |= gen_address_list_tlv(buf, af, addr_list, tlv_addr_count);
                if (err) {
                        address_list_clr(addr_list);
                        ibuf_free(buf);
@@ -92,9 +95,7 @@ send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
                }
 
                while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
-                       debug_msg_send("%s: lsr-id %s address %s",
-                           msg_name(msg_type), inet_ntoa(nbr->id),
-                           log_addr(af, &if_addr->addr));
+                       log_msg_address(1, msg_type, nbr, af, &if_addr->addr);
 
                        LIST_REMOVE(if_addr, entry);
                        free(if_addr);
@@ -137,16 +138,63 @@ send_address_all(struct nbr *nbr, int af)
        send_address(nbr, af, &addr_list, addr_count, 0);
 }
 
+void
+send_mac_withdrawal(struct nbr *nbr, struct map *fec, uint8_t *mac)
+{
+       struct ibuf     *buf;
+       uint16_t         size;
+       int              err;
+
+       size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE + len_fec_tlv(fec) +
+           TLV_HDR_SIZE;
+       if (mac)
+               size += ETHER_ADDR_LEN;
+
+       if ((buf = ibuf_open(size)) == NULL)
+               fatal(__func__);
+
+       err = gen_ldp_hdr(buf, size);
+       size -= LDP_HDR_SIZE;
+       err |= gen_msg_hdr(buf, MSG_TYPE_ADDRWITHDRAW, size);
+       size -= LDP_MSG_SIZE;
+       err |= gen_address_list_tlv(buf, AF_INET, NULL, 0);
+       err |= gen_fec_tlv(buf, fec);
+       err |= gen_mac_list_tlv(buf, mac);
+       if (err) {
+               ibuf_free(buf);
+               return;
+       }
+
+       log_msg_mac_withdrawal(1, nbr, mac);
+
+       evbuf_enqueue(&nbr->tcp->wbuf, buf);
+
+       nbr_fsm(nbr, NBR_EVT_PDU_SENT);
+}
+
 int
 recv_address(struct nbr *nbr, char *buf, uint16_t len)
 {
        struct ldp_msg          msg;
        uint16_t                msg_type;
-       struct address_list_tlv alt;
        enum imsg_type          type;
+       struct address_list_tlv alt;
+       uint16_t                alt_len;
+       uint16_t                alt_family;
        struct lde_addr         lde_addr;
 
        memcpy(&msg, buf, sizeof(msg));
+       msg_type = ntohs(msg.type);
+       switch (msg_type) {
+       case MSG_TYPE_ADDR:
+               type = IMSG_ADDRESS_ADD;
+               break;
+       case MSG_TYPE_ADDRWITHDRAW:
+               type = IMSG_ADDRESS_DEL;
+               break;
+       default:
+               fatalx("recv_address: unexpected msg type");
+       }
        buf += LDP_MSG_SIZE;
        len -= LDP_MSG_SIZE;
 
@@ -155,17 +203,18 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
                session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
                return (-1);
        }
-
        memcpy(&alt, buf, sizeof(alt));
-       if (ntohs(alt.length) != len - TLV_HDR_SIZE) {
+       alt_len = ntohs(alt.length);
+       alt_family = ntohs(alt.family);
+       if (alt_len > len - TLV_HDR_SIZE) {
                session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
                return (-1);
        }
        if (ntohs(alt.type) != TLV_TYPE_ADDRLIST) {
-               session_shutdown(nbr, S_UNKNOWN_TLV, msg.id, msg.type);
+               send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
                return (-1);
        }
-       switch (ntohs(alt.family)) {
+       switch (alt_family) {
        case AF_IPV4:
                if (!nbr->v4_enabled)
                        /* just ignore the message */
@@ -177,22 +226,18 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
                        return (0);
                break;
        default:
-               send_notification_nbr(nbr, S_UNSUP_ADDR, msg.id, msg.type);
+               send_notification(nbr->tcp, S_UNSUP_ADDR, msg.id, msg.type);
                return (-1);
        }
+       alt_len -= sizeof(alt.family);
        buf += sizeof(alt);
        len -= sizeof(alt);
 
-       msg_type = ntohs(msg.type);
-       if (msg_type == MSG_TYPE_ADDR)
-               type = IMSG_ADDRESS_ADD;
-       else
-               type = IMSG_ADDRESS_DEL;
-
-       while (len > 0) {
-               switch (ntohs(alt.family)) {
+       /* Process all received addresses */
+       while (alt_len > 0) {
+               switch (alt_family) {
                case AF_IPV4:
-                       if (len < sizeof(struct in_addr)) {
+                       if (alt_len < sizeof(struct in_addr)) {
                                session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
                                    msg.type);
                                return (-1);
@@ -204,9 +249,10 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
 
                        buf += sizeof(struct in_addr);
                        len -= sizeof(struct in_addr);
+                       alt_len -= sizeof(struct in_addr);
                        break;
                case AF_IPV6:
-                       if (len < sizeof(struct in6_addr)) {
+                       if (alt_len < sizeof(struct in6_addr)) {
                                session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
                                    msg.type);
                                return (-1);
@@ -218,24 +264,57 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
 
                        buf += sizeof(struct in6_addr);
                        len -= sizeof(struct in6_addr);
+                       alt_len -= sizeof(struct in6_addr);
                        break;
                default:
                        fatalx("recv_address: unknown af");
                }
 
-               debug_msg_recv("%s: lsr-id %s address %s", msg_name(msg_type),
-                   inet_ntoa(nbr->id), log_addr(lde_addr.af, &lde_addr.addr));
+               log_msg_address(0, msg_type, nbr, lde_addr.af, &lde_addr.addr);
 
                ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr,
                    sizeof(lde_addr));
        }
 
+       /* Optional Parameters */
+       while (len > 0) {
+               struct tlv      tlv;
+               uint16_t        tlv_type;
+               uint16_t        tlv_len;
+
+               if (len < sizeof(tlv)) {
+                       session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+                       return (-1);
+               }
+
+               memcpy(&tlv, buf, TLV_HDR_SIZE);
+               tlv_type = ntohs(tlv.type);
+               tlv_len = ntohs(tlv.length);
+               if (tlv_len + TLV_HDR_SIZE > len) {
+                       session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+                       return (-1);
+               }
+               buf += TLV_HDR_SIZE;
+               len -= TLV_HDR_SIZE;
+
+               switch (tlv_type) {
+               default:
+                       if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
+                               send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
+                                   msg.id, msg.type, tlv_type, tlv_len, buf);
+                       /* ignore unknown tlv */
+                       break;
+               }
+               buf += tlv_len;
+               len -= tlv_len;
+       }
+
        return (0);
 }
 
 static int
-gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
-    struct if_addr_head *addr_list, unsigned int tlv_addr_count)
+gen_address_list_tlv(struct ibuf *buf, int af, struct if_addr_head *addr_list,
+    unsigned int tlv_addr_count)
 {
        struct address_list_tlv  alt;
        uint16_t                 addr_size;
@@ -243,8 +322,7 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
        int                      err = 0;
 
        memset(&alt, 0, sizeof(alt));
-       alt.type = TLV_TYPE_ADDRLIST;
-       alt.length = htons(size - TLV_HDR_SIZE);
+       alt.type = htons(TLV_TYPE_ADDRLIST);
 
        switch (af) {
        case AF_INET:
@@ -258,8 +336,12 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
        default:
                fatalx("gen_address_list_tlv: unknown af");
        }
+       alt.length = htons(sizeof(alt.family) + addr_size * tlv_addr_count);
 
        err |= ibuf_add(buf, &alt, sizeof(alt));
+       if (addr_list == NULL)
+               return (err);
+
        LIST_FOREACH(if_addr, addr_list, entry) {
                err |= ibuf_add(buf, &if_addr->addr, addr_size);
                if (--tlv_addr_count == 0)
@@ -269,6 +351,23 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
        return (err);
 }
 
+static int
+gen_mac_list_tlv(struct ibuf *buf, uint8_t *mac)
+{
+       struct tlv       tlv;
+       int              err;
+
+       memset(&tlv, 0, sizeof(tlv));
+       tlv.type = htons(TLV_TYPE_MAC_LIST);
+       if (mac)
+               tlv.length = htons(ETHER_ADDR_LEN);
+       err = ibuf_add(buf, &tlv, sizeof(tlv));
+       if (mac)
+               err |= ibuf_add(buf, mac, ETHER_ADDR_LEN);
+
+       return (err);
+}
+
 static void
 address_list_add(struct if_addr_head *addr_list, struct if_addr *if_addr)
 {
@@ -292,3 +391,21 @@ address_list_clr(struct if_addr_head *addr_list)
                free(if_addr);
        }
 }
+
+static void
+log_msg_address(int out, uint16_t msg_type, struct nbr *nbr, int af,
+    union ldpd_addr *addr)
+{
+       debug_msg(out, "%s: lsr-id %s, address %s", msg_name(msg_type),
+           inet_ntoa(nbr->id), log_addr(af, addr));
+}
+
+static void
+log_msg_mac_withdrawal(int out, struct nbr *nbr, uint8_t *mac)
+{
+       char buf[ETHER_ADDR_STRLEN];
+
+       debug_msg(out, "mac withdrawal: lsr-id %s, mac %s", inet_ntoa(nbr->id),
+           (mac) ? prefix_mac2str((struct ethaddr *)mac, buf, sizeof(buf)) :
+           "wildcard");
+}
index 8a2280be07bf54ae36e0d1bb91655a635415bb53..0bfe0abc9de56bba7c67adeb2e879e40d63e03d6 100644 (file)
@@ -148,9 +148,10 @@ control_connbyfd(int fd)
 {
        struct ctl_conn *c;
 
-       for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd;
-           c = TAILQ_NEXT(c, entry))
-               ;       /* nothing */
+       TAILQ_FOREACH(c, &ctl_conns, entry) {
+               if (c->iev.ibuf.fd == fd)
+                       break;
+       }
 
        return (c);
 }
@@ -160,9 +161,10 @@ control_connbypid(pid_t pid)
 {
        struct ctl_conn *c;
 
-       for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.pid != pid;
-           c = TAILQ_NEXT(c, entry))
-               ;       /* nothing */
+       TAILQ_FOREACH(c, &ctl_conns, entry) {
+               if (c->iev.ibuf.pid == pid)
+                       break;
+       }
 
        return (c);
 }
index ed6b53c02db95995a5b031015f0cac91d8f8e13c..bc3a69edc7c032b57d7004be409ae769c9731a5e 100644 (file)
@@ -24,6 +24,9 @@
 #include "ldp_debug.h"
 
 static int     gen_init_prms_tlv(struct ibuf *, struct nbr *);
+static int     gen_cap_dynamic_tlv(struct ibuf *);
+static int     gen_cap_twcard_tlv(struct ibuf *, int);
+static int     gen_cap_unotif_tlv(struct ibuf *, int);
 
 void
 send_init(struct nbr *nbr)
@@ -34,15 +37,18 @@ send_init(struct nbr *nbr)
 
        debug_msg_send("initialization: lsr-id %s", inet_ntoa(nbr->id));
 
-       size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE;
+       size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE +
+           CAP_TLV_DYNAMIC_SIZE + CAP_TLV_TWCARD_SIZE + CAP_TLV_UNOTIF_SIZE;
        if ((buf = ibuf_open(size)) == NULL)
                fatal(__func__);
 
        err |= gen_ldp_hdr(buf, size);
        size -= LDP_HDR_SIZE;
        err |= gen_msg_hdr(buf, MSG_TYPE_INIT, size);
-       size -= LDP_MSG_SIZE;
        err |= gen_init_prms_tlv(buf, nbr);
+       err |= gen_cap_dynamic_tlv(buf);
+       err |= gen_cap_twcard_tlv(buf, 1);
+       err |= gen_cap_unotif_tlv(buf, 1);
        if (err) {
                ibuf_free(buf);
                return;
@@ -57,6 +63,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
        struct ldp_msg          msg;
        struct sess_prms_tlv    sess;
        uint16_t                max_pdu_len;
+       int                     caps_rcvd = 0;
 
        debug_msg_recv("initialization: lsr-id %s", inet_ntoa(nbr->id));
 
@@ -93,6 +100,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
        /* Optional Parameters */
        while (len > 0) {
                struct tlv      tlv;
+               uint16_t        tlv_type;
                uint16_t        tlv_len;
 
                if (len < sizeof(tlv)) {
@@ -101,6 +109,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
                }
 
                memcpy(&tlv, buf, TLV_HDR_SIZE);
+               tlv_type = ntohs(tlv.type);
                tlv_len = ntohs(tlv.length);
                if (tlv_len + TLV_HDR_SIZE > len) {
                        session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
@@ -109,17 +118,81 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
                buf += TLV_HDR_SIZE;
                len -= TLV_HDR_SIZE;
 
-               switch (ntohs(tlv.type)) {
+               /*
+                * RFC 5561 - Section 6:
+                * "The S-bit of a Capability Parameter in an Initialization
+                * message MUST be 1 and SHOULD be ignored on receipt".
+                */
+               switch (tlv_type) {
                case TLV_TYPE_ATMSESSIONPAR:
                        session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
                        return (-1);
                case TLV_TYPE_FRSESSION:
                        session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
                        return (-1);
+               case TLV_TYPE_DYNAMIC_CAP:
+                       if (tlv_len != CAP_TLV_DYNAMIC_LEN) {
+                               session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
+                                   msg.type);
+                               return (-1);
+                       }
+
+                       if (caps_rcvd & F_CAP_TLV_RCVD_DYNAMIC) {
+                               session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
+                                   msg.type);
+                               return (-1);
+                       }
+                       caps_rcvd |= F_CAP_TLV_RCVD_DYNAMIC;
+
+                       nbr->flags |= F_NBR_CAP_DYNAMIC;
+
+                       log_debug("%s: lsr-id %s announced the Dynamic "
+                           "Capability Announcement capability", __func__,
+                           inet_ntoa(nbr->id));
+                       break;
+               case TLV_TYPE_TWCARD_CAP:
+                       if (tlv_len != CAP_TLV_TWCARD_LEN) {
+                               session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
+                                   msg.type);
+                               return (-1);
+                       }
+
+                       if (caps_rcvd & F_CAP_TLV_RCVD_TWCARD) {
+                               session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
+                                   msg.type);
+                               return (-1);
+                       }
+                       caps_rcvd |= F_CAP_TLV_RCVD_TWCARD;
+
+                       nbr->flags |= F_NBR_CAP_TWCARD;
+
+                       log_debug("%s: lsr-id %s announced the Typed Wildcard "
+                           "FEC capability", __func__, inet_ntoa(nbr->id));
+                       break;
+               case TLV_TYPE_UNOTIF_CAP:
+                       if (tlv_len != CAP_TLV_UNOTIF_LEN) {
+                               session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
+                                   msg.type);
+                               return (-1);
+                       }
+
+                       if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) {
+                               session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
+                                   msg.type);
+                               return (-1);
+                       }
+                       caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF;
+
+                       nbr->flags |= F_NBR_CAP_UNOTIF;
+
+                       log_debug("%s: lsr-id %s announced the Unrecognized "
+                           "Notification capability", __func__,
+                           inet_ntoa(nbr->id));
+                       break;
                default:
                        if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
-                               send_notification_nbr(nbr, S_UNKNOWN_TLV,
-                                   msg.id, msg.type);
+                               send_notification_rtlvs(nbr, S_UNSSUPORTDCAP,
+                                   msg.id, msg.type, tlv_type, tlv_len, buf);
                        /* ignore unknown tlv */
                        break;
                }
@@ -145,6 +218,164 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
        return (0);
 }
 
+void
+send_capability(struct nbr *nbr, uint16_t capability, int enable)
+{
+       struct ibuf             *buf;
+       uint16_t                 size;
+       int                      err = 0;
+
+       log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
+
+       size = LDP_HDR_SIZE + LDP_MSG_SIZE + CAP_TLV_DYNAMIC_SIZE;
+       if ((buf = ibuf_open(size)) == NULL)
+               fatal(__func__);
+
+       err |= gen_ldp_hdr(buf, size);
+       size -= LDP_HDR_SIZE;
+       err |= gen_msg_hdr(buf, MSG_TYPE_CAPABILITY, size);
+
+       switch (capability) {
+       case TLV_TYPE_TWCARD_CAP:
+               err |= gen_cap_twcard_tlv(buf, enable);
+               break;
+       case TLV_TYPE_UNOTIF_CAP:
+               err |= gen_cap_unotif_tlv(buf, enable);
+               break;
+       case TLV_TYPE_DYNAMIC_CAP:
+               /*
+                * RFC 5561 - Section 9:
+                * "An LDP speaker MUST NOT include the Dynamic Capability
+                * Announcement Parameter in Capability messages sent to
+                * its peers".
+                */
+               /* FALLTHROUGH */
+       default:
+               fatalx("send_capability: unsupported capability");
+       }
+
+       if (err) {
+               ibuf_free(buf);
+               return;
+       }
+
+       evbuf_enqueue(&nbr->tcp->wbuf, buf);
+       nbr_fsm(nbr, NBR_EVT_PDU_SENT);
+}
+
+int
+recv_capability(struct nbr *nbr, char *buf, uint16_t len)
+{
+       struct ldp_msg   msg;
+       int              enable = 0;
+       int              caps_rcvd = 0;
+
+       log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
+
+       memcpy(&msg, buf, sizeof(msg));
+       buf += LDP_MSG_SIZE;
+       len -= LDP_MSG_SIZE;
+
+       /* Optional Parameters */
+       while (len > 0) {
+               struct tlv       tlv;
+               uint16_t         tlv_type;
+               uint16_t         tlv_len;
+               uint8_t          reserved;
+
+               if (len < sizeof(tlv)) {
+                       session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+                       return (-1);
+               }
+
+               memcpy(&tlv, buf, TLV_HDR_SIZE);
+               tlv_type = ntohs(tlv.type);
+               tlv_len = ntohs(tlv.length);
+               if (tlv_len + TLV_HDR_SIZE > len) {
+                       session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+                       return (-1);
+               }
+               buf += TLV_HDR_SIZE;
+               len -= TLV_HDR_SIZE;
+
+               switch (tlv_type) {
+               case TLV_TYPE_TWCARD_CAP:
+                       if (tlv_len != CAP_TLV_TWCARD_LEN) {
+                               session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
+                                   msg.type);
+                               return (-1);
+                       }
+
+                       if (caps_rcvd & F_CAP_TLV_RCVD_TWCARD) {
+                               session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
+                                   msg.type);
+                               return (-1);
+                       }
+                       caps_rcvd |= F_CAP_TLV_RCVD_TWCARD;
+
+                       memcpy(&reserved, buf, sizeof(reserved));
+                       enable = reserved & STATE_BIT;
+                       if (enable)
+                               nbr->flags |= F_NBR_CAP_TWCARD;
+                       else
+                               nbr->flags &= ~F_NBR_CAP_TWCARD;
+
+                       log_debug("%s: lsr-id %s %s the Typed Wildcard FEC "
+                           "capability", __func__, inet_ntoa(nbr->id),
+                           (enable) ? "announced" : "withdrew");
+                       break;
+               case TLV_TYPE_UNOTIF_CAP:
+                       if (tlv_len != CAP_TLV_UNOTIF_LEN) {
+                               session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
+                                   msg.type);
+                               return (-1);
+                       }
+
+                       if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) {
+                               session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
+                                   msg.type);
+                               return (-1);
+                       }
+                       caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF;
+
+                       memcpy(&reserved, buf, sizeof(reserved));
+                       enable = reserved & STATE_BIT;
+                       if (enable)
+                               nbr->flags |= F_NBR_CAP_UNOTIF;
+                       else
+                               nbr->flags &= ~F_NBR_CAP_UNOTIF;
+
+                       log_debug("%s: lsr-id %s %s the Unrecognized "
+                           "Notification capability", __func__,
+                           inet_ntoa(nbr->id), (enable) ? "announced" :
+                           "withdrew");
+                       break;
+               case TLV_TYPE_DYNAMIC_CAP:
+                       /*
+                        * RFC 5561 - Section 9:
+                        * "An LDP speaker that receives a Capability message
+                        * from a peer that includes the Dynamic Capability
+                        * Announcement Parameter SHOULD silently ignore the
+                        * parameter and process any other Capability Parameters
+                        * in the message".
+                        */
+                       /* FALLTHROUGH */
+               default:
+                       if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
+                               send_notification_rtlvs(nbr, S_UNSSUPORTDCAP,
+                                   msg.id, msg.type, tlv_type, tlv_len, buf);
+                       /* ignore unknown tlv */
+                       break;
+               }
+               buf += tlv_len;
+               len -= tlv_len;
+       }
+
+       nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
+
+       return (0);
+}
+
 static int
 gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr)
 {
@@ -163,3 +394,45 @@ gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr)
 
        return (ibuf_add(buf, &parms, SESS_PRMS_SIZE));
 }
+
+static int
+gen_cap_dynamic_tlv(struct ibuf *buf)
+{
+       struct capability_tlv   cap;
+
+       memset(&cap, 0, sizeof(cap));
+       cap.type = htons(TLV_TYPE_DYNAMIC_CAP);
+       cap.length = htons(CAP_TLV_DYNAMIC_LEN);
+       /* the S-bit is always 1 for the Dynamic Capability Announcement */
+       cap.reserved = STATE_BIT;
+
+       return (ibuf_add(buf, &cap, CAP_TLV_DYNAMIC_SIZE));
+}
+
+static int
+gen_cap_twcard_tlv(struct ibuf *buf, int enable)
+{
+       struct capability_tlv   cap;
+
+       memset(&cap, 0, sizeof(cap));
+       cap.type = htons(TLV_TYPE_TWCARD_CAP);
+       cap.length = htons(CAP_TLV_TWCARD_LEN);
+       if (enable)
+               cap.reserved = STATE_BIT;
+
+       return (ibuf_add(buf, &cap, CAP_TLV_TWCARD_SIZE));
+}
+
+static int
+gen_cap_unotif_tlv(struct ibuf *buf, int enable)
+{
+       struct capability_tlv   cap;
+
+       memset(&cap, 0, sizeof(cap));
+       cap.type = htons(TLV_TYPE_UNOTIF_CAP);
+       cap.length = htons(CAP_TLV_UNOTIF_LEN);
+       if (enable)
+               cap.reserved = STATE_BIT;
+
+       return (ibuf_add(buf, &cap, CAP_TLV_UNOTIF_SIZE));
+}
index 792608d4259677565310c2b13cbe8276d8e3d3e5..3f4e21e68556857b4aca49d0040d6840bc78baaa 100644 (file)
@@ -152,6 +152,33 @@ l2vpn_if_find_name(struct l2vpn *l2vpn, const char *ifname)
        return (RB_FIND(l2vpn_if_head, &l2vpn->if_tree, &lif));
 }
 
+void
+l2vpn_if_update(struct l2vpn_if *lif)
+{
+       struct l2vpn    *l2vpn = lif->l2vpn;
+       struct l2vpn_pw *pw;
+       struct map       fec;
+       struct nbr      *nbr;
+
+       if ((lif->flags & IFF_UP) && (lif->flags & IFF_RUNNING))
+               return;
+
+       RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) {
+               nbr = nbr_find_ldpid(pw->lsr_id.s_addr);
+               if (nbr == NULL)
+                       continue;
+
+               memset(&fec, 0, sizeof(fec));
+               fec.type = MAP_TYPE_PWID;
+               fec.fec.pwid.type = l2vpn->pw_type;
+               fec.fec.pwid.group_id = 0;
+               fec.flags |= F_MAP_PW_ID;
+               fec.fec.pwid.pwid = pw->pwid;
+
+               send_mac_withdrawal(nbr, &fec, lif->mac);
+       }
+}
+
 static __inline int
 l2vpn_pw_compare(struct l2vpn_pw *a, struct l2vpn_pw *b)
 {
@@ -330,7 +357,7 @@ l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map)
                        st.status_code = S_WRONG_CBIT;
                        st.msg_id = map->msg_id;
                        st.msg_type = htons(MSG_TYPE_LABELMAPPING);
-                       lde_send_labelwithdraw(ln, fn, NO_LABEL, &st);
+                       lde_send_labelwithdraw(ln, fn, NULL, &st);
 
                        pw->flags &= ~F_PW_CWORD;
                        lde_send_labelmapping(ln, fn, 1);
@@ -353,7 +380,7 @@ l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map)
 }
 
 void
-l2vpn_send_pw_status(uint32_t peerid, uint32_t status, struct fec *fec)
+l2vpn_send_pw_status(struct lde_nbr *ln, uint32_t status, struct fec *fec)
 {
        struct notify_msg        nm;
 
@@ -364,8 +391,27 @@ l2vpn_send_pw_status(uint32_t peerid, uint32_t status, struct fec *fec)
        lde_fec2map(fec, &nm.fec);
        nm.flags |= F_NOTIF_FEC;
 
-       lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0,
-           &nm, sizeof(nm));
+       lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm,
+           sizeof(nm));
+}
+
+void
+l2vpn_send_pw_status_wcard(struct lde_nbr *ln, uint32_t status,
+    uint16_t pw_type, uint32_t group_id)
+{
+       struct notify_msg        nm;
+
+       memset(&nm, 0, sizeof(nm));
+       nm.status_code = S_PW_STATUS;
+       nm.pw_status = status;
+       nm.flags |= F_NOTIF_PW_STATUS;
+       nm.fec.type = MAP_TYPE_PWID;
+       nm.fec.fec.pwid.type = pw_type;
+       nm.fec.fec.pwid.group_id = group_id;
+       nm.flags |= F_NOTIF_FEC;
+
+       lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm,
+           sizeof(nm));
 }
 
 void
@@ -376,9 +422,11 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
        struct fec_nh           *fnh;
        struct l2vpn_pw         *pw;
 
-       /* TODO group wildcard */
-       if (!(nm->fec.flags & F_MAP_PW_ID))
+       if (nm->fec.type == MAP_TYPE_TYPED_WCARD ||
+           !(nm->fec.flags & F_MAP_PW_ID)) {
+               l2vpn_recv_pw_status_wcard(ln, nm);
                return;
+       }
 
        lde_map2fec(&nm->fec, ln->id, &fec);
        fn = (struct fec_node *)fec_find(&ft, &fec);
@@ -397,7 +445,6 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
        /* remote status didn't change */
        if (pw->remote_status == nm->pw_status)
                return;
-
        pw->remote_status = nm->pw_status;
 
        if (l2vpn_pw_ok(pw, fnh))
@@ -406,6 +453,56 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
                lde_send_delete_klabel(fn, fnh);
 }
 
+/* RFC4447 PWid group wildcard */
+void
+l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm)
+{
+       struct fec              *f;
+       struct fec_node         *fn;
+       struct fec_nh           *fnh;
+       struct l2vpn_pw         *pw;
+       struct map              *wcard = &nm->fec;
+
+       RB_FOREACH(f, fec_tree, &ft) {
+               fn = (struct fec_node *)f;
+               if (fn->fec.type != FEC_TYPE_PWID)
+                       continue;
+
+               pw = (struct l2vpn_pw *) fn->data;
+               if (pw == NULL)
+                       continue;
+
+               switch (wcard->type) {
+               case MAP_TYPE_TYPED_WCARD:
+                       if (wcard->fec.twcard.u.pw_type != PW_TYPE_WILDCARD &&
+                           wcard->fec.twcard.u.pw_type != fn->fec.u.pwid.type)
+                               continue;
+                       break;
+               case MAP_TYPE_PWID:
+                       if (wcard->fec.pwid.type != fn->fec.u.pwid.type)
+                               continue;
+                       if (wcard->fec.pwid.group_id != pw->remote_group)
+                               continue;
+                       break;
+               }
+
+               fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id,
+                   0, 0);
+               if (fnh == NULL)
+                       continue;
+
+               /* remote status didn't change */
+               if (pw->remote_status == nm->pw_status)
+                       continue;
+               pw->remote_status = nm->pw_status;
+
+               if (l2vpn_pw_ok(pw, fnh))
+                       lde_send_change_klabel(fn, fnh);
+               else
+                       lde_send_delete_klabel(fn, fnh);
+       }
+}
+
 void
 l2vpn_sync_pws(int af, union ldpd_addr *addr)
 {
index 62f2a620d22c0c59f376f4bc40b00b19abaf3765..e8ce7fbdf534e34851905838951de5fda8344fd1 100644 (file)
@@ -28,9 +28,8 @@
 
 static void     enqueue_pdu(struct nbr *, struct ibuf *, uint16_t);
 static int      gen_label_tlv(struct ibuf *, uint32_t);
-static int      tlv_decode_label(struct nbr *, struct ldp_msg *, char *,
-                   uint16_t, uint32_t *);
 static int      gen_reqid_tlv(struct ibuf *, uint32_t);
+static void     log_msg_mapping(int, uint16_t, struct nbr *, struct map *);
 
 static void
 enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size)
@@ -71,25 +70,8 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
                }
 
                /* calculate size */
-               msg_size = LDP_MSG_SIZE + TLV_HDR_SIZE;
-               switch (me->map.type) {
-               case MAP_TYPE_WILDCARD:
-                       msg_size += FEC_ELM_WCARD_LEN;
-                       break;
-               case MAP_TYPE_PREFIX:
-                       msg_size += FEC_ELM_PREFIX_MIN_LEN +
-                           PREFIX_SIZE(me->map.fec.prefix.prefixlen);
-                       break;
-               case MAP_TYPE_PWID:
-                       msg_size += FEC_PWID_ELM_MIN_LEN;
-                       if (me->map.flags & F_MAP_PW_ID)
-                               msg_size += PW_STATUS_TLV_LEN;
-                       if (me->map.flags & F_MAP_PW_IFMTU)
-                               msg_size += FEC_SUBTLV_IFMTU_SIZE;
-                       if (me->map.flags & F_MAP_PW_STATUS)
-                               msg_size += PW_STATUS_TLV_SIZE;
-                       break;
-               }
+               msg_size = LDP_MSG_SIZE;
+               msg_size += len_fec_tlv(&me->map);
                if (me->map.label != NO_LABEL)
                        msg_size += LABEL_TLV_SIZE;
                if (me->map.flags & F_MAP_REQ_ID)
@@ -124,9 +106,7 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
                        return;
                }
 
-               debug_msg_send("%s: lsr-id %s fec %s label %s", msg_name(type),
-                   inet_ntoa(nbr->id), log_map(&me->map),
-                   log_label(me->map.label));
+               log_msg_mapping(1, type, nbr, &me->map);
 
                TAILQ_REMOVE(mh, me, entry);
                free(me);
@@ -146,7 +126,8 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
        uint32_t                 label = NO_LABEL, reqid = 0;
        uint32_t                 pw_status = 0;
        uint8_t                  flags = 0;
-       int                      feclen, lbllen, tlen;
+       int                      feclen, tlen;
+       uint16_t                 current_tlv = 1;
        struct mapping_entry    *me;
        struct mapping_head      mh;
        struct map               map;
@@ -163,7 +144,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
 
        memcpy(&ft, buf, sizeof(ft));
        if (ntohs(ft.type) != TLV_TYPE_FEC) {
-               send_notification_nbr(nbr, S_MISS_MSG, msg.id, msg.type);
+               send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
                return (-1);
        }
        feclen = ntohs(ft.length);
@@ -187,9 +168,9 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
                    !(map.flags & F_MAP_PW_ID) &&
                    type != MSG_TYPE_LABELWITHDRAW &&
                    type != MSG_TYPE_LABELRELEASE) {
-                       send_notification_nbr(nbr, S_MISS_MSG, msg.id,
+                       send_notification(nbr->tcp, S_MISS_MSG, msg.id,
                            msg.type);
-                       return (-1);
+                       goto err;
                }
 
                /*
@@ -209,6 +190,24 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
                        }
                }
 
+               /*
+                * RFC 5561 - Section 4:
+                * "An LDP implementation that supports the Typed Wildcard
+                * FEC Element MUST support its use in Label Request, Label
+                * Withdraw, and Label Release messages".
+                */
+               if (map.type == MAP_TYPE_TYPED_WCARD) {
+                       switch (type) {
+                       case MSG_TYPE_LABELMAPPING:
+                       case MSG_TYPE_LABELABORTREQ:
+                               session_shutdown(nbr, S_UNKNOWN_FEC, msg.id,
+                                   msg.type);
+                               goto err;
+                       default:
+                               break;
+                       }
+               }
+
                /*
                 * LDP supports the use of multiple FEC Elements per
                 * FEC for the Label Mapping message only.
@@ -226,19 +225,10 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
                feclen -= tlen;
        } while (feclen > 0);
 
-       /* Mandatory Label TLV */
-       if (type == MSG_TYPE_LABELMAPPING) {
-               lbllen = tlv_decode_label(nbr, &msg, buf, len, &label);
-               if (lbllen == -1)
-                       goto err;
-
-               buf += lbllen;
-               len -= lbllen;
-       }
-
        /* Optional Parameters */
        while (len > 0) {
                struct tlv      tlv;
+               uint16_t        tlv_type;
                uint16_t        tlv_len;
                uint32_t        reqbuf, labelbuf, statusbuf;
 
@@ -248,6 +238,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
                }
 
                memcpy(&tlv, buf, TLV_HDR_SIZE);
+               tlv_type = ntohs(tlv.type);
                tlv_len = ntohs(tlv.length);
                if (tlv_len + TLV_HDR_SIZE > len) {
                        session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
@@ -256,7 +247,18 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
                buf += TLV_HDR_SIZE;
                len -= TLV_HDR_SIZE;
 
-               switch (ntohs(tlv.type)) {
+               /*
+                * For Label Mapping messages the Label TLV is mandatory and
+                * should appear right after the FEC TLV.
+                */
+               if (current_tlv == 1 && type == MSG_TYPE_LABELMAPPING &&
+                   !(tlv_type & TLV_TYPE_GENERICLABEL)) {
+                       send_notification(nbr->tcp, S_MISS_MSG, msg.id,
+                           msg.type);
+                       goto err;
+               }
+
+               switch (tlv_type) {
                case TLV_TYPE_LABELREQUEST:
                        switch (type) {
                        case MSG_TYPE_LABELMAPPING:
@@ -282,6 +284,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
                        break;
                case TLV_TYPE_GENERICLABEL:
                        switch (type) {
+                       case MSG_TYPE_LABELMAPPING:
                        case MSG_TYPE_LABELWITHDRAW:
                        case MSG_TYPE_LABELRELEASE:
                                if (tlv_len != LABEL_TLV_LEN) {
@@ -292,6 +295,16 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
 
                                memcpy(&labelbuf, buf, sizeof(labelbuf));
                                label = ntohl(labelbuf);
+                               /* do not accept invalid labels */
+                               if (label > MPLS_LABEL_MAX ||
+                                   (label <= MPLS_LABEL_RESERVED_MAX &&
+                                    label != MPLS_LABEL_IPV4NULL &&
+                                    label != MPLS_LABEL_IPV6NULL &&
+                                    label != MPLS_LABEL_IMPLNULL)) {
+                                       session_shutdown(nbr, S_BAD_TLV_VAL,
+                                           msg.id, msg.type);
+                                       goto err;
+                               }
                                break;
                        default:
                                /* ignore */
@@ -301,6 +314,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
                case TLV_TYPE_ATMLABEL:
                case TLV_TYPE_FRLABEL:
                        switch (type) {
+                       case MSG_TYPE_LABELMAPPING:
                        case MSG_TYPE_LABELWITHDRAW:
                        case MSG_TYPE_LABELRELEASE:
                                /* unsupported */
@@ -341,13 +355,14 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
                        break;
                default:
                        if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
-                               send_notification_nbr(nbr, S_UNKNOWN_TLV,
-                                   msg.id, msg.type);
+                               send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
+                                   msg.id, msg.type, tlv_type, tlv_len, buf);
                        /* ignore unknown tlv */
                        break;
                }
                buf += tlv_len;
                len -= tlv_len;
+               current_tlv++;
        }
 
        /* notify lde about the received message. */
@@ -396,9 +411,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
                if (me->map.flags & F_MAP_REQ_ID)
                        me->map.requestid = reqid;
 
-               debug_msg_recv("%s: lsr-id %s fec %s label %s", msg_name(type),
-                   inet_ntoa(nbr->id), log_map(&me->map),
-                   log_label(me->map.label));
+               log_msg_mapping(0, type, nbr, &me->map);
 
                switch (type) {
                case MSG_TYPE_LABELMAPPING:
@@ -423,14 +436,14 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
                ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map,
                    sizeof(struct map));
 
-next:
+ next:
                TAILQ_REMOVE(&mh, me, entry);
                free(me);
        }
 
        return (0);
 
-err:
+ err:
        mapping_list_clr(&mh);
 
        return (-1);
@@ -449,53 +462,6 @@ gen_label_tlv(struct ibuf *buf, uint32_t label)
        return (ibuf_add(buf, &lt, sizeof(lt)));
 }
 
-static int
-tlv_decode_label(struct nbr *nbr, struct ldp_msg *msg, char *buf,
-    uint16_t len, uint32_t *label)
-{
-       struct label_tlv lt;
-
-       if (len < sizeof(lt)) {
-               session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type);
-               return (-1);
-       }
-       memcpy(&lt, buf, sizeof(lt));
-
-       if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) {
-               send_notification_nbr(nbr, S_MISS_MSG, msg->id, msg->type);
-               return (-1);
-       }
-
-       switch (htons(lt.type)) {
-       case TLV_TYPE_GENERICLABEL:
-               if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_SIZE) {
-                       session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
-                           msg->type);
-                       return (-1);
-               }
-
-               *label = ntohl(lt.label);
-               if (*label > MPLS_LABEL_MAX ||
-                   (*label <= MPLS_LABEL_RESERVED_MAX &&
-                    *label != MPLS_LABEL_IPV4NULL &&
-                    *label != MPLS_LABEL_IPV6NULL &&
-                    *label != MPLS_LABEL_IMPLNULL)) {
-                       session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
-                           msg->type);
-                       return (-1);
-               }
-               break;
-       case TLV_TYPE_ATMLABEL:
-       case TLV_TYPE_FRLABEL:
-       default:
-               /* unsupported */
-               session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, msg->type);
-               return (-1);
-       }
-
-       return (sizeof(lt));
-}
-
 static int
 gen_reqid_tlv(struct ibuf *buf, uint32_t reqid)
 {
@@ -520,12 +486,52 @@ gen_pw_status_tlv(struct ibuf *buf, uint32_t status)
        return (ibuf_add(buf, &st, sizeof(st)));
 }
 
+uint16_t
+len_fec_tlv(struct map *map)
+{
+       uint16_t         len = TLV_HDR_SIZE;
+
+       switch (map->type) {
+       case MAP_TYPE_WILDCARD:
+               len += FEC_ELM_WCARD_LEN;
+               break;
+       case MAP_TYPE_PREFIX:
+               len += FEC_ELM_PREFIX_MIN_LEN +
+                   PREFIX_SIZE(map->fec.prefix.prefixlen);
+               break;
+       case MAP_TYPE_PWID:
+               len += FEC_PWID_ELM_MIN_LEN;
+               if (map->flags & F_MAP_PW_ID)
+                       len += PW_STATUS_TLV_LEN;
+               if (map->flags & F_MAP_PW_IFMTU)
+                       len += FEC_SUBTLV_IFMTU_SIZE;
+               if (map->flags & F_MAP_PW_STATUS)
+                       len += PW_STATUS_TLV_SIZE;
+               break;
+       case MAP_TYPE_TYPED_WCARD:
+               len += FEC_ELM_TWCARD_MIN_LEN;
+               switch (map->fec.twcard.type) {
+               case MAP_TYPE_PREFIX:
+               case MAP_TYPE_PWID:
+                       len += sizeof(uint16_t);
+                       break;
+               default:
+                       fatalx("len_fec_tlv: unexpected fec type");
+               }
+               break;
+       default:
+               fatalx("len_fec_tlv: unexpected fec type");
+       }
+
+       return (len);
+}
+
 int
 gen_fec_tlv(struct ibuf *buf, struct map *map)
 {
        struct tlv      ft;
        uint16_t        family, len, pw_type, ifmtu;
-       uint8_t         pw_len = 0;
+       uint8_t         pw_len = 0, twcard_len;
        uint32_t        group_id, pwid;
        int             err = 0;
 
@@ -562,7 +568,7 @@ gen_fec_tlv(struct ibuf *buf, struct map *map)
                break;
        case MAP_TYPE_PWID:
                if (map->flags & F_MAP_PW_ID)
-                       pw_len += PW_STATUS_TLV_LEN;
+                       pw_len += FEC_PWID_SIZE;
                if (map->flags & F_MAP_PW_IFMTU)
                        pw_len += FEC_SUBTLV_IFMTU_SIZE;
 
@@ -595,6 +601,50 @@ gen_fec_tlv(struct ibuf *buf, struct map *map)
                        err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t));
                }
                break;
+       case MAP_TYPE_TYPED_WCARD:
+               len = FEC_ELM_TWCARD_MIN_LEN;
+               switch (map->fec.twcard.type) {
+               case MAP_TYPE_PREFIX:
+               case MAP_TYPE_PWID:
+                       len += sizeof(uint16_t);
+                       break;
+               default:
+                       fatalx("gen_fec_tlv: unexpected fec type");
+               }
+               ft.length = htons(len);
+               err |= ibuf_add(buf, &ft, sizeof(ft));
+               err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
+               err |= ibuf_add(buf, &map->fec.twcard.type, sizeof(uint8_t));
+
+               switch (map->fec.twcard.type) {
+               case MAP_TYPE_PREFIX:
+                       twcard_len = sizeof(uint16_t);
+                       err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
+
+                       switch (map->fec.twcard.u.prefix_af) {
+                       case AF_INET:
+                               family = htons(AF_IPV4);
+                               break;
+                       case AF_INET6:
+                               family = htons(AF_IPV6);
+                               break;
+                       default:
+                               fatalx("gen_fec_tlv: unknown af");
+                               break;
+                       }
+
+                       err |= ibuf_add(buf, &family, sizeof(uint16_t));
+                       break;
+               case MAP_TYPE_PWID:
+                       twcard_len = sizeof(uint16_t);
+                       err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
+                       pw_type = htons(map->fec.twcard.u.pw_type);
+                       err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
+                       break;
+               default:
+                       fatalx("gen_fec_tlv: unexpected fec type");
+               }
+               break;
        default:
                break;
        }
@@ -607,7 +657,7 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
     uint16_t len, struct map *map)
 {
        uint16_t        off = 0;
-       uint8_t         pw_len;
+       uint8_t         pw_len, twcard_len;
 
        map->type = *buf;
        off += sizeof(uint8_t);
@@ -642,7 +692,7 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
                        map->fec.prefix.af = AF_INET6;
                        break;
                default:
-                       send_notification_nbr(nbr, S_UNSUP_ADDR, msg->id,
+                       send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id,
                            msg->type);
                        return (-1);
                }
@@ -751,11 +801,84 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
                        pw_len -= stlv.length;
                }
 
+               return (off);
+       case MAP_TYPE_TYPED_WCARD:
+               if (len < FEC_ELM_TWCARD_MIN_LEN) {
+                       session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
+                           msg->type);
+                       return (-1);
+               }
+
+               memcpy(&map->fec.twcard.type, buf + off, sizeof(uint8_t));
+               off += sizeof(uint8_t);
+               memcpy(&twcard_len, buf + off, sizeof(uint8_t));
+               off += sizeof(uint8_t);
+               if (len != FEC_ELM_TWCARD_MIN_LEN + twcard_len) {
+                       session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
+                           msg->type);
+                       return (-1);
+               }
+
+               switch (map->fec.twcard.type) {
+               case MAP_TYPE_PREFIX:
+                       if (twcard_len != sizeof(uint16_t)) {
+                               session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
+                                   msg->type);
+                               return (-1);
+                       }
+
+                       memcpy(&map->fec.twcard.u.prefix_af, buf + off,
+                           sizeof(uint16_t));
+                       map->fec.twcard.u.prefix_af =
+                           ntohs(map->fec.twcard.u.prefix_af);
+                       off += sizeof(uint16_t);
+
+                       switch (map->fec.twcard.u.prefix_af) {
+                       case AF_IPV4:
+                               map->fec.twcard.u.prefix_af = AF_INET;
+                               break;
+                       case AF_IPV6:
+                               map->fec.twcard.u.prefix_af = AF_INET6;
+                               break;
+                       default:
+                               session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
+                                   msg->type);
+                               return (-1);
+                       }
+                       break;
+               case MAP_TYPE_PWID:
+                       if (twcard_len != sizeof(uint16_t)) {
+                               session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
+                                   msg->type);
+                               return (-1);
+                       }
+
+                       memcpy(&map->fec.twcard.u.pw_type, buf + off,
+                           sizeof(uint16_t));
+                       map->fec.twcard.u.pw_type =
+                           ntohs(map->fec.twcard.u.pw_type);
+                       /* ignore the reserved bit as per RFC 6667 */
+                       map->fec.twcard.u.pw_type &= ~PW_TWCARD_RESERVED_BIT;
+                       off += sizeof(uint16_t);
+                       break;
+               default:
+                       send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id,
+                           msg->type);
+                       return (-1);
+               }
+
                return (off);
        default:
-               send_notification_nbr(nbr, S_UNKNOWN_FEC, msg->id, msg->type);
+               send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type);
                break;
        }
 
        return (-1);
 }
+
+static void
+log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map)
+{
+       debug_msg(out, "%s: lsr-id %s, fec %s, label %s", msg_name(msg_type),
+           inet_ntoa(nbr->id), log_map(map), log_label(map->label));
+}
index 1323ba3d0245344f740cf61bb82b5fbd66f95c15..08339c720ad7038f6de5f90602272d0f990e3b12 100644 (file)
@@ -37,7 +37,7 @@
 static void             lde_shutdown(void);
 static int              lde_dispatch_imsg(struct thread *);
 static int              lde_dispatch_parent(struct thread *);
-static __inline                 int lde_nbr_compare(struct lde_nbr *,
+static __inline        int      lde_nbr_compare(struct lde_nbr *,
                            struct lde_nbr *);
 static struct lde_nbr  *lde_nbr_new(uint32_t, struct lde_nbr *);
 static void             lde_nbr_del(struct lde_nbr *);
@@ -205,9 +205,9 @@ lde_dispatch_imsg(struct thread *thread)
        struct imsgbuf          *ibuf = &iev->ibuf;
        struct imsg              imsg;
        struct lde_nbr          *ln;
-       struct map               map;
-       struct lde_addr          lde_addr;
-       struct notify_msg        nm;
+       struct map              *map;
+       struct lde_addr         *lde_addr;
+       struct notify_msg       *nm;
        ssize_t                  n;
        int                      shut = 0;
 
@@ -240,9 +240,10 @@ lde_dispatch_imsg(struct thread *thread)
                case IMSG_LABEL_RELEASE:
                case IMSG_LABEL_WITHDRAW:
                case IMSG_LABEL_ABORT:
-                       if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map))
+                       if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+                           sizeof(struct map))
                                fatalx("lde_dispatch_imsg: wrong imsg len");
-                       memcpy(&map, imsg.data, sizeof(map));
+                       map = imsg.data;
 
                        ln = lde_nbr_find(imsg.hdr.peerid);
                        if (ln == NULL) {
@@ -253,22 +254,16 @@ lde_dispatch_imsg(struct thread *thread)
 
                        switch (imsg.hdr.type) {
                        case IMSG_LABEL_MAPPING:
-                               lde_check_mapping(&map, ln);
+                               lde_check_mapping(map, ln);
                                break;
                        case IMSG_LABEL_REQUEST:
-                               lde_check_request(&map, ln);
+                               lde_check_request(map, ln);
                                break;
                        case IMSG_LABEL_RELEASE:
-                               if (map.type == MAP_TYPE_WILDCARD)
-                                       lde_check_release_wcard(&map, ln);
-                               else
-                                       lde_check_release(&map, ln);
+                               lde_check_release(map, ln);
                                break;
                        case IMSG_LABEL_WITHDRAW:
-                               if (map.type == MAP_TYPE_WILDCARD)
-                                       lde_check_withdraw_wcard(&map, ln);
-                               else
-                                       lde_check_withdraw(&map, ln);
+                               lde_check_withdraw(map, ln);
                                break;
                        case IMSG_LABEL_ABORT:
                                /* not necessary */
@@ -276,9 +271,10 @@ lde_dispatch_imsg(struct thread *thread)
                        }
                        break;
                case IMSG_ADDRESS_ADD:
-                       if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr))
+                       if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+                           sizeof(struct lde_addr))
                                fatalx("lde_dispatch_imsg: wrong imsg len");
-                       memcpy(&lde_addr, imsg.data, sizeof(lde_addr));
+                       lde_addr = imsg.data;
 
                        ln = lde_nbr_find(imsg.hdr.peerid);
                        if (ln == NULL) {
@@ -286,16 +282,17 @@ lde_dispatch_imsg(struct thread *thread)
                                    __func__);
                                break;
                        }
-                       if (lde_address_add(ln, &lde_addr) < 0) {
+                       if (lde_address_add(ln, lde_addr) < 0) {
                                log_debug("%s: cannot add address %s, it "
                                    "already exists", __func__,
-                                   log_addr(lde_addr.af, &lde_addr.addr));
+                                   log_addr(lde_addr->af, &lde_addr->addr));
                        }
                        break;
                case IMSG_ADDRESS_DEL:
-                       if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr))
+                       if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+                           sizeof(struct lde_addr))
                                fatalx("lde_dispatch_imsg: wrong imsg len");
-                       memcpy(&lde_addr, imsg.data, sizeof(lde_addr));
+                       lde_addr = imsg.data;
 
                        ln = lde_nbr_find(imsg.hdr.peerid);
                        if (ln == NULL) {
@@ -303,16 +300,17 @@ lde_dispatch_imsg(struct thread *thread)
                                    __func__);
                                break;
                        }
-                       if (lde_address_del(ln, &lde_addr) < 0) {
+                       if (lde_address_del(ln, lde_addr) < 0) {
                                log_debug("%s: cannot delete address %s, it "
                                    "does not exist", __func__,
-                                   log_addr(lde_addr.af, &lde_addr.addr));
+                                   log_addr(lde_addr->af, &lde_addr->addr));
                        }
                        break;
                case IMSG_NOTIFICATION:
-                       if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(nm))
+                       if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+                           sizeof(struct notify_msg))
                                fatalx("lde_dispatch_imsg: wrong imsg len");
-                       memcpy(&nm, imsg.data, sizeof(nm));
+                       nm = imsg.data;
 
                        ln = lde_nbr_find(imsg.hdr.peerid);
                        if (ln == NULL) {
@@ -321,10 +319,17 @@ lde_dispatch_imsg(struct thread *thread)
                                break;
                        }
 
-                       switch (nm.status_code) {
+                       switch (nm->status_code) {
                        case S_PW_STATUS:
-                               l2vpn_recv_pw_status(ln, &nm);
+                               l2vpn_recv_pw_status(ln, nm);
                                break;
+                       case S_ENDOFLIB:
+                               /*
+                                * Do nothing for now. Should be useful in
+                                * the future when we implement LDP-IGP
+                                * Synchronization (RFC 5443) and Graceful
+                                * Restart (RFC 3478).
+                                */
                        default:
                                break;
                        }
@@ -391,7 +396,7 @@ lde_dispatch_parent(struct thread *thread)
        struct l2vpn_if         *nlif;
        struct l2vpn_pw         *npw;
        struct imsg              imsg;
-       struct kroute            kr;
+       struct kroute           *kr;
        int                      fd = THREAD_FD(thread);
        struct imsgev           *iev = THREAD_ARG(thread);
        struct imsgbuf          *ibuf = &iev->ibuf;
@@ -415,22 +420,23 @@ lde_dispatch_parent(struct thread *thread)
                switch (imsg.hdr.type) {
                case IMSG_NETWORK_ADD:
                case IMSG_NETWORK_UPDATE:
-                       if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) {
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE +
+                           sizeof(struct kroute)) {
                                log_warnx("%s: wrong imsg len", __func__);
                                break;
                        }
-                       memcpy(&kr, imsg.data, sizeof(kr));
+                       kr = imsg.data;
 
-                       switch (kr.af) {
+                       switch (kr->af) {
                        case AF_INET:
                                fec.type = FEC_TYPE_IPV4;
-                               fec.u.ipv4.prefix = kr.prefix.v4;
-                               fec.u.ipv4.prefixlen = kr.prefixlen;
+                               fec.u.ipv4.prefix = kr->prefix.v4;
+                               fec.u.ipv4.prefixlen = kr->prefixlen;
                                break;
                        case AF_INET6:
                                fec.type = FEC_TYPE_IPV6;
-                               fec.u.ipv6.prefix = kr.prefix.v6;
-                               fec.u.ipv6.prefixlen = kr.prefixlen;
+                               fec.u.ipv6.prefix = kr->prefix.v6;
+                               fec.u.ipv6.prefixlen = kr->prefixlen;
                                break;
                        default:
                                fatalx("lde_dispatch_parent: unknown af");
@@ -438,9 +444,9 @@ lde_dispatch_parent(struct thread *thread)
 
                        switch (imsg.hdr.type) {
                        case IMSG_NETWORK_ADD:
-                               lde_kernel_insert(&fec, kr.af, &kr.nexthop,
-                                   kr.ifindex, kr.priority,
-                                   kr.flags & F_CONNECTED, NULL);
+                               lde_kernel_insert(&fec, kr->af, &kr->nexthop,
+                                   kr->ifindex, kr->priority,
+                                   kr->flags & F_CONNECTED, NULL);
                                break;
                        case IMSG_NETWORK_UPDATE:
                                lde_kernel_update(&fec);
@@ -929,8 +935,8 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
 }
 
 void
-lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label,
-    struct status_tlv *st)
+lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn,
+    struct map *wcard, struct status_tlv *st)
 {
        struct lde_wdraw        *lw;
        struct map               map;
@@ -959,11 +965,8 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label,
                        break;
                }
                map.label = fn->local_label;
-       } else {
-               memset(&map, 0, sizeof(map));
-               map.type = MAP_TYPE_WILDCARD;
-               map.label = label;
-       }
+       } else
+               memcpy(&map, wcard, sizeof(map));
 
        if (st) {
                map.st.status_code = st->status_code;
@@ -984,8 +987,13 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label,
                        lw = lde_wdraw_add(ln, fn);
                lw->label = map.label;
        } else {
+               struct lde_map *me;
+
                RB_FOREACH(f, fec_tree, &ft) {
                        fn = (struct fec_node *)f;
+                       me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
+                       if (lde_wildcard_apply(wcard, &fn->fec, me) == 0)
+                               continue;
 
                        lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw,
                            &fn->fec);
@@ -997,16 +1005,62 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label,
 }
 
 void
-lde_send_labelwithdraw_all(struct fec_node *fn, uint32_t label)
+lde_send_labelwithdraw_wcard(struct lde_nbr *ln, uint32_t label)
 {
-       struct lde_nbr          *ln;
+       struct map       wcard;
 
-       RB_FOREACH(ln, nbr_tree, &lde_nbrs)
-               lde_send_labelwithdraw(ln, fn, label, NULL);
+       memset(&wcard, 0, sizeof(wcard));
+       wcard.type = MAP_TYPE_WILDCARD;
+       wcard.label = label;
+       lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
+}
+
+void
+lde_send_labelwithdraw_twcard_prefix(struct lde_nbr *ln, uint16_t af,
+    uint32_t label)
+{
+       struct map       wcard;
+
+       memset(&wcard, 0, sizeof(wcard));
+       wcard.type = MAP_TYPE_TYPED_WCARD;
+       wcard.fec.twcard.type = MAP_TYPE_PREFIX;
+       wcard.fec.twcard.u.prefix_af = af;
+       wcard.label = label;
+       lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
 }
 
 void
-lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label)
+lde_send_labelwithdraw_twcard_pwid(struct lde_nbr *ln, uint16_t pw_type,
+    uint32_t label)
+{
+       struct map       wcard;
+
+       memset(&wcard, 0, sizeof(wcard));
+       wcard.type = MAP_TYPE_TYPED_WCARD;
+       wcard.fec.twcard.type = MAP_TYPE_PWID;
+       wcard.fec.twcard.u.pw_type = pw_type;
+       wcard.label = label;
+       lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
+}
+
+void
+lde_send_labelwithdraw_pwid_wcard(struct lde_nbr *ln, uint16_t pw_type,
+    uint32_t group_id)
+{
+       struct map       wcard;
+
+       memset(&wcard, 0, sizeof(wcard));
+       wcard.type = MAP_TYPE_PWID;
+       wcard.fec.pwid.type = pw_type;
+       wcard.fec.pwid.group_id = group_id;
+       /* we can not append a Label TLV when using PWid group wildcards. */
+       wcard.label = NO_LABEL;
+       lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
+}
+
+void
+lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn,
+    struct map *wcard, uint32_t label)
 {
        struct map               map;
        struct l2vpn_pw         *pw;
@@ -1032,10 +1086,8 @@ lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label)
                                map.flags |= F_MAP_PW_CWORD;
                        break;
                }
-       } else {
-               memset(&map, 0, sizeof(map));
-               map.type = MAP_TYPE_WILDCARD;
-       }
+       } else
+               memcpy(&map, wcard, sizeof(map));
        map.label = label;
 
        lde_imsg_compose_ldpe(IMSG_RELEASE_ADD, ln->peerid, 0,
@@ -1044,7 +1096,7 @@ lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label)
 }
 
 void
-lde_send_notification(uint32_t peerid, uint32_t status_code, uint32_t msg_id,
+lde_send_notification(struct lde_nbr *ln, uint32_t status_code, uint32_t msg_id,
     uint16_t msg_type)
 {
        struct notify_msg nm;
@@ -1055,7 +1107,39 @@ lde_send_notification(uint32_t peerid, uint32_t status_code, uint32_t msg_id,
        nm.msg_id = msg_id;
        nm.msg_type = msg_type;
 
-       lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0,
+       lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0,
+           &nm, sizeof(nm));
+}
+
+void
+lde_send_notification_eol_prefix(struct lde_nbr *ln, int af)
+{
+       struct notify_msg nm;
+
+       memset(&nm, 0, sizeof(nm));
+       nm.status_code = S_ENDOFLIB;
+       nm.fec.type = MAP_TYPE_TYPED_WCARD;
+       nm.fec.fec.twcard.type = MAP_TYPE_PREFIX;
+       nm.fec.fec.twcard.u.prefix_af = af;
+       nm.flags |= F_NOTIF_FEC;
+
+       lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0,
+           &nm, sizeof(nm));
+}
+
+void
+lde_send_notification_eol_pwid(struct lde_nbr *ln, uint16_t pw_type)
+{
+       struct notify_msg nm;
+
+       memset(&nm, 0, sizeof(nm));
+       nm.status_code = S_ENDOFLIB;
+       nm.fec.type = MAP_TYPE_TYPED_WCARD;
+       nm.fec.fec.twcard.type = MAP_TYPE_PWID;
+       nm.fec.fec.twcard.u.pw_type = pw_type;
+       nm.flags |= F_NOTIF_FEC;
+
+       lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0,
            &nm, sizeof(nm));
 }
 
@@ -1076,6 +1160,7 @@ lde_nbr_new(uint32_t peerid, struct lde_nbr *new)
        ln->id = new->id;
        ln->v4_enabled = new->v4_enabled;
        ln->v6_enabled = new->v6_enabled;
+       ln->flags = new->flags;
        ln->peerid = peerid;
        fec_init(&ln->recv_map);
        fec_init(&ln->sent_map);
@@ -1352,13 +1437,11 @@ lde_change_egress_label(int af)
 
        /* explicitly withdraw all null labels */
        RB_FOREACH(ln, nbr_tree, &lde_nbrs) {
-               lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IMPLNULL, NULL);
+               lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IMPLNULL);
                if (ln->v4_enabled)
-                       lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IPV4NULL,
-                           NULL);
+                       lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV4NULL);
                if (ln->v6_enabled)
-                       lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IPV6NULL,
-                           NULL);
+                       lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV6NULL);
        }
 
        /* update label of connected routes */
index e0e9873d5ca842bc83e4b260f4590e551724fd18..b5bcb42c8b561d98e44b5c66f36eedb865174688 100644 (file)
@@ -90,6 +90,7 @@ struct lde_nbr {
        struct in_addr           id;
        int                      v4_enabled;    /* announce/process v4 msgs */
        int                      v6_enabled;    /* announce/process v6 msgs */
+       int                      flags;         /* capabilities */
        struct fec_tree          recv_req;
        struct fec_tree          sent_req;
        struct fec_tree          recv_map;
@@ -143,11 +144,20 @@ void               lde_map2fec(struct map *, struct in_addr, struct fec *);
 void            lde_send_labelmapping(struct lde_nbr *, struct fec_node *,
                    int);
 void            lde_send_labelwithdraw(struct lde_nbr *, struct fec_node *,
-                   uint32_t, struct status_tlv *);
-void            lde_send_labelwithdraw_all(struct fec_node *, uint32_t);
-void            lde_send_labelrelease(struct lde_nbr *, struct fec_node *,
+                   struct map *, struct status_tlv *);
+void            lde_send_labelwithdraw_wcard(struct lde_nbr *, uint32_t);
+void            lde_send_labelwithdraw_twcard_prefix(struct lde_nbr *,
+                   uint16_t, uint32_t);
+void            lde_send_labelwithdraw_twcard_pwid(struct lde_nbr *, uint16_t,
+                   uint32_t);
+void            lde_send_labelwithdraw_pwid_wcard(struct lde_nbr *, uint16_t,
                    uint32_t);
-void            lde_send_notification(uint32_t, uint32_t, uint32_t, uint16_t);
+void            lde_send_labelrelease(struct lde_nbr *, struct fec_node *,
+                   struct map *, uint32_t);
+void            lde_send_notification(struct lde_nbr *, uint32_t, uint32_t,
+                   uint16_t);
+void            lde_send_notification_eol_prefix(struct lde_nbr *, int);
+void            lde_send_notification_eol_pwid(struct lde_nbr *, uint16_t);
 struct lde_nbr *lde_nbr_find_by_lsrid(struct in_addr);
 struct lde_nbr *lde_nbr_find_by_addr(int, union ldpd_addr *);
 struct lde_map *lde_map_add(struct lde_nbr *, struct fec_node *, int);
@@ -178,10 +188,13 @@ void               lde_kernel_remove(struct fec *, int, union ldpd_addr *,
 void            lde_kernel_update(struct fec *);
 void            lde_check_mapping(struct map *, struct lde_nbr *);
 void            lde_check_request(struct map *, struct lde_nbr *);
+void            lde_check_request_wcard(struct map *, struct lde_nbr *);
 void            lde_check_release(struct map *, struct lde_nbr *);
 void            lde_check_release_wcard(struct map *, struct lde_nbr *);
 void            lde_check_withdraw(struct map *, struct lde_nbr *);
 void            lde_check_withdraw_wcard(struct map *, struct lde_nbr *);
+int             lde_wildcard_apply(struct map *, struct fec *,
+                   struct lde_map *);
 int             lde_gc_timer(struct thread *);
 void            lde_gc_start_timer(void);
 void            lde_gc_stop_timer(void);
@@ -195,6 +208,7 @@ void                 l2vpn_exit(struct l2vpn *);
 struct l2vpn_if        *l2vpn_if_new(struct l2vpn *, struct kif *);
 struct l2vpn_if        *l2vpn_if_find(struct l2vpn *, unsigned int);
 struct l2vpn_if        *l2vpn_if_find_name(struct l2vpn *, const char *);
+void            l2vpn_if_update(struct l2vpn_if *);
 struct l2vpn_pw        *l2vpn_pw_new(struct l2vpn *, struct kif *);
 struct l2vpn_pw *l2vpn_pw_find(struct l2vpn *, unsigned int);
 struct l2vpn_pw *l2vpn_pw_find_name(struct l2vpn *, const char *);
@@ -204,8 +218,12 @@ void                l2vpn_pw_reset(struct l2vpn_pw *);
 int             l2vpn_pw_ok(struct l2vpn_pw *, struct fec_nh *);
 int             l2vpn_pw_negotiate(struct lde_nbr *, struct fec_node *,
                    struct map *);
-void            l2vpn_send_pw_status(uint32_t, uint32_t, struct fec *);
+void            l2vpn_send_pw_status(struct lde_nbr *, uint32_t, struct fec *);
+void            l2vpn_send_pw_status_wcard(struct lde_nbr *, uint32_t,
+                   uint16_t, uint32_t);
 void            l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *);
+void            l2vpn_recv_pw_status_wcard(struct lde_nbr *,
+                   struct notify_msg *);
 void            l2vpn_sync_pws(int, union ldpd_addr *);
 void            l2vpn_pw_ctl(pid_t);
 void            l2vpn_binding_ctl(pid_t);
index 234d373fbb145998705022d2cd1ed6f4f484ed76..4444a1e1ac38e2fcafd20d553aa41305455764e1 100644 (file)
@@ -374,7 +374,8 @@ lde_kernel_update(struct fec *fec)
        }
 
        if (LIST_EMPTY(&fn->nexthops)) {
-               lde_send_labelwithdraw_all(fn, NO_LABEL);
+               RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+                       lde_send_labelwithdraw(ln, fn, NULL, NULL);
                fn->local_label = NO_LABEL;
                fn->data = NULL;
        } else {
@@ -478,7 +479,7 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
                /* LMp.10 */
                if (me->map.label != map->label && lre == NULL) {
                        /* LMp.10a */
-                       lde_send_labelrelease(ln, fn, me->map.label);
+                       lde_send_labelrelease(ln, fn, NULL, me->map.label);
 
                        /*
                         * Can not use lde_nbr_find_by_addr() because there's
@@ -554,6 +555,12 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
        struct fec_node *fn;
        struct fec_nh   *fnh;
 
+       /* wildcard label request */
+       if (map->type == MAP_TYPE_TYPED_WCARD) {
+               lde_check_request_wcard(map, ln);
+               return;
+       }
+
        /* LRq.1: skip loop detection (not necessary) */
 
        /* LRq.2: is there a next hop for fec? */
@@ -561,7 +568,7 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
        fn = (struct fec_node *)fec_find(&ft, &fec);
        if (fn == NULL || LIST_EMPTY(&fn->nexthops)) {
                /* LRq.5: send No Route notification */
-               lde_send_notification(ln->peerid, S_NO_ROUTE, map->msg_id,
+               lde_send_notification(ln, S_NO_ROUTE, map->msg_id,
                    htons(MSG_TYPE_LABELREQUEST));
                return;
        }
@@ -575,8 +582,8 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
                                continue;
 
                        /* LRq.4: send Loop Detected notification */
-                       lde_send_notification(ln->peerid, S_LOOP_DETECTED,
-                           map->msg_id, htons(MSG_TYPE_LABELREQUEST));
+                       lde_send_notification(ln, S_LOOP_DETECTED, map->msg_id,
+                           htons(MSG_TYPE_LABELREQUEST));
                        return;
                default:
                        break;
@@ -604,6 +611,40 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
         */
 }
 
+void
+lde_check_request_wcard(struct map *map, struct lde_nbr *ln)
+{
+       struct fec      *f;
+       struct fec_node *fn;
+       struct lde_req  *lre;
+
+       RB_FOREACH(f, fec_tree, &ft) {
+               fn = (struct fec_node *)f;
+
+               /* only a typed wildcard is possible here */
+               if (lde_wildcard_apply(map, &fn->fec, NULL) == 0)
+                       continue;
+
+               /* LRq.2: is there a next hop for fec? */
+               if (LIST_EMPTY(&fn->nexthops))
+                       continue;
+
+               /* LRq.6: first check if we have a pending request running */
+               lre = (struct lde_req *)fec_find(&ln->recv_req, &fn->fec);
+               if (lre != NULL)
+                       /* LRq.7: duplicate request */
+                       continue;
+
+               /* LRq.8: record label request */
+               lre = lde_req_add(ln, &fn->fec, 0);
+               if (lre != NULL)
+                       lre->msg_id = ntohl(map->msg_id);
+
+               /* LRq.9: perform LSR label distribution */
+               lde_send_labelmapping(ln, fn, 1);
+       }
+}
+
 void
 lde_check_release(struct map *map, struct lde_nbr *ln)
 {
@@ -612,9 +653,13 @@ lde_check_release(struct map *map, struct lde_nbr *ln)
        struct lde_wdraw        *lw;
        struct lde_map          *me;
 
-       /* TODO group wildcard */
-       if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))
+       /* wildcard label release */
+       if (map->type == MAP_TYPE_WILDCARD ||
+           map->type == MAP_TYPE_TYPED_WCARD ||
+           (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) {
+               lde_check_release_wcard(map, ln);
                return;
+       }
 
        lde_map2fec(map, ln->id, &fec);
        fn = (struct fec_node *)fec_find(&ft, &fec);
@@ -624,8 +669,7 @@ lde_check_release(struct map *map, struct lde_nbr *ln)
 
        /* LRl.3: first check if we have a pending withdraw running */
        lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
-       if (lw && (map->label == NO_LABEL ||
-           (lw->label != NO_LABEL && map->label == lw->label))) {
+       if (lw && (map->label == NO_LABEL || map->label == lw->label)) {
                /* LRl.4: delete record of outstanding label withdraw */
                lde_wdraw_del(ln, lw);
        }
@@ -651,17 +695,20 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln)
 
        RB_FOREACH(f, fec_tree, &ft) {
                fn = (struct fec_node *)f;
+               me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
+
+               /* LRl.1: does FEC match a known FEC? */
+               if (lde_wildcard_apply(map, &fn->fec, me) == 0)
+                       continue;
 
                /* LRl.3: first check if we have a pending withdraw running */
                lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
-               if (lw && (map->label == NO_LABEL ||
-                   (lw->label != NO_LABEL && map->label == lw->label))) {
+               if (lw && (map->label == NO_LABEL || map->label == lw->label)) {
                        /* LRl.4: delete record of outstanding lbl withdraw */
                        lde_wdraw_del(ln, lw);
                }
 
                /* LRl.6: check sent map list and remove it if available */
-               me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
                if (me &&
                    (map->label == NO_LABEL || map->label == me->map.label))
                        lde_map_del(ln, me, 1);
@@ -682,9 +729,13 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
        struct lde_map          *me;
        struct l2vpn_pw         *pw;
 
-       /* TODO group wildcard */
-       if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))
+       /* wildcard label withdraw */
+       if (map->type == MAP_TYPE_WILDCARD ||
+           map->type == MAP_TYPE_TYPED_WCARD ||
+           (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) {
+               lde_check_withdraw_wcard(map, ln);
                return;
+       }
 
        lde_map2fec(map, ln->id, &fec);
        fn = (struct fec_node *)fec_find(&ft, &fec);
@@ -707,12 +758,15 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
                default:
                        break;
                }
+               if (map->label != NO_LABEL && map->label != fnh->remote_label)
+                       continue;
+
                lde_send_delete_klabel(fn, fnh);
                fnh->remote_label = NO_LABEL;
        }
 
        /* LWd.2: send label release */
-       lde_send_labelrelease(ln, fn, map->label);
+       lde_send_labelrelease(ln, fn, NULL, map->label);
 
        /* LWd.3: check previously received label mapping */
        me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
@@ -730,10 +784,14 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
        struct lde_map  *me;
 
        /* LWd.2: send label release */
-       lde_send_labelrelease(ln, NULL, map->label);
+       lde_send_labelrelease(ln, NULL, map, map->label);
 
        RB_FOREACH(f, fec_tree, &ft) {
                fn = (struct fec_node *)f;
+               me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
+
+               if (lde_wildcard_apply(map, &fn->fec, me) == 0)
+                       continue;
 
                /* LWd.1: remove label from forwarding/switching use */
                LIST_FOREACH(fnh, &fn->nexthops, entry) {
@@ -751,12 +809,15 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
                        default:
                                break;
                        }
+                       if (map->label != NO_LABEL && map->label !=
+                           fnh->remote_label)
+                               continue;
+
                        lde_send_delete_klabel(fn, fnh);
                        fnh->remote_label = NO_LABEL;
                }
 
                /* LWd.3: check previously received label mapping */
-               me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
                if (me && (map->label == NO_LABEL ||
                    map->label == me->map.label))
                        /*
@@ -767,6 +828,49 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
        }
 }
 
+int
+lde_wildcard_apply(struct map *wcard, struct fec *fec, struct lde_map *me)
+{
+       switch (wcard->type) {
+       case MAP_TYPE_WILDCARD:
+               /* full wildcard */
+               return (1);
+       case MAP_TYPE_TYPED_WCARD:
+               switch (wcard->fec.twcard.type) {
+               case MAP_TYPE_PREFIX:
+                       if (wcard->fec.twcard.u.prefix_af == AF_INET &&
+                           fec->type != FEC_TYPE_IPV4)
+                               return (0);
+                       if (wcard->fec.twcard.u.prefix_af == AF_INET6 &&
+                           fec->type != FEC_TYPE_IPV6)
+                               return (0);
+                       return (1);
+               case MAP_TYPE_PWID:
+                       if (fec->type != FEC_TYPE_PWID)
+                               return (0);
+                       if (wcard->fec.twcard.u.pw_type != PW_TYPE_WILDCARD &&
+                           wcard->fec.twcard.u.pw_type != fec->u.pwid.type)
+                               return (0);
+                       return (1);
+               default:
+                       fatalx("lde_wildcard_apply: unexpected fec type");
+               }
+               break;
+       case MAP_TYPE_PWID:
+               /* RFC4447 pw-id group wildcard */
+               if (fec->type != FEC_TYPE_PWID)
+                       return (0);
+               if (fec->u.pwid.type != wcard->fec.pwid.type)
+                       return (0);
+               if (me == NULL || (me->map.fec.pwid.group_id !=
+                   wcard->fec.pwid.group_id))
+                       return (0);
+               return (1);
+       default:
+               fatalx("lde_wildcard_apply: unexpected fec type");
+       }
+}
+
 /* gabage collector timer: timer to remove dead entries from the LIB */
 
 /* ARGSUSED */
index c421cddc386f8fb9bbcedf4bd91a907fa45c4b09..c2b64d20c67458cb9f413df9157ecfcb1edc62a4 100644 (file)
@@ -63,6 +63,7 @@
 #define MSG_TYPE_HELLO         0x0100
 #define MSG_TYPE_INIT          0x0200
 #define MSG_TYPE_KEEPALIVE     0x0201
+#define MSG_TYPE_CAPABILITY    0x0202 /* RFC 5561 */
 #define MSG_TYPE_ADDR          0x0300
 #define MSG_TYPE_ADDRWITHDRAW  0x0301
 #define MSG_TYPE_LABELMAPPING  0x0400
 #define TLV_TYPE_FRSESSION     0x0502
 #define TLV_TYPE_LABELREQUEST  0x0600
 /* RFC 4447 */
-#define TLV_TYPE_PW_STATUS     0x096A
+#define TLV_TYPE_MAC_LIST      0x8404
+#define TLV_TYPE_PW_STATUS     0x896A
 #define TLV_TYPE_PW_IF_PARAM   0x096B
 #define TLV_TYPE_PW_GROUP_ID   0x096C
+/* RFC 5561 */
+#define TLV_TYPE_RETURNED_TLVS 0x8304
+#define TLV_TYPE_DYNAMIC_CAP   0x8506
+/* RFC 5918 */
+#define TLV_TYPE_TWCARD_CAP    0x850B
+/* RFC 5919 */
+#define TLV_TYPE_UNOTIF_CAP    0x8603
 /* RFC 7552 */
 #define TLV_TYPE_DUALSTACK     0x8701
 
@@ -196,6 +205,10 @@ struct hello_prms_opt16_tlv {
 #define S_UNASSIGN_TAI 0x00000029
 #define S_MISCONF_ERR  0x0000002A
 #define S_WITHDRAW_MTHD        0x0000002B
+/* RFC 5561 */
+#define        S_UNSSUPORTDCAP 0x0000002E
+/* RFC 5919 */
+#define        S_ENDOFLIB      0x0000002F
 /* RFC 7552 */
 #define        S_TRANS_MISMTCH 0x80000032
 #define        S_DS_NONCMPLNCE 0x80000033
@@ -227,6 +240,26 @@ struct status_tlv {
 #define STATUS_TLV_LEN         10
 #define        STATUS_FATAL            0x80000000
 
+struct capability_tlv {
+       uint16_t        type;
+       uint16_t        length;
+       uint8_t         reserved;
+};
+#define STATE_BIT              0x80
+
+#define F_CAP_TLV_RCVD_DYNAMIC 0x01
+#define F_CAP_TLV_RCVD_TWCARD  0x02
+#define F_CAP_TLV_RCVD_UNOTIF  0x04
+
+#define CAP_TLV_DYNAMIC_SIZE   5
+#define CAP_TLV_DYNAMIC_LEN    1
+
+#define CAP_TLV_TWCARD_SIZE    5
+#define CAP_TLV_TWCARD_LEN     1
+
+#define CAP_TLV_UNOTIF_SIZE    5
+#define CAP_TLV_UNOTIF_LEN     1
+
 #define        AF_IPV4                 0x1
 #define        AF_IPV6                 0x2
 
@@ -242,17 +275,23 @@ struct address_list_tlv {
 #define FEC_ELM_WCARD_LEN      1
 #define FEC_ELM_PREFIX_MIN_LEN 4
 #define FEC_PWID_ELM_MIN_LEN   8
+#define FEC_PWID_SIZE          4
+#define FEC_ELM_TWCARD_MIN_LEN 3
 
 #define        MAP_TYPE_WILDCARD       0x01
 #define        MAP_TYPE_PREFIX         0x02
+#define        MAP_TYPE_TYPED_WCARD    0x05
 #define        MAP_TYPE_PWID           0x80
 #define        MAP_TYPE_GENPWID        0x81
 
 #define CONTROL_WORD_FLAG      0x8000
 #define PW_TYPE_ETHERNET_TAGGED        0x0004
 #define PW_TYPE_ETHERNET       0x0005
+#define PW_TYPE_WILDCARD       0x7FFF
 #define DEFAULT_PW_TYPE                PW_TYPE_ETHERNET
 
+#define PW_TWCARD_RESERVED_BIT 0x8000
+
 /* RFC 4447 Sub-TLV record */
 struct subtlv {
        uint8_t         type;
index aa0cd47e7bc66dd98c5c0450de01be8ebd7a0e13..f944851b6e3568b26bcd3e431982f9d5a210ae42 100644 (file)
@@ -104,6 +104,14 @@ do {                                                                       \
                log_debug("msg[out]: " emsg, __VA_ARGS__);              \
 } while (0)
 
+#define                 debug_msg(out, emsg, ...)                              \
+do {                                                                   \
+       if (out)                                                        \
+               debug_msg_send(emsg, __VA_ARGS__);                      \
+       else                                                            \
+               debug_msg_recv(emsg, __VA_ARGS__);                      \
+} while (0)
+
 #define                 debug_kalive_recv(emsg, ...)                           \
 do {                                                                   \
        if (LDP_DEBUG(msg, MSG_RECV_ALL))                               \
index 12954b91af6791ac862adf03e932f1a9d6fb2d7d..c41a0dbd9151516dbfd447946d24c10cbe797b97 100644 (file)
@@ -65,6 +65,8 @@ ifp2kif(struct interface *ifp, struct kif *kif)
        strlcpy(kif->ifname, ifp->name, sizeof(kif->ifname));
        kif->ifindex = ifp->ifindex;
        kif->flags = ifp->flags;
+       if (ifp->ll_type == ZEBRA_LLT_ETHER)
+               memcpy(kif->mac, ifp->hw_addr, ETHER_ADDR_LEN);
 }
 
 static void
index ff3af19db4729d5ce90b5b0ebd7408036b340e2d..0a7e1177bc54f468d1c185672cccaee3ee3e7a31 100644 (file)
@@ -27,6 +27,7 @@
 #include "imsg.h"
 #include "thread.h"
 #include "qobj.h"
+#include "prefix.h"
 #include "filter.h"
 
 #include "ldp.h"
@@ -220,6 +221,13 @@ struct map {
                        uint32_t        group_id;
                        uint16_t        ifmtu;
                } pwid;
+               struct {
+                       uint8_t         type;
+                       union {
+                               uint16_t        prefix_af;
+                               uint16_t        pw_type;
+                       } u;
+               } twcard;
        } fec;
        struct {
                uint32_t        status_code;
@@ -244,10 +252,16 @@ struct notify_msg {
        uint16_t        msg_type;       /* network byte order */
        uint32_t        pw_status;
        struct map      fec;
+       struct {
+               uint16_t         type;
+               uint16_t         length;
+               char            *data;
+       } rtlvs;
        uint8_t         flags;
 };
 #define F_NOTIF_PW_STATUS      0x01    /* pseudowire status tlv present */
 #define F_NOTIF_FEC            0x02    /* fec tlv present */
+#define F_NOTIF_RETURNED_TLVS  0x04    /* returned tlvs present */
 
 struct if_addr {
        LIST_ENTRY(if_addr)      entry;
@@ -337,6 +351,7 @@ struct l2vpn_if {
        char                     ifname[IF_NAMESIZE];
        unsigned int             ifindex;
        uint16_t                 flags;
+       uint8_t                  mac[ETHER_ADDR_LEN];
        QOBJ_FIELDS
 };
 RB_HEAD(l2vpn_if_head, l2vpn_if);
@@ -506,6 +521,7 @@ struct kif {
        char                     ifname[IF_NAMESIZE];
        unsigned short           ifindex;
        int                      flags;
+       uint8_t                  mac[ETHER_ADDR_LEN];
        int                      mtu;
 };
 
index 7dcc8fbe16dcf5db03c7a6ec2474b0db8cc376ef..3bb84e92a992906be803fc525c94a09b031cfa38 100644 (file)
@@ -251,8 +251,8 @@ ldpe_dispatch_main(struct thread *thread)
        struct iface            *niface;
        struct tnbr             *ntnbr;
        struct nbr_params       *nnbrp;
-       static struct l2vpn     *nl2vpn;
-       struct l2vpn_if         *nlif;
+       static struct l2vpn     *l2vpn, *nl2vpn;
+       struct l2vpn_if         *lif = NULL, *nlif;
        struct l2vpn_pw         *npw;
        struct imsg              imsg;
        int                      fd = THREAD_FD(thread);
@@ -292,11 +292,22 @@ ldpe_dispatch_main(struct thread *thread)
                        kif = imsg.data;
 
                        iface = if_lookup_name(leconf, kif->ifname);
-                       if (!iface)
+                       if (iface) {
+                               if_update_info(iface, kif);
+                               if_update(iface, AF_UNSPEC);
                                break;
+                       }
 
-                       if_update_info(iface, kif);
-                       if_update(iface, AF_UNSPEC);
+                       RB_FOREACH(l2vpn, l2vpn_head, &leconf->l2vpn_tree) {
+                               lif = l2vpn_if_find_name(l2vpn, kif->ifname);
+                               if (lif) {
+                                       lif->flags = kif->flags;
+                                       memcpy(lif->mac, kif->mac,
+                                           sizeof(lif->mac));
+                                       l2vpn_if_update(lif);
+                                       break;
+                               }
+                       }
                        break;
                case IMSG_NEWADDR:
                        if (imsg.hdr.len != IMSG_HEADER_SIZE +
@@ -529,10 +540,10 @@ ldpe_dispatch_lde(struct thread *thread)
        struct imsgev           *iev = THREAD_ARG(thread);
        struct imsgbuf          *ibuf = &iev->ibuf;
        struct imsg              imsg;
-       struct map               map;
-       struct notify_msg        nm;
+       struct map              *map;
+       struct notify_msg       *nm;
+       struct nbr              *nbr;
        int                      n, shut = 0;
-       struct nbr              *nbr = NULL;
 
        iev->ev_read = NULL;
 
@@ -552,9 +563,10 @@ ldpe_dispatch_lde(struct thread *thread)
                case IMSG_RELEASE_ADD:
                case IMSG_REQUEST_ADD:
                case IMSG_WITHDRAW_ADD:
-                       if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map))
+                       if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+                           sizeof(struct map))
                                fatalx("invalid size of map request");
-                       memcpy(&map, imsg.data, sizeof(map));
+                       map = imsg.data;
 
                        nbr = nbr_find_peerid(imsg.hdr.peerid);
                        if (nbr == NULL) {
@@ -567,16 +579,16 @@ ldpe_dispatch_lde(struct thread *thread)
 
                        switch (imsg.hdr.type) {
                        case IMSG_MAPPING_ADD:
-                               mapping_list_add(&nbr->mapping_list, &map);
+                               mapping_list_add(&nbr->mapping_list, map);
                                break;
                        case IMSG_RELEASE_ADD:
-                               mapping_list_add(&nbr->release_list, &map);
+                               mapping_list_add(&nbr->release_list, map);
                                break;
                        case IMSG_REQUEST_ADD:
-                               mapping_list_add(&nbr->request_list, &map);
+                               mapping_list_add(&nbr->request_list, map);
                                break;
                        case IMSG_WITHDRAW_ADD:
-                               mapping_list_add(&nbr->withdraw_list, &map);
+                               mapping_list_add(&nbr->withdraw_list, map);
                                break;
                        }
                        break;
@@ -613,9 +625,10 @@ ldpe_dispatch_lde(struct thread *thread)
                        }
                        break;
                case IMSG_NOTIFICATION_SEND:
-                       if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(nm))
+                       if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+                           sizeof(struct notify_msg))
                                fatalx("invalid size of OE request");
-                       memcpy(&nm, imsg.data, sizeof(nm));
+                       nm = imsg.data;
 
                        nbr = nbr_find_peerid(imsg.hdr.peerid);
                        if (nbr == NULL) {
@@ -626,7 +639,7 @@ ldpe_dispatch_lde(struct thread *thread)
                        if (nbr->state != NBR_STA_OPER)
                                break;
 
-                       send_notification_full(nbr->tcp, &nm);
+                       send_notification_full(nbr->tcp, nm);
                        break;
                case IMSG_CTL_END:
                case IMSG_CTL_SHOW_LIB:
@@ -791,8 +804,7 @@ ldpe_iface_af_ctl(struct ctl_conn *c, int af, unsigned int idx)
                                continue;
 
                        ictl = if_to_ctl(ia);
-                       imsg_compose_event(&c->iev,
-                            IMSG_CTL_SHOW_INTERFACE,
+                       imsg_compose_event(&c->iev, IMSG_CTL_SHOW_INTERFACE,
                            0, 0, -1, ictl, sizeof(struct ctl_iface));
                }
        }
index 052439df888c75e722ee02822ef9d1731281a8df..22b75eb008c2723efc24d08d6ea4052efa568768 100644 (file)
@@ -111,6 +111,9 @@ struct nbr {
        int                      flags;
 };
 #define F_NBR_GTSM_NEGOTIATED   0x01
+#define F_NBR_CAP_DYNAMIC       0x02
+#define F_NBR_CAP_TWCARD        0x04
+#define F_NBR_CAP_UNOTIF        0x08
 
 RB_HEAD(nbr_id_head, nbr);
 RB_PROTOTYPE(nbr_id_head, nbr, id_tree, nbr_id_compare)
@@ -159,6 +162,8 @@ void         recv_hello(struct in_addr, struct ldp_msg *, int, union ldpd_addr *,
 /* init.c */
 void    send_init(struct nbr *);
 int     recv_init(struct nbr *, char *, uint16_t);
+void    send_capability(struct nbr *, uint16_t, int);
+int     recv_capability(struct nbr *, char *, uint16_t);
 
 /* keepalive.c */
 void    send_keepalive(struct nbr *);
@@ -166,15 +171,16 @@ int        recv_keepalive(struct nbr *, char *, uint16_t);
 
 /* notification.c */
 void    send_notification_full(struct tcp_conn *, struct notify_msg *);
-void    send_notification(uint32_t, struct tcp_conn *, uint32_t,
-           uint16_t);
-void    send_notification_nbr(struct nbr *, uint32_t, uint32_t, uint16_t);
+void    send_notification(struct tcp_conn *, uint32_t, uint32_t, uint16_t);
+void    send_notification_rtlvs(struct nbr *, uint32_t, uint32_t, uint16_t,
+           uint16_t, uint16_t, char *);
 int     recv_notification(struct nbr *, char *, uint16_t);
 int     gen_status_tlv(struct ibuf *, uint32_t, uint32_t, uint16_t);
 
 /* address.c */
 void    send_address_single(struct nbr *, struct if_addr *, int);
 void    send_address_all(struct nbr *, int);
+void    send_mac_withdrawal(struct nbr *, struct map *, uint8_t *);
 int     recv_address(struct nbr *, char *, uint16_t);
 
 /* labelmapping.c */
@@ -182,6 +188,7 @@ int  recv_address(struct nbr *, char *, uint16_t);
 void    send_labelmessage(struct nbr *, uint16_t, struct mapping_head *);
 int     recv_labelmessage(struct nbr *, char *, uint16_t, uint16_t);
 int     gen_pw_status_tlv(struct ibuf *, uint32_t);
+uint16_t len_fec_tlv(struct map *);
 int     gen_fec_tlv(struct ibuf *, struct map *);
 int     tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *,
            uint16_t, struct map *);
index 77efdb47140c19fe7dacde80a0bf68a0570e8f74..b30604db0d1a1b55db11517509e98efb77355688 100644 (file)
@@ -313,7 +313,7 @@ log_hello_src(const struct hello_source *src)
 const char *
 log_map(const struct map *map)
 {
-       static char     buf[64];
+       static char     buf[128];
 
        switch (map->type) {
        case MAP_TYPE_WILDCARD:
@@ -327,11 +327,34 @@ log_map(const struct map *map)
                        return ("???");
                break;
        case MAP_TYPE_PWID:
-               if (snprintf(buf, sizeof(buf), "pwid %u (%s)",
-                   map->fec.pwid.pwid,
+               if (snprintf(buf, sizeof(buf), "pw-id %u group-id %u (%s)",
+                   map->fec.pwid.pwid, map->fec.pwid.group_id,
                    pw_type_name(map->fec.pwid.type)) == -1)
                        return ("???");
                break;
+       case MAP_TYPE_TYPED_WCARD:
+               if (snprintf(buf, sizeof(buf), "typed wildcard") < 0)
+                       return ("???");
+               switch (map->fec.twcard.type) {
+               case MAP_TYPE_PREFIX:
+                       if (snprintf(buf + strlen(buf), sizeof(buf) -
+                           strlen(buf), " (prefix, address-family %s)",
+                           af_name(map->fec.twcard.u.prefix_af)) < 0)
+                               return ("???");
+                       break;
+               case MAP_TYPE_PWID:
+                       if (snprintf(buf + strlen(buf), sizeof(buf) -
+                           strlen(buf), " (pwid, type %s)",
+                           pw_type_name(map->fec.twcard.u.pw_type)) < 0)
+                               return ("???");
+                       break;
+               default:
+                       if (snprintf(buf + strlen(buf), sizeof(buf) -
+                           strlen(buf), " (unknown type)") < 0)
+                               return ("???");
+                       break;
+               }
+               break;
        default:
                return ("???");
        }
@@ -464,6 +487,8 @@ msg_name(uint16_t msg)
                return ("initialization");
        case MSG_TYPE_KEEPALIVE:
                return ("keepalive");
+       case MSG_TYPE_CAPABILITY:
+               return ("capability");
        case MSG_TYPE_ADDR:
                return ("address");
        case MSG_TYPE_ADDRWITHDRAW:
@@ -557,6 +582,10 @@ status_code_name(uint32_t status)
                return ("Generic Misconfiguration Error");
        case S_WITHDRAW_MTHD:
                return ("Label Withdraw PW Status Method");
+       case S_UNSSUPORTDCAP:
+               return ("Unsupported Capability");
+       case S_ENDOFLIB:
+               return ("End-of-LIB");
        case S_TRANS_MISMTCH:
                return ("Transport Connection Mismatch");
        case S_DS_NONCMPLNCE:
@@ -577,6 +606,8 @@ pw_type_name(uint16_t pw_type)
                return ("Eth Tagged");
        case PW_TYPE_ETHERNET:
                return ("Ethernet");
+       case PW_TYPE_WILDCARD:
+               return ("Wildcard");
        default:
                snprintf(buf, sizeof(buf), "[%0x]", pw_type);
                return (buf);
index d24ceb1229dcee6519b932c7127a7ba6e97646c4..077d472850059129c9b9fc6d33f64ebd3edf97f8 100644 (file)
@@ -744,6 +744,7 @@ nbr_act_session_operational(struct nbr *nbr)
        lde_nbr.id = nbr->id;
        lde_nbr.v4_enabled = nbr->v4_enabled;
        lde_nbr.v6_enabled = nbr->v6_enabled;
+       lde_nbr.flags = nbr->flags;
        return (ldpe_imsg_compose_lde(IMSG_NEIGHBOR_UP, nbr->peerid, 0,
            &lde_nbr, sizeof(lde_nbr)));
 }
index d306361d5c2d78a4280107d13aa4ecd0197ac662..393994ed5f72686990055cd99c131b46384693e5 100644 (file)
@@ -24,6 +24,9 @@
 #include "ldpe.h"
 #include "ldp_debug.h"
 
+static int      gen_returned_tlvs(struct ibuf *, uint16_t, uint16_t, char *);
+static void     log_msg_notification(int, struct nbr *, struct notify_msg *);
+
 void
 send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)
 {
@@ -35,16 +38,10 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)
        size = LDP_HDR_SIZE + LDP_MSG_SIZE + STATUS_SIZE;
        if (nm->flags & F_NOTIF_PW_STATUS)
                size += PW_STATUS_TLV_SIZE;
-       if (nm->flags & F_NOTIF_FEC) {
-               size += TLV_HDR_SIZE;
-               switch (nm->fec.type) {
-               case MAP_TYPE_PWID:
-                       size += FEC_PWID_ELM_MIN_LEN;
-                       if (nm->fec.flags & F_MAP_PW_ID)
-                               size += sizeof(uint32_t);
-                       break;
-               }
-       }
+       if (nm->flags & F_NOTIF_FEC)
+               size += len_fec_tlv(&nm->fec);
+       if (nm->flags & F_NOTIF_RETURNED_TLVS)
+               size += TLV_HDR_SIZE * 2 + nm->rtlvs.length;
 
        if ((buf = ibuf_open(size)) == NULL)
                fatal(__func__);
@@ -58,22 +55,25 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)
                err |= gen_pw_status_tlv(buf, nm->pw_status);
        if (nm->flags & F_NOTIF_FEC)
                err |= gen_fec_tlv(buf, &nm->fec);
+       if (nm->flags & F_NOTIF_RETURNED_TLVS)
+               err |= gen_returned_tlvs(buf, nm->rtlvs.type, nm->rtlvs.length,
+                   nm->rtlvs.data);
        if (err) {
                ibuf_free(buf);
                return;
        }
 
-       if (tcp->nbr)
-               debug_msg_send("notification: lsr-id %s status %s%s",
-                   inet_ntoa(tcp->nbr->id), status_code_name(nm->status_code),
-                   (nm->status_code & STATUS_FATAL) ? " (fatal)" : "");
+       if (tcp->nbr) {
+               log_msg_notification(1, tcp->nbr, nm);
+               nbr_fsm(tcp->nbr, NBR_EVT_PDU_SENT);
+       }
 
        evbuf_enqueue(&tcp->wbuf, buf);
 }
 
 /* send a notification without optional tlvs */
 void
-send_notification(uint32_t status_code, struct tcp_conn *tcp, uint32_t msg_id,
+send_notification(struct tcp_conn *tcp, uint32_t status_code, uint32_t msg_id,
     uint16_t msg_type)
 {
        struct notify_msg        nm;
@@ -87,11 +87,24 @@ send_notification(uint32_t status_code, struct tcp_conn *tcp, uint32_t msg_id,
 }
 
 void
-send_notification_nbr(struct nbr *nbr, uint32_t status_code, uint32_t msg_id,
-    uint16_t msg_type)
+send_notification_rtlvs(struct nbr *nbr, uint32_t status_code, uint32_t msg_id,
+    uint16_t msg_type, uint16_t tlv_type, uint16_t tlv_len, char *tlv_data)
 {
-       send_notification(status_code, nbr->tcp, msg_id, msg_type);
-       nbr_fsm(nbr, NBR_EVT_PDU_SENT);
+       struct notify_msg        nm;
+
+       memset(&nm, 0, sizeof(nm));
+       nm.status_code = status_code;
+       nm.msg_id = msg_id;
+       nm.msg_type = msg_type;
+       /* do not append the given TLV if it's too big (shouldn't happen) */
+       if (tlv_len < 1024) {
+               nm.rtlvs.type = tlv_type;
+               nm.rtlvs.length = tlv_len;
+               nm.rtlvs.data = tlv_data;
+               nm.flags |= F_NOTIF_RETURNED_TLVS;
+       }
+
+       send_notification_full(nbr->tcp, &nm);
 }
 
 int
@@ -126,6 +139,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
        /* Optional Parameters */
        while (len > 0) {
                struct tlv      tlv;
+               uint16_t        tlv_type;
                uint16_t        tlv_len;
 
                if (len < sizeof(tlv)) {
@@ -134,6 +148,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
                }
 
                memcpy(&tlv, buf, TLV_HDR_SIZE);
+               tlv_type = ntohs(tlv.type);
                tlv_len = ntohs(tlv.length);
                if (tlv_len + TLV_HDR_SIZE > len) {
                        session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
@@ -142,7 +157,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
                buf += TLV_HDR_SIZE;
                len -= TLV_HDR_SIZE;
 
-               switch (ntohs(tlv.type)) {
+               switch (tlv_type) {
                case TLV_TYPE_EXTSTATUS:
                case TLV_TYPE_RETURNEDPDU:
                case TLV_TYPE_RETURNEDMSG:
@@ -172,8 +187,8 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
                        break;
                default:
                        if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
-                               send_notification_nbr(nbr, S_UNKNOWN_TLV,
-                                   msg.id, msg.type);
+                               send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
+                                   msg.id, msg.type, tlv_type, tlv_len, buf);
                        /* ignore unknown tlv */
                        break;
                }
@@ -181,9 +196,11 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
                len -= tlv_len;
        }
 
-       if (nm.status_code == S_PW_STATUS) {
+       /* sanity checks */
+       switch (nm.status_code) {
+       case S_PW_STATUS:
                if (!(nm.flags & (F_NOTIF_PW_STATUS|F_NOTIF_FEC))) {
-                       send_notification_nbr(nbr, S_MISS_MSG,
+                       send_notification(nbr->tcp, S_MISS_MSG,
                            msg.id, msg.type);
                        return (-1);
                }
@@ -192,15 +209,28 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
                case MAP_TYPE_PWID:
                        break;
                default:
-                       send_notification_nbr(nbr, S_BAD_TLV_VAL,
+                       send_notification(nbr->tcp, S_BAD_TLV_VAL,
+                           msg.id, msg.type);
+                       return (-1);
+               }
+               break;
+       case S_ENDOFLIB:
+               if (!(nm.flags & F_NOTIF_FEC)) {
+                       send_notification(nbr->tcp, S_MISS_MSG,
                            msg.id, msg.type);
                        return (-1);
                }
+               if (nm.fec.type != MAP_TYPE_TYPED_WCARD) {
+                       send_notification(nbr->tcp, S_BAD_TLV_VAL,
+                           msg.id, msg.type);
+                       return (-1);
+               }
+               break;
+       default:
+               break;
        }
 
-       debug_msg_recv("notification: lsr-id %s: %s%s", inet_ntoa(nbr->id),
-           status_code_name(ntohl(st.status_code)),
-           (st.status_code & htonl(STATUS_FATAL)) ? " (fatal)" : "");
+       log_msg_notification(0, nbr, &nm);
 
        if (st.status_code & htonl(STATUS_FATAL)) {
                if (nbr->state == NBR_STA_OPENSENT)
@@ -210,9 +240,16 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
                return (-1);
        }
 
-       if (nm.status_code == S_PW_STATUS)
+       /* lde needs to know about a few notification messages */
+       switch (nm.status_code) {
+       case S_PW_STATUS:
+       case S_ENDOFLIB:
                ldpe_imsg_compose_lde(IMSG_NOTIFICATION, nbr->peerid, 0,
                    &nm, sizeof(nm));
+               break;
+       default:
+               break;
+       }
 
        return (0);
 }
@@ -236,3 +273,42 @@ gen_status_tlv(struct ibuf *buf, uint32_t status_code, uint32_t msg_id,
 
        return (ibuf_add(buf, &st, STATUS_SIZE));
 }
+
+static int
+gen_returned_tlvs(struct ibuf *buf, uint16_t type, uint16_t length,
+    char *tlv_data)
+{
+       struct tlv       rtlvs;
+       struct tlv       tlv;
+       int              err;
+
+       rtlvs.type = htons(TLV_TYPE_RETURNED_TLVS);
+       rtlvs.length = htons(length + TLV_HDR_SIZE);
+       tlv.type = htons(type);
+       tlv.length = htons(length);
+
+       err = ibuf_add(buf, &rtlvs, sizeof(rtlvs));
+       err |= ibuf_add(buf, &tlv, sizeof(tlv));
+       err |= ibuf_add(buf, tlv_data, length);
+
+       return (err);
+}
+
+void
+log_msg_notification(int out, struct nbr *nbr, struct notify_msg *nm)
+{
+       if (nm->status_code & STATUS_FATAL) {
+               debug_msg(out, "notification: lsr-id %s, status %s "
+                   "(fatal error)", inet_ntoa(nbr->id),
+                   status_code_name(nm->status_code));
+               return;
+       }
+
+       debug_msg(out, "notification: lsr-id %s, status %s",
+           inet_ntoa(nbr->id), status_code_name(nm->status_code));
+       if (nm->flags & F_NOTIF_FEC)
+               debug_msg(out, "notification:   fec %s", log_map(&nm->fec));
+       if (nm->flags & F_NOTIF_PW_STATUS)
+               debug_msg(out, "notification:   pw-status %s",
+                   (nm->pw_status) ? "not forwarding" : "forwarding");
+}
index b085cac055e5bbab863d65ceb5c9dad8040c86ea..a7be0f6b42e0a578ac03736a62ea14f91297486c 100644 (file)
@@ -519,13 +519,7 @@ session_read(struct thread *thread)
                                        return (0);
                                }
                                break;
-                       case MSG_TYPE_ADDR:
-                       case MSG_TYPE_ADDRWITHDRAW:
-                       case MSG_TYPE_LABELMAPPING:
-                       case MSG_TYPE_LABELREQUEST:
-                       case MSG_TYPE_LABELWITHDRAW:
-                       case MSG_TYPE_LABELRELEASE:
-                       case MSG_TYPE_LABELABORTREQ:
+                       default:
                                if (nbr->state != NBR_STA_OPER) {
                                        session_shutdown(nbr, S_SHUTDOWN,
                                            msg->id, msg->type);
@@ -533,8 +527,6 @@ session_read(struct thread *thread)
                                        return (0);
                                }
                                break;
-                       default:
-                               break;
                        }
 
                        /* switch LDP packet type */
@@ -548,6 +540,9 @@ session_read(struct thread *thread)
                        case MSG_TYPE_KEEPALIVE:
                                ret = recv_keepalive(nbr, pdu, msg_size);
                                break;
+                       case MSG_TYPE_CAPABILITY:
+                               ret = recv_capability(nbr, pdu, msg_size);
+                               break;
                        case MSG_TYPE_ADDR:
                        case MSG_TYPE_ADDRWITHDRAW:
                                ret = recv_address(nbr, pdu, msg_size);
@@ -564,7 +559,7 @@ session_read(struct thread *thread)
                                log_debug("%s: unknown LDP message from nbr %s",
                                    __func__, inet_ntoa(nbr->id));
                                if (!(ntohs(msg->type) & UNKNOWN_FLAG))
-                                       send_notification_nbr(nbr,
+                                       send_notification(nbr->tcp,
                                            S_UNKNOWN_MSG, msg->id, msg->type);
                                /* ignore the message */
                                ret = 0;
@@ -632,7 +627,7 @@ session_shutdown(struct nbr *nbr, uint32_t status, uint32_t msg_id,
        case NBR_STA_OPER:
                log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
 
-               send_notification_nbr(nbr, status, msg_id, msg_type);
+               send_notification(nbr->tcp, status, msg_id, msg_type);
 
                nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
                break;
@@ -788,7 +783,7 @@ pending_conn_timeout(struct thread *thread)
         * notification message reliably.
         */
        tcp = tcp_new(pconn->fd, NULL);
-       send_notification(S_NO_HELLO, tcp, 0, 0);
+       send_notification(tcp, S_NO_HELLO, 0, 0);
        msgbuf_write(&tcp->wbuf.wbuf);
 
        pending_conn_del(pconn);
index 29f763e6a620bda546a6b85e35af0a98d836148e..88a778cccca7de604d798a253bc682b8cf9593c3 100644 (file)
@@ -131,7 +131,7 @@ pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
                sa.sadb_sa_exttype = SADB_EXT_SA;
                sa.sadb_sa_len = sizeof(sa) / 8;
                sa.sadb_sa_replay = 0;
-               sa.sadb_sa_spi = spi;
+               sa.sadb_sa_spi = htonl(spi);
                sa.sadb_sa_state = SADB_SASTATE_MATURE;
                break;
        }
@@ -280,7 +280,7 @@ pfkey_read(int sd, struct sadb_msg *h)
 }
 
 static int
-pfkey_reply(int sd, uint32_t *spip)
+pfkey_reply(int sd, uint32_t *spi)
 {
        struct sadb_msg hdr, *msg;
        struct sadb_ext *ext;
@@ -317,7 +317,7 @@ pfkey_reply(int sd, uint32_t *spip)
        }
 
        if (hdr.sadb_msg_type == SADB_GETSPI) {
-               if (spip == NULL) {
+               if (spi == NULL) {
                        explicit_bzero(data, len);
                        free(data);
                        return (0);
@@ -331,7 +331,7 @@ pfkey_reply(int sd, uint32_t *spip)
                    ext->sadb_ext_len * PFKEY2_CHUNK)) {
                        if (ext->sadb_ext_type == SADB_EXT_SA) {
                                sa = (struct sadb_sa *) ext;
-                               *spip = sa->sadb_sa_spi;
+                               *spi = ntohl(sa->sadb_sa_spi);
                                break;
                        }
                }
index 780d4bc1b8386bac505a67d52482648dacc34ebb..a9fe646938f4738823ab9c6dc288acbbf3787b57 100644 (file)
@@ -28,6 +28,7 @@ libfrr_la_SOURCES = \
        event_counter.c \
        grammar_sandbox.c \
        srcdest_table.c \
+       spf_backoff.c \
        strlcpy.c \
        strlcat.c
 
@@ -50,6 +51,7 @@ pkginclude_HEADERS = \
        skiplist.h qobj.h wheel.h \
        event_counter.h \
        monotime.h \
+       spf_backoff.h \
        srcdest_table.h
 
 noinst_HEADERS = \
index b166d8e0daeb734895d3563c9e11e33ab53c7d87..50976f201035820e8b46b68c347d87f89592a7f1 100644 (file)
@@ -1055,6 +1055,7 @@ node_parent ( enum node_type node )
     case BGP_IPV4M_NODE:
     case BGP_IPV6_NODE:
     case BGP_IPV6M_NODE:
+    case BGP_EVPN_NODE:
       ret = BGP_NODE;
       break;
     case KEYCHAIN_KEY_NODE:
@@ -1421,6 +1422,7 @@ cmd_exit (struct vty *vty)
     case BGP_VNC_L2_GROUP_NODE:
     case BGP_IPV6_NODE:
     case BGP_IPV6M_NODE:
+    case BGP_EVPN_NODE:
       vty->node = BGP_NODE;
       break;
     case LDP_IPV4_NODE:
@@ -1489,6 +1491,7 @@ DEFUN (config_end,
     case BGP_IPV4M_NODE:
     case BGP_IPV6_NODE:
     case BGP_IPV6M_NODE:
+    case BGP_EVPN_NODE:
     case RMAP_NODE:
     case OSPF_NODE:
     case OSPF6_NODE:
@@ -1626,7 +1629,8 @@ DEFUN (show_commandtree,
        show_commandtree_cmd,
        "show commandtree [permutations]",
        SHOW_STR
-       "Show command tree\n")
+       "Show command tree\n"
+       "Permutations that we are interested in\n")
 {
   return cmd_list_cmds (vty, argc == 3);
 }
index 29283418ce54281dd2e6f2f9392559eefacfc980..d62f7655eed8cf65ee108e0e0ba51e84655a8609 100644 (file)
@@ -105,6 +105,7 @@ enum node_type
   BGP_VNC_NVE_GROUP_NODE,      /* BGP VNC nve group */
   BGP_VNC_L2_GROUP_NODE,       /* BGP VNC L2 group */
   RFP_DEFAULTS_NODE,   /* RFP defaults node */
+  BGP_EVPN_NODE,               /* BGP EVPN node. */
   OSPF_NODE,                    /* OSPF protocol mode */
   OSPF6_NODE,                   /* OSPF protocol for IPv6 mode */
   LDP_NODE,                    /* LDP protocol mode */
index 052025a86c316d2ec3cce811bc920dbd426bc684..cd6e2f13aa3015f739cce78dc702e0f778a61d78 100644 (file)
@@ -135,15 +135,4 @@ extern void list_add_list (struct list *, struct list *);
     (L)->count--; \
   } while (0)
 
-/* Deprecated: 20050406 */
-#if !defined(QUAGGA_NO_DEPRECATED_INTERFACES)
-#warning "Using deprecated libfrr interfaces"
-#define LISTNODE_ADD(L,N) LISTNODE_ATTACH(L,N)
-#define LISTNODE_DELETE(L,N) LISTNODE_DETACH(L,N)
-#define nextnode(X) ((X) = (X)->next)
-#define getdata(X) listgetdata(X)
-#define LIST_LOOP(L,V,N) \
-  for (ALL_LIST_ELEMENTS_RO (L,N,V))
-#endif /* QUAGGA_NO_DEPRECATED_INTERFACES */
-
 #endif /* _ZEBRA_LINKLIST_H */
index a421f604439d44491711c83ca47e4268a1e5efcf..baf7bdbca13aefdea8c13f31642129bf868664dd 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -983,6 +983,7 @@ static const struct zebra_desc_table command_types[] = {
   DESC_ENTRY    (ZEBRA_INTERFACE_ENABLE_RADV),
   DESC_ENTRY    (ZEBRA_INTERFACE_DISABLE_RADV),
   DESC_ENTRY    (ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB),
+  DESC_ENTRY    (ZEBRA_INTERFACE_LINK_PARAMS),
   DESC_ENTRY   (ZEBRA_MPLS_LABELS_ADD),
   DESC_ENTRY   (ZEBRA_MPLS_LABELS_DELETE),
   DESC_ENTRY   (ZEBRA_IPV4_NEXTHOP_ADD),
index 0fd49404311b8e51f35f92f8cd53bab926095423..ad44bf511a2c6c558df784fcc7b935dfd60dc171 100644 (file)
 
 #ifndef TIMESPEC_TO_TIMEVAL
 /* should be in sys/time.h on BSD & Linux libcs */
-#define TIMESPEC_TO_TIMEVAL(tv, ts) do {       \
-       (tv)->tv_sec = (ts)->tv_sec;            \
-       (tv)->tv_usec = (ts)->tv_nsec / 1000;   \
-       } while (0)
+#define TIMESPEC_TO_TIMEVAL(tv, ts) do {        \
+        (tv)->tv_sec = (ts)->tv_sec;            \
+        (tv)->tv_usec = (ts)->tv_nsec / 1000;   \
+        } while (0)
 #endif
 #ifndef TIMEVAL_TO_TIMESPEC
 /* should be in sys/time.h on BSD & Linux libcs */
-#define TIMEVAL_TO_TIMESPEC(tv, ts) do {       \
-       (ts)->tv_sec = (tv)->tv_sec;            \
-       (ts)->tv_nsec = (tv)->tv_usec * 1000;   \
-       } while (0)
+#define TIMEVAL_TO_TIMESPEC(tv, ts) do {        \
+        (ts)->tv_sec = (tv)->tv_sec;            \
+        (ts)->tv_nsec = (tv)->tv_usec * 1000;   \
+        } while (0)
 #endif
 
 static inline time_t monotime(struct timeval *tvo)
 {
-       struct timespec ts;
+        struct timespec ts;
 
-       clock_gettime(CLOCK_MONOTONIC, &ts);
-       if (tvo) {
-               TIMESPEC_TO_TIMEVAL(tvo, &ts);
-       }
-       return ts.tv_sec;
+        clock_gettime(CLOCK_MONOTONIC, &ts);
+        if (tvo) {
+                TIMESPEC_TO_TIMEVAL(tvo, &ts);
+        }
+        return ts.tv_sec;
 }
 
 /* the following two return microseconds, not time_t!
@@ -53,25 +53,25 @@ static inline time_t monotime(struct timeval *tvo)
  * code more readable
  */
 static inline int64_t monotime_since(const struct timeval *ref,
-                                    struct timeval *out)
+                                     struct timeval *out)
 {
-       struct timeval tv;
-       monotime(&tv);
-       timersub(&tv, ref, &tv);
-       if (out)
-               *out = tv;
-       return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
+        struct timeval tv;
+        monotime(&tv);
+        timersub(&tv, ref, &tv);
+        if (out)
+                *out = tv;
+        return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
 }
 
 static inline int64_t monotime_until(const struct timeval *ref,
-                                    struct timeval *out)
+                                     struct timeval *out)
 {
-       struct timeval tv;
-       monotime(&tv);
-       timersub(ref, &tv, &tv);
-       if (out)
-               *out = tv;
-       return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
+        struct timeval tv;
+        monotime(&tv);
+        timersub(ref, &tv, &tv);
+        if (out)
+                *out = tv;
+        return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
 }
 
 #endif /* _FRR_MONOTIME_H */
index 4539d829724bef944ca20670e7b01806945da988..9a2fc4af09dea1abd2b0868286a5738015f59207 100644 (file)
@@ -972,7 +972,7 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name,
       apply_mask_ipv6 ((struct prefix_ipv6 *) &p_tmp);
 
       break;
-    case AFI_ETHER:
+    case AFI_L2VPN:
     default:
       vty_out (vty, "%% Unrecognized AFI (%d)%s", afi, VTY_NEWLINE);
       return CMD_WARNING;
index 7231715a52199d8a27dd06cae09b1080def07366..dec22a44a3a0f58c17521e1b54cf8772c6c7a7d8 100644 (file)
@@ -209,7 +209,7 @@ afi2family (afi_t afi)
     return AF_INET;
   else if (afi == AFI_IP6)
     return AF_INET6;
-  else if (afi == AFI_ETHER)
+  else if (afi == AFI_L2VPN)
     return AF_ETHERNET;
   return 0;
 }
@@ -222,7 +222,7 @@ family2afi (int family)
   else if (family == AF_INET6)
     return AFI_IP6;
   else if (family == AF_ETHERNET)
-    return AFI_ETHER;
+    return AFI_L2VPN;
   return 0;
 }
 
@@ -234,8 +234,8 @@ afi2str(afi_t afi)
        return "IPv4";
     case AFI_IP6:
        return "IPv6";
-    case AFI_ETHER:
-       return "ethernet";
+    case AFI_L2VPN:
+       return "l2vpn";
     case AFI_MAX:
         return "bad-value";
     default:
@@ -256,6 +256,8 @@ safi2str(safi_t safi)
        return "encap";
     case SAFI_MPLS_VPN:
        return "vpn";
+    case SAFI_EVPN:
+       return "evpn";
   }
   return NULL;
 }
@@ -300,15 +302,15 @@ prefix_copy (struct prefix *dest, const struct prefix *src)
     dest->u.prefix4 = src->u.prefix4;
   else if (src->family == AF_INET6)
     dest->u.prefix6 = src->u.prefix6;
+  else if (src->family == AF_ETHERNET)
+    {
+      memcpy (&dest->u.prefix_evpn, &src->u.prefix_evpn, sizeof (struct evpn_addr));
+    }
   else if (src->family == AF_UNSPEC)
     {
       dest->u.lp.id = src->u.lp.id;
       dest->u.lp.adv_router = src->u.lp.adv_router;
     }
-  else if (src->family == AF_ETHERNET)
-    {
-      dest->u.prefix_eth = src->u.prefix_eth;
-    }
   else
     {
       zlog (NULL, LOG_ERR, "prefix_copy(): Unknown address family %d",
@@ -342,10 +344,9 @@ prefix_same (const struct prefix *p1, const struct prefix *p2)
       if (p1->family == AF_INET6 )
        if (IPV6_ADDR_SAME (&p1->u.prefix6.s6_addr, &p2->u.prefix6.s6_addr))
          return 1;
-      if (p1->family == AF_ETHERNET) {
-       if (!memcmp(p1->u.prefix_eth.octet, p2->u.prefix_eth.octet, ETHER_ADDR_LEN))
-           return 1;
-      }
+      if (p1->family == AF_ETHERNET )
+        if (!memcmp (&p1->u.prefix_evpn, &p2->u.prefix_evpn, sizeof (struct evpn_addr)))
+          return 1;
     }
   return 0;
 }
@@ -408,6 +409,9 @@ prefix_common_bits (const struct prefix *p1, const struct prefix *p2)
     length = IPV4_MAX_BYTELEN;
   if (p1->family == AF_INET6)
     length = IPV6_MAX_BYTELEN;
+  if (p1->family == AF_ETHERNET)
+    length = 8 * sizeof (struct evpn_addr);
+
   if (p1->family != p2->family || !length)
     return -1;
 
@@ -849,23 +853,46 @@ str2prefix (const char *str, struct prefix *p)
 }
 
 const char *
-prefix2str (union prefix46constptr pu, char *str, int size)
+prefix2str (union prefixconstptr pu, char *str, int size)
 {
   const struct prefix *p = pu.p;
+  char buf[PREFIX2STR_BUFFER];
 
-  if (p->family == AF_ETHERNET)
-    {
-      snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x/%d",
-               p->u.prefix_eth.octet[0], p->u.prefix_eth.octet[1],
-               p->u.prefix_eth.octet[2], p->u.prefix_eth.octet[3],
-               p->u.prefix_eth.octet[4], p->u.prefix_eth.octet[5],
-               p->prefixlen);
-    }
-  else
+  switch (p->family)
     {
-      char buf[PREFIX2STR_BUFFER];
-      inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf));
-      snprintf(str, size, "%s/%d", buf, p->prefixlen);
+      case AF_INET:
+      case AF_INET6:
+        snprintf (str, size, "%s/%d",
+                  inet_ntop (p->family, &p->u.prefix, buf, PREFIX2STR_BUFFER),
+                  p->prefixlen);
+        break;
+
+      case AF_ETHERNET:
+        if (p->u.prefix_evpn.route_type == 5)
+          {
+            u_char family;
+            family = (p->u.prefix_evpn.flags & (IP_ADDR_V4 | IP_PREFIX_V4)) ?
+              AF_INET : AF_INET6;
+            snprintf (str, size, "[%d]:[%u][%s]/%d",
+                      p->u.prefix_evpn.route_type,
+                      p->u.prefix_evpn.eth_tag,
+                      inet_ntop (family, &p->u.prefix_evpn.ip.addr,
+                                 buf, PREFIX2STR_BUFFER),
+                      p->prefixlen);
+          }
+        else
+          {
+            sprintf (str, "UNK AF_ETHER prefix");
+            snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x/%d",
+                     p->u.prefix_eth.octet[0], p->u.prefix_eth.octet[1],
+                     p->u.prefix_eth.octet[2], p->u.prefix_eth.octet[3],
+                     p->u.prefix_eth.octet[4], p->u.prefix_eth.octet[5],
+                     p->prefixlen);
+          }
+        break;
+      default:
+        sprintf (str, "UNK prefix");
+        break;
     }
 
   return str;
index 56adce5eabfe277d0d0690f7a198275f25378647..eb3ae3dafb618713b8f9e327ad4fb0c3e81e22bf 100644 (file)
  */
 struct ethaddr {
     u_char octet[ETHER_ADDR_LEN];
-} __packed;
+} __attribute__ ((packed));
 
 
+/* length is the number of valuable bits of prefix structure 
+* 18 bytes is current length in structure, if address is ipv4
+* 30 bytes is in case of ipv6
+*/
+#define PREFIX_LEN_ROUTE_TYPE_5_IPV4 (18*8)
+#define PREFIX_LEN_ROUTE_TYPE_5_IPV6 (30*8)
+
+/* EVPN address (RFC 7432) */
+struct evpn_addr
+{
+  u_char route_type;
+  u_char flags;
+#define IP_ADDR_NONE      0x0
+#define IP_ADDR_V4        0x1
+#define IP_ADDR_V6        0x2
+#define IP_PREFIX_V4      0x4
+#define IP_PREFIX_V6      0x8
+  struct ethaddr mac;
+  uint32_t eth_tag;
+  u_char ip_prefix_length;
+  union
+  {
+    u_char addr;
+    struct in_addr v4_addr;
+    struct in6_addr v6_addr;
+  } ip;
+};
+
+/* EVPN prefix structure. */
+struct prefix_evpn
+{
+  u_char family;
+  u_char prefixlen;
+  struct evpn_addr prefix __attribute__ ((aligned (8)));
+};
+
 /*
  * A struct prefix contains an address family, a prefix length, and an
  * address.  This can represent either a 'network prefix' as defined
@@ -88,6 +124,7 @@ struct prefix
     struct ethaddr prefix_eth; /* AF_ETHERNET */
     u_char val[8];
     uintptr_t ptr;
+    struct evpn_addr prefix_evpn;
   } u __attribute__ ((aligned (8)));
 };
 
@@ -152,18 +189,20 @@ struct prefix_sg
  * side, which strips type safety since the cast will accept any pointer
  * type.)
  */
-union prefix46ptr
+union prefixptr
 {
   struct prefix *p;
   struct prefix_ipv4 *p4;
   struct prefix_ipv6 *p6;
+  struct prefix_evpn *evp;
 } __attribute__ ((transparent_union));
 
-union prefix46constptr
+union prefixconstptr
 {
   const struct prefix *p;
   const struct prefix_ipv4 *p4;
   const struct prefix_ipv6 *p6;
+  const struct prefix_evpn *evp;
 } __attribute__ ((transparent_union));
 
 #ifndef INET_ADDRSTRLEN
@@ -237,7 +276,7 @@ extern int str2prefix (const char *, struct prefix *);
 
 #define PREFIX2STR_BUFFER  PREFIX_STRLEN
 
-extern const char *prefix2str (union prefix46constptr, char *, int);
+extern const char *prefix2str (union prefixconstptr, char *, int);
 extern int prefix_match (const struct prefix *, const struct prefix *);
 extern int prefix_same (const struct prefix *, const struct prefix *);
 extern int prefix_cmp (const struct prefix *, const struct prefix *);
diff --git a/lib/spf_backoff.c b/lib/spf_backoff.c
new file mode 100644 (file)
index 0000000..e923f23
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * This is an implementation of the IETF SPF delay algorithm
+ * as explained in draft-ietf-rtgwg-backoff-algo-04
+ *
+ * Created: 25-01-2017 by S. Litkowski
+ *
+ * Copyright (C) 2017 Orange Labs http://www.orange.com/
+ * Copyright (C) 2017 by Christian Franke, Open Source Routing / NetDEF Inc.
+ *
+ * This file is part of FreeRangeRouting (FRR)
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "spf_backoff.h"
+
+#include "command.h"
+#include "memory.h"
+#include "thread.h"
+#include "vty.h"
+
+DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF, "SPF backoff")
+DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF_NAME, "SPF backoff name")
+
+static bool debug_spf_backoff = false;
+#define backoff_debug(...) \
+  do \
+    { \
+      if (debug_spf_backoff) \
+        zlog_debug(__VA_ARGS__); \
+    } \
+  while (0)
+
+enum spf_backoff_state {
+  SPF_BACKOFF_QUIET,
+  SPF_BACKOFF_SHORT_WAIT,
+  SPF_BACKOFF_LONG_WAIT
+};
+
+struct spf_backoff {
+  struct thread_master *m;
+
+  /* Timers as per draft */
+  long init_delay;
+  long short_delay;
+  long long_delay;
+  long holddown;
+  long timetolearn;
+
+  /* State machine */
+  enum spf_backoff_state state;
+  struct thread *t_holddown;
+  struct thread *t_timetolearn;
+
+  /* For debugging */
+  char *name;
+  struct timeval first_event_time;
+  struct timeval last_event_time;
+};
+
+static const char *
+spf_backoff_state2str(enum spf_backoff_state state)
+{
+  switch (state)
+    {
+    case SPF_BACKOFF_QUIET:
+      return "QUIET";
+    case SPF_BACKOFF_SHORT_WAIT:
+      return "SHORT_WAIT";
+    case SPF_BACKOFF_LONG_WAIT:
+      return "LONG_WAIT";
+    }
+  return "???";
+}
+
+struct spf_backoff *
+spf_backoff_new(struct thread_master *m,
+                const char *name,
+                long init_delay,
+                long short_delay,
+                long long_delay,
+                long holddown,
+                long timetolearn)
+{
+  struct spf_backoff *rv;
+
+  rv = XCALLOC(MTYPE_SPF_BACKOFF, sizeof(*rv));
+  rv->m = m;
+
+  rv->init_delay = init_delay;
+  rv->short_delay = short_delay;
+  rv->long_delay = long_delay;
+  rv->holddown = holddown;
+  rv->timetolearn = timetolearn;
+
+  rv->state = SPF_BACKOFF_QUIET;
+
+  rv->name = XSTRDUP(MTYPE_SPF_BACKOFF_NAME, name);
+  return rv;
+}
+
+void
+spf_backoff_free(struct spf_backoff *backoff)
+{
+  if (!backoff)
+    return;
+
+  THREAD_TIMER_OFF(backoff->t_holddown);
+  THREAD_TIMER_OFF(backoff->t_timetolearn);
+  XFREE(MTYPE_SPF_BACKOFF_NAME, backoff->name);
+
+  XFREE(MTYPE_SPF_BACKOFF, backoff);
+}
+
+static int
+spf_backoff_timetolearn_elapsed(struct thread *thread)
+{
+  struct spf_backoff *backoff = THREAD_ARG(thread);
+
+  backoff->t_timetolearn = NULL;
+  backoff->state = SPF_BACKOFF_LONG_WAIT;
+  backoff_debug("SPF Back-off(%s) TIMETOLEARN elapsed, move to state %s",
+                backoff->name, spf_backoff_state2str(backoff->state));
+  return 0;
+}
+
+static int
+spf_backoff_holddown_elapsed(struct thread *thread)
+{
+  struct spf_backoff *backoff = THREAD_ARG(thread);
+
+  backoff->t_holddown = NULL;
+  THREAD_TIMER_OFF(backoff->t_timetolearn);
+  timerclear(&backoff->first_event_time);
+  backoff->state = SPF_BACKOFF_QUIET;
+  backoff_debug("SPF Back-off(%s) HOLDDOWN elapsed, move to state %s",
+                backoff->name, spf_backoff_state2str(backoff->state));
+  return 0;
+}
+
+long spf_backoff_schedule(struct spf_backoff *backoff)
+{
+  long rv;
+  struct timeval now;
+
+  gettimeofday(&now, NULL);
+
+  backoff_debug("SPF Back-off(%s) schedule called in state %s",
+                backoff->name, spf_backoff_state2str(backoff->state));
+
+  backoff->last_event_time = now;
+
+  switch (backoff->state)
+    {
+    case SPF_BACKOFF_QUIET:
+      backoff->state = SPF_BACKOFF_SHORT_WAIT;
+      THREAD_TIMER_MSEC_ON(backoff->m, backoff->t_timetolearn,
+                           spf_backoff_timetolearn_elapsed, backoff,
+                           backoff->timetolearn);
+      THREAD_TIMER_MSEC_ON(backoff->m, backoff->t_holddown,
+                           spf_backoff_holddown_elapsed, backoff,
+                           backoff->holddown);
+      backoff->first_event_time = now;
+      rv = backoff->init_delay;
+      break;
+    case SPF_BACKOFF_SHORT_WAIT:
+    case SPF_BACKOFF_LONG_WAIT:
+      THREAD_TIMER_OFF(backoff->t_holddown);
+      THREAD_TIMER_MSEC_ON(backoff->m, backoff->t_holddown,
+                           spf_backoff_holddown_elapsed, backoff,
+                           backoff->holddown);
+      if (backoff->state == SPF_BACKOFF_SHORT_WAIT)
+        rv = backoff->short_delay;
+      else
+        rv = backoff->long_delay;
+      break;
+    default:
+      zlog_warn("SPF Back-off(%s) in unknown state", backoff->name);
+      rv = backoff->init_delay;
+    }
+
+  backoff_debug("SPF Back-off(%s) changed state to %s and returned %ld delay",
+                backoff->name, spf_backoff_state2str(backoff->state), rv);
+  return rv;
+}
+
+static const char *
+timeval_format(struct timeval *tv)
+{
+  struct tm tm_store;
+  struct tm *tm;
+  static char timebuf[256];
+
+  if (!tv->tv_sec && !tv->tv_usec)
+    return "(never)";
+
+  tm = localtime_r(&tv->tv_sec, &tm_store);
+  if (!tm || strftime(timebuf, sizeof(timebuf),
+                      "%Z %a %Y-%m-%d %H:%M:%S", tm) == 0)
+    {
+      return "???";
+    }
+
+  size_t offset = strlen(timebuf);
+  snprintf(timebuf + offset, sizeof(timebuf) - offset, ".%ld", tv->tv_usec);
+
+  return timebuf;
+}
+
+void
+spf_backoff_show(struct spf_backoff *backoff, struct vty *vty,
+                 const char *prefix)
+{
+  vty_out(vty, "%sCurrent state:     %s%s", prefix,
+          spf_backoff_state2str(backoff->state), VTY_NEWLINE);
+  vty_out(vty, "%sInit timer:        %ld msec%s", prefix,
+          backoff->init_delay, VTY_NEWLINE);
+  vty_out(vty, "%sShort timer:       %ld msec%s", prefix,
+          backoff->short_delay, VTY_NEWLINE);
+  vty_out(vty, "%sLong timer:        %ld msec%s", prefix,
+          backoff->long_delay, VTY_NEWLINE);
+  vty_out(vty, "%sHolddown timer:    %ld msec%s", prefix,
+          backoff->holddown, VTY_NEWLINE);
+  if (backoff->t_holddown)
+    {
+      struct timeval remain = thread_timer_remain(backoff->t_holddown);
+      vty_out(vty, "%s                   Still runs for %ld msec%s",
+              prefix, remain.tv_sec * 1000 + remain.tv_usec/1000, VTY_NEWLINE);
+    }
+  else
+    {
+      vty_out(vty, "%s                   Inactive%s", prefix, VTY_NEWLINE);
+    }
+
+  vty_out(vty, "%sTimeToLearn timer: %ld msec%s", prefix,
+          backoff->timetolearn, VTY_NEWLINE);
+  if (backoff->t_timetolearn)
+    {
+      struct timeval remain = thread_timer_remain(backoff->t_timetolearn);
+      vty_out(vty, "%s                   Still runs for %ld msec%s",
+              prefix, remain.tv_sec * 1000 + remain.tv_usec/1000, VTY_NEWLINE);
+    }
+  else
+    {
+      vty_out(vty, "%s                   Inactive%s", prefix, VTY_NEWLINE);
+    }
+
+  vty_out(vty, "%sFirst event:       %s%s", prefix,
+          timeval_format(&backoff->first_event_time), VTY_NEWLINE);
+  vty_out(vty, "%sLast event:        %s%s", prefix,
+          timeval_format(&backoff->last_event_time), VTY_NEWLINE);
+}
+
+DEFUN(spf_backoff_debug,
+      spf_backoff_debug_cmd,
+      "debug spf-delay-ietf",
+      DEBUG_STR
+      "SPF Back-off Debugging\n")
+{
+  debug_spf_backoff = true;
+  return CMD_SUCCESS;
+}
+
+DEFUN(no_spf_backoff_debug,
+      no_spf_backoff_debug_cmd,
+      "no debug spf-delay-ietf",
+      NO_STR
+      DEBUG_STR
+      "SPF Back-off Debugging\n")
+{
+  debug_spf_backoff = false;
+  return CMD_SUCCESS;
+}
+
+int
+spf_backoff_write_config(struct vty *vty)
+{
+  int written = 0;
+
+  if (debug_spf_backoff)
+    {
+      vty_out(vty, "debug spf-delay-ietf%s", VTY_NEWLINE);
+      written++;
+    }
+
+  return written;
+}
+
+void
+spf_backoff_cmd_init(void)
+{
+  install_element(ENABLE_NODE, &spf_backoff_debug_cmd);
+  install_element(CONFIG_NODE, &spf_backoff_debug_cmd);
+  install_element(ENABLE_NODE, &no_spf_backoff_debug_cmd);
+  install_element(CONFIG_NODE, &no_spf_backoff_debug_cmd);
+}
+
+long
+spf_backoff_init_delay(struct spf_backoff *backoff)
+{
+  return backoff->init_delay;
+}
+
+long
+spf_backoff_short_delay(struct spf_backoff *backoff)
+{
+  return backoff->short_delay;
+}
+
+long
+spf_backoff_long_delay(struct spf_backoff *backoff)
+{
+  return backoff->long_delay;
+}
+
+long
+spf_backoff_holddown(struct spf_backoff *backoff)
+{
+  return backoff->holddown;
+}
+
+long
+spf_backoff_timetolearn(struct spf_backoff *backoff)
+{
+  return backoff->timetolearn;
+}
diff --git a/lib/spf_backoff.h b/lib/spf_backoff.h
new file mode 100644 (file)
index 0000000..552ca4a
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * This is an implementation of the IETF SPF delay algorithm
+ * as explained in draft-ietf-rtgwg-backoff-algo-04
+ *
+ * Created: 25-01-2017 by S. Litkowski
+ *
+ * Copyright (C) 2017 Orange Labs http://www.orange.com/
+ * Copyright (C) 2017 by Christian Franke, Open Source Routing / NetDEF Inc.
+ *
+ * This file is part of FreeRangeRouting (FRR)
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef _ZEBRA_SPF_BACKOFF_H
+#define _ZEBRA_SPF_BACKOFF_H
+
+struct spf_backoff;
+struct thread_master;
+struct vty;
+
+struct spf_backoff *spf_backoff_new(struct thread_master *m,
+                                    const char *name,
+                                    long init_delay,
+                                    long short_delay,
+                                    long long_delay,
+                                    long holddown,
+                                    long timetolearn);
+
+void spf_backoff_free(struct spf_backoff *backoff);
+
+/* Called whenever an IGP event is received, returns how many
+ * milliseconds routing table computation should be delayed */
+long spf_backoff_schedule(struct spf_backoff *backoff);
+
+/* Shows status of SPF backoff instance */
+void spf_backoff_show(struct spf_backoff *backoff,
+                      struct vty *vty,
+                      const char *prefix);
+
+/* Writes out global SPF backoff debug config */
+int spf_backoff_write_config(struct vty *vty);
+
+/* Registers global SPF backoff debug commands */
+void spf_backoff_cmd_init(void);
+
+/* Accessor functions for SPF backoff parameters */
+long spf_backoff_init_delay(struct spf_backoff *backoff);
+long spf_backoff_short_delay(struct spf_backoff *backoff);
+long spf_backoff_long_delay(struct spf_backoff *backoff);
+long spf_backoff_holddown(struct spf_backoff *backoff);
+long spf_backoff_timetolearn(struct spf_backoff *backoff);
+
+#endif
index dd148fa41d2b906277a34e9aa2776cb320f2b09c..04c9eff79a72fb9ec9d76e0b93c8e8be24dd5711 100644 (file)
@@ -242,7 +242,7 @@ srcdest_route_next(struct route_node *rn)
 }
 
 struct route_node *
-srcdest_rnode_get (struct route_table *table, union prefix46ptr dst_pu,
+srcdest_rnode_get (struct route_table *table, union prefixptr dst_pu,
                   struct prefix_ipv6 *src_p)
 {
   struct prefix_ipv6 *dst_p = dst_pu.p6;
@@ -253,7 +253,7 @@ srcdest_rnode_get (struct route_table *table, union prefix46ptr dst_pu,
 }
 
 struct route_node *
-srcdest_rnode_lookup (struct route_table *table, union prefix46ptr dst_pu,
+srcdest_rnode_lookup (struct route_table *table, union prefixptr dst_pu,
                       struct prefix_ipv6 *src_p)
 {
   struct prefix_ipv6 *dst_p = dst_pu.p6;
index 59111b5d17b6d414519757bec80e1f6c96724f53..207f5d121d9eacfb6f3a86dfb9f82100a6642594 100644 (file)
@@ -57,10 +57,10 @@ extern route_table_delegate_t _srcdest_srcnode_delegate;
 
 extern struct route_table *srcdest_table_init(void);
 extern struct route_node *srcdest_rnode_get(struct route_table *table,
-                                            union prefix46ptr dst_pu,
+                                            union prefixptr dst_pu,
                                             struct prefix_ipv6 *src_p);
 extern struct route_node *srcdest_rnode_lookup(struct route_table *table,
-                                            union prefix46ptr dst_pu,
+                                            union prefixptr dst_pu,
                                             struct prefix_ipv6 *src_p);
 extern void srcdest_rnode_prefixes (struct route_node *rn, struct prefix **p,
                                     struct prefix **src_p);
index 49964e7743f6b87f115379fb85234bcd2b481504..0489246ea67ed4fb83af81f506fc076cfaa7c240 100644 (file)
@@ -126,11 +126,6 @@ struct cpu_thread_history
   const char *funcname;
 };
 
-/* Clocks supported by Quagga */
-enum quagga_clkid {
-  QUAGGA_CLK_MONOTONIC = 1,    /* monotonic, against an indeterminate base */
-};
-
 /* Struct timeval's tv_usec one second value.  */
 #define TIMER_SECOND_MICRO 1000000L
 
index ce6349bf779c7e90f2a85876ceb857c143ca151f..3a3265f54d528b9b25490be41bb92f8ecb0ae0d4 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -750,6 +750,7 @@ vty_end_config (struct vty *vty)
     case BGP_IPV4M_NODE:
     case BGP_IPV6_NODE:
     case BGP_IPV6M_NODE:
+    case BGP_EVPN_NODE:
     case RMAP_NODE:
     case OSPF_NODE:
     case OSPF6_NODE:
index f3be18a66081db7738dbcff3f77bbed934aa5f6a..72a4f6394d1f93d887581912a5b7b96599bbe0fb 100644 (file)
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -177,7 +177,7 @@ struct vty_arg
 };
 
 /* Integrated configuration file. */
-#define INTEGRATE_DEFAULT_CONFIG "Frr.conf"
+#define INTEGRATE_DEFAULT_CONFIG "frr.conf"
 
 /* Small macro to determine newline is newline only or linefeed needed. */
 #define VTY_NEWLINE  ((vty->type == VTY_TERM) ? "\r\n" : "\n")
index 19a26b523005101c518482191dadd993a1c468db..760264d752fe72ad60616ad21df0416f67dcf43c 100644 (file)
@@ -401,8 +401,8 @@ extern const char *zserv_command_string (unsigned int command);
 typedef enum {
   AFI_IP  = 1,
   AFI_IP6 = 2,
-  AFI_ETHER = 3,                /* RFC 1700 has "6" for 802.* */
-  AFI_MAX = 4
+  AFI_L2VPN = 4,
+  AFI_MAX = 5
 } afi_t;
 
 /* Subsequent Address Family Identifier. */
@@ -412,7 +412,8 @@ typedef enum {
 #define SAFI_RESERVED_4           4
 #define SAFI_ENCAP               5
 #define SAFI_RESERVED_5           5
-#define SAFI_MAX                  6
+#define SAFI_EVPN                 6
+#define SAFI_MAX                  7
 
 #define IANA_SAFI_RESERVED            0
 #define IANA_SAFI_UNICAST             1
@@ -442,6 +443,7 @@ typedef enum {
 #define IANA_SAFI_UNICAST             1
 #define IANA_SAFI_MULTICAST           2
 #define IANA_SAFI_ENCAP               7
+#define IANA_SAFI_EVPN                70
 #define IANA_SAFI_MPLS_VPN            128
 
 /* Default Administrative Distance of each protocol. */
@@ -482,6 +484,8 @@ static inline afi_t afi_iana2int (iana_afi_t afi)
     return AFI_IP;
   if (afi == IANA_AFI_IPV6)
     return AFI_IP6;
+  if (afi == IANA_AFI_L2VPN)
+    return AFI_L2VPN;
   return AFI_MAX;
 }
 
@@ -491,6 +495,8 @@ static inline iana_afi_t afi_int2iana (afi_t afi)
     return IANA_AFI_IPV4;
   if (afi == AFI_IP6)
     return IANA_AFI_IPV6;
+  if (afi == AFI_L2VPN)
+    return IANA_AFI_L2VPN;
   return IANA_AFI_RESERVED;
 }
 
@@ -504,6 +510,8 @@ static inline safi_t safi_iana2int (safi_t safi)
     return SAFI_MPLS_VPN;
   if (safi == IANA_SAFI_ENCAP)
     return SAFI_ENCAP;
+  if (safi == IANA_SAFI_EVPN)
+    return SAFI_EVPN;
   return SAFI_MAX;
 }
 
@@ -517,6 +525,8 @@ static inline safi_t safi_int2iana (safi_t safi)
     return IANA_SAFI_MPLS_VPN;
   if (safi == SAFI_ENCAP)
     return IANA_SAFI_ENCAP;
+  if (safi == SAFI_EVPN)
+    return IANA_SAFI_EVPN;
   return IANA_SAFI_RESERVED;
 }
 
index 76bee9cf55eadc1f75adc90a2ce1264251f0d1fa..1904623e714208e3c32e5c880cc71ad2878f5b71 100644 (file)
@@ -217,7 +217,7 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient,
   struct stream *s;
   struct zapi_ipv6 api;
   unsigned long ifindex;
-  struct prefix_ipv6 p, src_p;
+  struct prefix p, src_p;
   struct in6_addr *nexthop;
 
   if (ospf6 == NULL)
@@ -235,17 +235,17 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient,
   api.message = stream_getc (s);
 
   /* IPv6 prefix. */
-  memset (&p, 0, sizeof (struct prefix_ipv6));
+  memset (&p, 0, sizeof (struct prefix));
   p.family = AF_INET6;
   p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc (s));
-  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+  stream_get (&p.u.prefix6, s, PSIZE (p.prefixlen));
 
-  memset (&src_p, 0, sizeof (struct prefix_ipv6));
+  memset (&src_p, 0, sizeof (struct prefix));
   src_p.family = AF_INET6;
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_SRCPFX))
     {
       src_p.prefixlen = stream_getc (s);
-      stream_get (&src_p.prefix, s, PSIZE (src_p.prefixlen));
+      stream_get (&src_p.u.prefix6, s, PSIZE (src_p.prefixlen));
     }
 
   if (src_p.prefixlen)
@@ -294,10 +294,10 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient,
     }
  
   if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
-    ospf6_asbr_redistribute_add (api.type, ifindex, (struct prefix *) &p,
+    ospf6_asbr_redistribute_add (api.type, ifindex, &p,
                                  api.nexthop_num, nexthop, api.tag);
   else
-    ospf6_asbr_redistribute_remove (api.type, ifindex, (struct prefix *) &p);
+    ospf6_asbr_redistribute_remove (api.type, ifindex, &p);
 
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
     free (nexthop);
index f7d6f09f22cca815e83f3bacfdeb2f4c378b3452..4b8787c89ec34723c7a141d1a0311a4a59ced4ee 100644 (file)
@@ -14,4 +14,4 @@ TAGS
 .arch-ids
 *~
 *.loT
-
+*.a
index 845d96032bc062aa023eedaf0a5a3b450cf6a00c..edb1ca470e71fb17ea043dc6e9ac9953f57cf256 100644 (file)
@@ -383,7 +383,7 @@ main (int argc, char **argv)
           pid_file[0] = '\0';
 
       snprintf(pidfile_temp, sizeof(pidfile_temp), "%s/ospfd-%d.pid", pid_file, instance );
-      strncpy(pid_file, pidfile_temp, sizeof(pid_file));
+      strlcpy(pid_file, pidfile_temp, sizeof(pid_file));
     }
   /* Process id file create. */
   pid_output (pid_file);
@@ -407,7 +407,7 @@ main (int argc, char **argv)
     }
   else
     {
-      strcpy(vty_path, vty_sock_path);
+      strlcpy(vty_path, vty_sock_path, sizeof(vty_path));
     }
   vty_serv_sock (vty_addr, vty_port, vty_path);
 
index d6f372cc444b309e6ab27e9fc003d4c88530c1b4..f2bfb846dda46ee402e5e6cb8b30f65e65788892 100644 (file)
@@ -379,9 +379,7 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size,
 
   /* Encode group */
   remain = buf_pastend - pim_msg_curr;
-  pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
-                                               remain,
-                                               group_addr);
+  pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr, group_addr);
   if (!pim_msg_curr) {
     char group_str[INET_ADDRSTRLEN];
     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
@@ -392,9 +390,7 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size,
 
   /* Encode source */
   remain = buf_pastend - pim_msg_curr;
-  pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
-                                               remain,
-                                               source_addr);
+  pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr, source_addr);
   if (!pim_msg_curr) {
     char source_str[INET_ADDRSTRLEN];
     pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
index 7f64c9d5f2a7c1fc33ea017e681907e27a438a78..8f7d40bb36d6a69c711a2ebe084bae617c7f490c 100644 (file)
@@ -27,6 +27,7 @@
 #include "vrf.h"
 #include "linklist.h"
 #include "plist.h"
+#include "hash.h"
 
 #include "pimd.h"
 #include "pim_iface.h"
@@ -86,6 +87,9 @@ static void *if_list_clean(struct pim_interface *pim_ifp)
     list_delete(pim_ifp->pim_ifchannel_list);
   }
 
+  if (pim_ifp->pim_ifchannel_hash)
+    hash_free (pim_ifp->pim_ifchannel_hash);
+
   XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
 
   return 0;
@@ -131,6 +135,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
   pim_ifp->igmp_socket_list = NULL;
   pim_ifp->pim_neighbor_list = NULL;
   pim_ifp->pim_ifchannel_list = NULL;
+  pim_ifp->pim_ifchannel_hash = NULL;
   pim_ifp->pim_generation_id = 0;
 
   /* list of struct igmp_sock */
@@ -161,6 +166,9 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
   pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free;
   pim_ifp->pim_ifchannel_list->cmp = (int (*)(void *, void *)) pim_ifchannel_compare;
 
+  pim_ifp->pim_ifchannel_hash = hash_create (pim_ifchannel_hash_key,
+                                             pim_ifchannel_equal);
+
   ifp->info = pim_ifp;
 
   pim_sock_reset(ifp);
@@ -197,6 +205,8 @@ void pim_if_delete(struct interface *ifp)
   list_delete(pim_ifp->pim_neighbor_list);
   list_delete(pim_ifp->pim_ifchannel_list);
 
+  hash_free (pim_ifp->pim_ifchannel_hash);
+
   XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
 
   ifp->info = NULL;
@@ -945,10 +955,7 @@ int pim_if_del_vif(struct interface *ifp)
     return -1;
   }
 
-  if (pim_mroute_del_vif(pim_ifp->mroute_vif_index)) {
-    /* pim_mroute_del_vif reported error */
-    return -2;
-  }
+  pim_mroute_del_vif(pim_ifp->mroute_vif_index);
 
   /*
     Update vif_index
index 244de598db7dad12f4270db6d2353c71cc56f555..7c0d57a5d132f659df73dcea4e90e44a22a61a11 100644 (file)
@@ -98,6 +98,7 @@ struct pim_interface {
   uint16_t       pim_override_interval_msec; /* config */
   struct list   *pim_neighbor_list; /* list of struct pim_neighbor */
   struct list   *pim_ifchannel_list; /* list of struct pim_ifchannel */
+  struct hash   *pim_ifchannel_hash;
 
   /* neighbors without lan_delay */
   int            pim_number_of_nonlandelay_neighbors;
index f0e4a3a68ae01ca15483dc0905c96dc396e57c08..891bdc448d3236a1b2515ef9692257fd2e3767b2 100644 (file)
@@ -25,6 +25,8 @@
 #include "memory.h"
 #include "if.h"
 #include "vrf.h"
+#include "hash.h"
+#include "jhash.h"
 
 #include "pimd.h"
 #include "pim_str.h"
@@ -193,6 +195,7 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
     called by list_delete_all_node()
   */
   listnode_delete(pim_ifp->pim_ifchannel_list, ch);
+  hash_release(pim_ifp->pim_ifchannel_hash, ch);
   listnode_delete(pim_ifchannel_list, ch);
 
   pim_ifchannel_free(ch);
@@ -373,10 +376,8 @@ struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
                                         struct prefix_sg *sg)
 {
   struct pim_interface *pim_ifp;
-  struct listnode      *ch_node;
   struct pim_ifchannel *ch;
-
-  zassert(ifp);
+  struct pim_ifchannel lookup;
 
   pim_ifp = ifp->info;
 
@@ -385,19 +386,13 @@ struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
              __PRETTY_FUNCTION__,
              pim_str_sg_dump (sg),
              ifp->name);
-    return 0;
+    return NULL;
   }
 
-  for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
-    if (
-       (sg->src.s_addr == ch->sg.src.s_addr) &&
-       (sg->grp.s_addr == ch->sg.grp.s_addr)
-       ) {
-      return ch;
-    }
-  }
+  lookup.sg = *sg;
+  ch = hash_lookup (pim_ifp->pim_ifchannel_hash, &lookup);
 
-  return 0;
+  return ch;
 }
 
 static void ifmembership_set(struct pim_ifchannel *ch,
@@ -553,6 +548,7 @@ pim_ifchannel_add(struct interface *ifp,
 
   /* Attach to list */
   listnode_add_sort(pim_ifp->pim_ifchannel_list, ch);
+  ch = hash_get (pim_ifp->pim_ifchannel_hash, ch, hash_alloc_intern);
   listnode_add_sort(pim_ifchannel_list, ch);
 
   return ch;
@@ -601,8 +597,13 @@ static int on_ifjoin_prune_pending_timer(struct thread *t)
       /* from here ch may have been deleted */
 
       if (send_prune_echo)
-       pim_joinprune_send (ifp, pim_ifp->primary_address,
-                           ch->upstream, 0);
+        {
+          struct pim_rpf rpf;
+
+          rpf.source_nexthop.interface = ifp;
+          rpf.rpf_addr.u.prefix4 = pim_ifp->primary_address;
+          pim_joinprune_send (&rpf, ch->upstream, 0);
+        }
     }
   else
     {
@@ -665,28 +666,26 @@ static void check_recv_upstream(int is_join,
   if (source_flags & PIM_RPT_BIT_MASK) {
     if (source_flags & PIM_WILDCARD_BIT_MASK) {
       /* Prune(*,G) to RPF'(S,G) */
-      pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)",
-                                                    up, up->rpf.rpf_addr.u.prefix4);
+      pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)", up);
       return;
     }
 
     /* Prune(S,G,rpt) to RPF'(S,G) */
-    pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)",
-                                                  up, up->rpf.rpf_addr.u.prefix4);
+    pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)", up);
     return;
   }
 
   /* Prune(S,G) to RPF'(S,G) */
-  pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up,
-                                                up->rpf.rpf_addr.u.prefix4);
+  pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up);
 }
 
-static int nonlocal_upstream(int is_join,
-                            struct interface *recv_ifp,
-                            struct in_addr upstream,
-                            struct prefix_sg *sg,
-                            uint8_t source_flags,
-                            uint16_t holdtime)
+static int
+nonlocal_upstream(int is_join,
+                  struct interface *recv_ifp,
+                  struct in_addr upstream,
+                  struct prefix_sg *sg,
+                  uint8_t source_flags,
+                  uint16_t holdtime)
 {
   struct pim_interface *recv_pim_ifp;
   int is_local; /* boolean */
@@ -695,27 +694,26 @@ static int nonlocal_upstream(int is_join,
   zassert(recv_pim_ifp);
 
   is_local = (upstream.s_addr == recv_pim_ifp->primary_address.s_addr);
-  
+
+  if (is_local)
+    return 0;
+
   if (PIM_DEBUG_PIM_TRACE_DETAIL) {
     char up_str[INET_ADDRSTRLEN];
     pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
-    zlog_warn("%s: recv %s (S,G)=%s to %s upstream=%s on %s",
-             __PRETTY_FUNCTION__,
-             is_join ? "join" : "prune",
-             pim_str_sg_dump (sg),
-             is_local ? "local" : "non-local",
-             up_str, recv_ifp->name);
+    zlog_warn("%s: recv %s (S,G)=%s to non-local upstream=%s on %s",
+              __PRETTY_FUNCTION__,
+              is_join ? "join" : "prune",
+              pim_str_sg_dump (sg),
+              up_str, recv_ifp->name);
   }
 
-  if (is_local)
-    return 0;
-
   /*
-    Since recv upstream addr was not directed to our primary
-    address, check if we should react to it in any way.
-  */
+   * Since recv upstream addr was not directed to our primary
+   * address, check if we should react to it in any way.
+   */
   check_recv_upstream(is_join, recv_ifp, upstream, sg,
-                     source_flags, holdtime);
+                      source_flags, holdtime);
 
   return 1; /* non-local */
 }
@@ -972,7 +970,7 @@ pim_ifchannel_local_membership_add(struct interface *ifp,
                       __FILE__, __PRETTY_FUNCTION__,
                       child->sg_str, ifp->name, up->sg_str);
 
-         if (pim_upstream_evaluate_join_desired (child))
+         if (pim_upstream_evaluate_join_desired_interface (child, ch))
            {
              pim_channel_add_oif (child->channel_oil, ifp, PIM_OIF_FLAG_PROTO_STAR);
              pim_upstream_switch (child, PIM_UPSTREAM_JOINED);
@@ -1019,7 +1017,7 @@ void pim_ifchannel_local_membership_del(struct interface *ifp,
                       __FILE__, __PRETTY_FUNCTION__,
                       up->sg_str, ifp->name, child->sg_str);
 
-         if (c_oil && !pim_upstream_evaluate_join_desired (child))
+         if (c_oil && !pim_upstream_evaluate_join_desired_interface (child, ch))
             pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_STAR);
 
          /*
@@ -1231,3 +1229,24 @@ pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom)
        }
     }
 }
+
+unsigned int
+pim_ifchannel_hash_key (void *arg)
+{
+  struct pim_ifchannel *ch = (struct pim_ifchannel *)arg;
+
+  return jhash_2words (ch->sg.src.s_addr, ch->sg.grp.s_addr, 0);
+}
+
+int
+pim_ifchannel_equal (const void *arg1, const void *arg2)
+{
+  const struct pim_ifchannel *ch1 = (const struct pim_ifchannel *)arg1;
+  const struct pim_ifchannel *ch2 = (const struct pim_ifchannel *)arg2;
+
+  if ((ch1->sg.grp.s_addr == ch2->sg.grp.s_addr) &&
+      (ch1->sg.src.s_addr == ch2->sg.src.s_addr))
+    return 1;
+
+  return 0;
+}
index a3dc0e9d83fc8d5da402eefefafffe55d843d92f..c7084034a0a93c84e15ee8f5cd04c4dff5ebbd89 100644 (file)
@@ -26,6 +26,7 @@
 #include "if.h"
 #include "prefix.h"
 
+struct pim_ifchannel;
 #include "pim_upstream.h"
 
 enum pim_ifmembership {
@@ -153,4 +154,7 @@ void pim_ifchannel_scan_forward_start (struct interface *new_ifp);
 void pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom);
 
 int pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2);
+
+unsigned int pim_ifchannel_hash_key (void *arg);
+int pim_ifchannel_equal (const void *arg1, const void *arg2);
 #endif /* PIM_IFCHANNEL_H */
index 24b9e54ea5fa8e8b3a456a3210e295ed81fb222a..e6582e2b175efdd9e6eb05602a5f34fb544ecbc3 100644 (file)
@@ -23,6 +23,8 @@
 #include "memory.h"
 #include "prefix.h"
 #include "if.h"
+#include "hash.h"
+#include "jhash.h"
 
 #include "pimd.h"
 #include "pim_igmp.h"
@@ -428,23 +430,6 @@ int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len)
               from_str, to_str, igmp->interface->name, len, ip_hlen, ip_hdr->ip_p);
   }
 
-  if (ip_hdr->ip_p != PIM_IP_PROTO_IGMP) {
-    zlog_warn("IP packet protocol=%d is not IGMP=%d",
-             ip_hdr->ip_p, PIM_IP_PROTO_IGMP);
-    return -1;
-  }
-
-  if (ip_hlen < PIM_IP_HEADER_MIN_LEN) {
-    zlog_warn("IP packet header size=%zu shorter than minimum=%d",
-             ip_hlen, PIM_IP_HEADER_MIN_LEN);
-    return -1;
-  }
-  if (ip_hlen > PIM_IP_HEADER_MAX_LEN) {
-    zlog_warn("IP packet header size=%zu greater than maximum=%d",
-             ip_hlen, PIM_IP_HEADER_MAX_LEN);
-    return -1;
-  }
-
   igmp_msg = buf + ip_hlen;
   msg_type = *igmp_msg;
   igmp_msg_len = len - ip_hlen;
@@ -730,6 +715,8 @@ static void igmp_group_delete(struct igmp_group *group)
 
   group_timer_off(group);
   listnode_delete(group->group_igmp_sock->igmp_group_list, group);
+  hash_release (group->group_igmp_sock->igmp_group_hash, group);
+
   igmp_group_free(group);
 }
 
@@ -750,6 +737,7 @@ void igmp_sock_free(struct igmp_sock *igmp)
   zassert(!listcount(igmp->igmp_group_list));
 
   list_free(igmp->igmp_group_list);
+  hash_free(igmp->igmp_group_hash);
 
   XFREE(MTYPE_PIM_IGMP_SOCKET, igmp);
 }
@@ -790,6 +778,26 @@ igmp_sock_delete_all (struct interface *ifp)
     }
 }
 
+static unsigned int
+igmp_group_hash_key (void *arg)
+{
+  struct igmp_group *group = (struct igmp_group *)arg;
+
+  return jhash_1word(group->group_addr.s_addr, 0);
+}
+
+static int
+igmp_group_hash_equal (const void *arg1, const void *arg2)
+{
+  const struct igmp_group *g1 = (const struct igmp_group *)arg1;
+  const struct igmp_group *g2 = (const struct igmp_group *)arg2;
+
+  if (g1->group_addr.s_addr == g2->group_addr.s_addr)
+    return 1;
+
+  return 0;
+}
+
 static struct igmp_sock *igmp_sock_new(int fd,
                                       struct in_addr ifaddr,
                                       struct interface *ifp)
@@ -819,6 +827,9 @@ static struct igmp_sock *igmp_sock_new(int fd,
   }
   igmp->igmp_group_list->del = (void (*)(void *)) igmp_group_free;
 
+  igmp->igmp_group_hash = hash_create (igmp_group_hash_key,
+                                       igmp_group_hash_equal);
+
   igmp->fd                          = fd;
   igmp->interface                   = ifp;
   igmp->ifaddr                      = ifaddr;
@@ -1029,14 +1040,11 @@ struct igmp_group *
 find_group_by_addr (struct igmp_sock *igmp,
                   struct in_addr group_addr)
 {
-  struct igmp_group *group;
-  struct listnode   *node;
+  struct igmp_group lookup;
 
-  for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, node, group))
-    if (group_addr.s_addr == group->group_addr.s_addr)
-      return group;
+  lookup.group_addr.s_addr = group_addr.s_addr;
 
-  return 0;
+  return hash_lookup(igmp->igmp_group_hash, &lookup);
 }
 
 struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
@@ -1105,6 +1113,7 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
   group->group_filtermode_isexcl = 0; /* 0=INCLUDE, 1=EXCLUDE */
 
   listnode_add(igmp->igmp_group_list, group);
+  group = hash_get (igmp->igmp_group_hash, group, hash_alloc_intern);
 
   if (PIM_DEBUG_IGMP_TRACE) {
     char group_str[INET_ADDRSTRLEN];
index 802f1ba471866c4281137b2e220e18b469c216be..9c569bbd208de100a7b04b68769a457ca63bc7e4 100644 (file)
@@ -89,6 +89,7 @@ struct igmp_sock {
   int               startup_query_count;
 
   struct list      *igmp_group_list; /* list of struct igmp_group */
+  struct hash      *igmp_group_hash;
 };
 
 struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list,
index f7a6cbd0ce2910e5a7b6f367b96089d552b555d6..8c7083d83df21b85b116834104527292db169564 100644 (file)
@@ -348,6 +348,7 @@ static void source_channel_oil_detach(struct igmp_source *source)
 void igmp_source_delete(struct igmp_source *source)
 {
   struct igmp_group *group;
+  struct in_addr src;
 
   group = source->source_group;
 
@@ -388,11 +389,17 @@ void igmp_source_delete(struct igmp_source *source)
   */
   listnode_delete(group->group_source_list, source);
 
+  src.s_addr = source->source_addr.s_addr;
   igmp_source_free(source);
 
-  if (group->group_filtermode_isexcl) {
-    group_exclude_fwd_anysrc_ifempty(group);
-  }
+  /* Group source list is empty and current source is * then
+   *,G group going away so do not trigger start */
+  if (group->group_filtermode_isexcl &&
+      (listcount (group->group_source_list) != 0) &&
+      src.s_addr != INADDR_ANY)
+    {
+      group_exclude_fwd_anysrc_ifempty (group);
+    }
 }
 
 static void source_delete_by_flag(struct list *source_list)
index 028f77f53214c5684cc74f7a2c79643e9e15a631..783dd7507595012654d9301a392f0b2a8f7c3980 100644 (file)
@@ -303,45 +303,33 @@ int pim_joinprune_recv(struct interface *ifp,
   return 0;
 }
 
-int pim_joinprune_send(struct interface *ifp,
-                      struct in_addr upstream_addr,
-                      struct pim_upstream *up,
-                      int send_join)
+int pim_joinprune_send(struct pim_rpf *rpf,
+                       struct pim_upstream *up,
+                       int send_join)
 {
   struct pim_interface *pim_ifp;
   uint8_t pim_msg[9000];
   int pim_msg_size;
 
-  on_trace (__PRETTY_FUNCTION__, ifp, upstream_addr);
+  on_trace (__PRETTY_FUNCTION__, rpf->source_nexthop.interface, rpf->rpf_addr.u.prefix4);
 
-  zassert(ifp);
-
-  pim_ifp = ifp->info;
+  pim_ifp = rpf->source_nexthop.interface->info;
 
   if (!pim_ifp) {
     zlog_warn("%s: multicast not enabled on interface %s",
-             __PRETTY_FUNCTION__,
-             ifp->name);
+              __PRETTY_FUNCTION__,
+              rpf->source_nexthop.interface->name);
     return -1;
   }
 
-  if (PIM_DEBUG_PIM_J_P) {
-    char dst_str[INET_ADDRSTRLEN];
-    pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
-    zlog_debug("%s: sending %s(S,G)=%s to upstream=%s on interface %s",
-              __PRETTY_FUNCTION__,
-              send_join ? "Join" : "Prune",
-              up->sg_str, dst_str, ifp->name);
-  }
-
-  if (PIM_INADDR_IS_ANY(upstream_addr)) {
+  if (PIM_INADDR_IS_ANY(rpf->rpf_addr.u.prefix4)) {
     if (PIM_DEBUG_PIM_J_P) {
       char dst_str[INET_ADDRSTRLEN];
-      pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
+      pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str));
       zlog_debug("%s: %s(S,G)=%s: upstream=%s is myself on interface %s",
                 __PRETTY_FUNCTION__,
                 send_join ? "Join" : "Prune",
-                up->sg_str, dst_str, ifp->name);
+                up->sg_str, dst_str, rpf->source_nexthop.interface->name);
     }
     return 0;
   }
@@ -355,25 +343,34 @@ int pim_joinprune_send(struct interface *ifp,
     relevant Hello message without waiting for the Hello Timer to
     expire, followed by the Join/Prune or Assert message.
   */
-  pim_hello_require(ifp);
+  pim_hello_require(rpf->source_nexthop.interface);
 
   /*
     Build PIM message
   */
   pim_msg_size = pim_msg_join_prune_encode (pim_msg, 9000, send_join,
-                                           up, upstream_addr, PIM_JP_HOLDTIME);
+                                           up, rpf->rpf_addr.u.prefix4, PIM_JP_HOLDTIME);
 
   if (pim_msg_size < 0)
     return pim_msg_size;
 
+  if (PIM_DEBUG_PIM_J_P) {
+    char dst_str[INET_ADDRSTRLEN];
+    pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str));
+    zlog_debug("%s: sending %s(S,G)=%s to upstream=%s on interface %s",
+              __PRETTY_FUNCTION__,
+              send_join ? "Join" : "Prune",
+              up->sg_str, dst_str, rpf->source_nexthop.interface->name);
+  }
+
   if (pim_msg_send(pim_ifp->pim_sock_fd,
                   pim_ifp->primary_address,
                   qpim_all_pim_routers_addr,
                   pim_msg,
                   pim_msg_size,
-                  ifp->name)) {
+                  rpf->source_nexthop.interface->name)) {
     zlog_warn("%s: could not send PIM message on interface %s",
-             __PRETTY_FUNCTION__, ifp->name);
+             __PRETTY_FUNCTION__, rpf->source_nexthop.interface->name);
     return -8;
   }
 
index 1eeeef756fde5dba007a02e25b26a6d37c8c5e48..4b761663282fbf0b48ef61a7564772f7884b7cec 100644 (file)
@@ -32,9 +32,8 @@ int pim_joinprune_recv(struct interface *ifp,
                       struct in_addr src_addr,
                       uint8_t *tlv_buf, int tlv_buf_size);
 
-int pim_joinprune_send(struct interface *ifp,
-                      struct in_addr upstream_addr,
-                      struct pim_upstream *up,
-                      int send_join);
+int pim_joinprune_send(struct pim_rpf *nexthop,
+                       struct pim_upstream *up,
+                       int send_join);
 
 #endif /* PIM_JOIN_H */
index b1cdaf9b95bb1c6effbc25835efe39e1787a1188..ae5d0e9891ae907c1bcb5c6ec28be107c1f07639 100644 (file)
@@ -351,7 +351,7 @@ pim_mroute_msg_wrvifwhole (int fd, struct interface *ifp, const char *buf)
   struct pim_interface *pim_ifp;
   struct pim_ifchannel *ch;
   struct pim_upstream *up;
-  //struct prefix_sg star_g;
+  struct prefix_sg star_g;
   struct prefix_sg sg;
   struct channel_oil *oil;
 
@@ -367,9 +367,10 @@ pim_mroute_msg_wrvifwhole (int fd, struct interface *ifp, const char *buf)
                    ch->sg_str, ifp->name);
       return -1;
     }
-#if 0
+
   star_g = sg;
   star_g.src.s_addr = INADDR_ANY;
+#if 0
   ch = pim_ifchannel_find(ifp, &star_g);
   if (ch)
     {
@@ -383,11 +384,22 @@ pim_mroute_msg_wrvifwhole (int fd, struct interface *ifp, const char *buf)
   up = pim_upstream_find (&sg);
   if (up)
     {
+      struct pim_upstream *parent;
       struct pim_nexthop source;
       struct pim_rpf *rpf = RP (sg.grp);
       if (!rpf || !rpf->source_nexthop.interface)
         return 0;
 
+      /*
+       * If we have received a WRVIFWHOLE and are at this
+       * point, we could be receiving the packet on the *,G
+       * tree, let's check and if so we can safely drop
+       * it.
+       */
+      parent = pim_upstream_find (&star_g);
+      if (parent && parent->rpf.source_nexthop.interface == ifp)
+        return 0;
+
       pim_ifp = rpf->source_nexthop.interface->info;
 
       memset (&source, 0, sizeof (source));
@@ -734,6 +746,13 @@ int pim_mroute_del_vif(int vif_index)
     return -1;
   }
 
+  if (PIM_DEBUG_MROUTE)
+    {
+      struct interface *ifp = pim_if_find_by_vif_index (vif_index);
+      zlog_debug ("%s %s: Del Vif %d (%s) ", __FILE__,
+                  __PRETTY_FUNCTION__, vif_index, ifp ? ifp->name : "NULL");
+    }
+
   memset(&vc, 0, sizeof(vc));
   vc.vifc_vifi = vif_index;
 
@@ -763,6 +782,17 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name)
              __PRETTY_FUNCTION__);
     return -1;
   }
+  /* Do not install route if incoming interface is undefined. */
+  if (c_oil->oil.mfcc_parent == MAXVIFS)
+    {
+      if (PIM_DEBUG_MROUTE)
+        {
+          char buf[1000];
+          zlog_debug("%s(%s) %s Attempting to add vifi that is invalid to mroute table",
+              __PRETTY_FUNCTION__, name, pim_channel_oil_dump (c_oil, buf, sizeof(buf)));
+        }
+      return -2;
+    }
 
   /* The linux kernel *expects* the incoming
    * vif to be part of the outgoing list
@@ -834,6 +864,18 @@ int pim_mroute_del (struct channel_oil *c_oil, const char *name)
     return -1;
   }
 
+  if (!c_oil->installed)
+    {
+      if (PIM_DEBUG_MROUTE)
+        {
+          char buf[1000];
+          zlog_debug("%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
+                __FILE__, __PRETTY_FUNCTION__, c_oil->oil.mfcc_parent,
+                pim_channel_oil_dump (c_oil, buf, sizeof(buf)));
+        }
+      return -2;
+    }
+
   err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, &c_oil->oil, sizeof(c_oil->oil));
   if (err) {
     if (PIM_DEBUG_MROUTE)
@@ -852,7 +894,9 @@ int pim_mroute_del (struct channel_oil *c_oil, const char *name)
                  pim_channel_oil_dump (c_oil, buf, sizeof(buf)));
     }
 
+  /*reset incoming vifi and kernel installed flags*/
   c_oil->installed = 0;
+  c_oil->oil.mfcc_parent = MAXVIFS;
 
   return 0;
 }
index 7ea7b1ad82a2836387390eabe02fdd810bf6e222..e6b13f312167d93ef5eb63113e03331e1c8c7ccb 100644 (file)
 #include "pim_iface.h"
 #include "pim_rp.h"
 #include "pim_rpf.h"
+#include "pim_register.h"
 
-void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size,
-                         uint8_t pim_msg_type)
+void pim_msg_build_header(uint8_t *pim_msg, size_t pim_msg_size, uint8_t pim_msg_type)
 {
-  uint16_t checksum;
-
-  zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
+  struct pim_msg_header *header = (struct pim_msg_header *)pim_msg;
 
   /*
    * Write header
    */
+  header->ver = PIM_PROTO_VERSION;
+  header->type = pim_msg_type;
+  header->reserved = 0;
 
-  *(uint8_t *) PIM_MSG_HDR_OFFSET_VERSION(pim_msg) = (PIM_PROTO_VERSION << 4) | pim_msg_type;
-  *(uint8_t *) PIM_MSG_HDR_OFFSET_RESERVED(pim_msg) = 0;
 
+  header->checksum = 0;
   /*
-   * Compute checksum
+   * The checksum for Registers is done only on the first 8 bytes of the packet,
+   * including the PIM header and the next 4 bytes, excluding the data packet portion
    */
-
-  *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0;
-  checksum = in_cksum(pim_msg, pim_msg_size);
-  *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = checksum;
+  if (pim_msg_type == PIM_MSG_TYPE_REGISTER)
+    header->checksum = in_cksum (pim_msg, PIM_MSG_REGISTER_LEN);
+  else
+    header->checksum = in_cksum (pim_msg, pim_msg_size);
 }
 
-uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf,
-                                       int buf_size,
-                                       struct in_addr addr)
+uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, struct in_addr addr)
 {
-  const int ENCODED_IPV4_UCAST_SIZE = 6;
-
-  if (buf_size < ENCODED_IPV4_UCAST_SIZE) {
-    return 0;
-  }
-
   buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */
   buf[1] = '\0';    /* native encoding */
   memcpy(buf+2, &addr, sizeof(struct in_addr));
 
-  return buf + ENCODED_IPV4_UCAST_SIZE;
+  return buf + PIM_ENCODED_IPV4_UCAST_SIZE;
 }
 
-uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf,
-                                       int buf_size,
-                                       struct in_addr addr)
+uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, struct in_addr addr)
 {
-  const int ENCODED_IPV4_GROUP_SIZE = 8;
-
-  if (buf_size < ENCODED_IPV4_GROUP_SIZE) {
-    return 0;
-  }
-
   buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */
   buf[1] = '\0';    /* native encoding */
   buf[2] = '\0';    /* reserved */
   buf[3] = 32;      /* mask len */
   memcpy(buf+4, &addr, sizeof(struct in_addr));
 
-  return buf + ENCODED_IPV4_GROUP_SIZE;
+  return buf + PIM_ENCODED_IPV4_GROUP_SIZE;
 }
 
 uint8_t *
-pim_msg_addr_encode_ipv4_source(uint8_t *buf, int buf_size,
-                               struct in_addr addr, uint8_t bits)
+pim_msg_addr_encode_ipv4_source(uint8_t *buf,
+                                struct in_addr addr, uint8_t bits)
 {
-  const int ENCODED_IPV4_SOURCE_SIZE = 8;
-
-  if (buf_size < ENCODED_IPV4_SOURCE_SIZE) {
-    return 0;
-  }
-
   buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */
   buf[1] = '\0';    /* native encoding */
   buf[2] = bits;
   buf[3] = 32;      /* mask len */
   memcpy(buf+4, &addr, sizeof(struct in_addr));
 
-  return buf + ENCODED_IPV4_SOURCE_SIZE;
+  return buf + PIM_ENCODED_IPV4_SOURCE_SIZE;
 }
 
-int
-pim_msg_join_prune_encode (uint8_t *buf, int buf_size, int is_join,
-                          struct pim_upstream *up,
-                          struct in_addr upstream, int holdtime)
+static size_t
+pim_msg_build_jp_groups (struct pim_jp_groups *grp, struct pim_upstream *up, int is_join)
 {
-  uint8_t *pim_msg = buf;
-  uint8_t *pim_msg_curr = buf + PIM_MSG_HEADER_LEN;
-  uint8_t *end = buf + buf_size;
-  uint16_t *prunes = NULL;
-  uint16_t *joins = NULL;
   struct in_addr stosend;
   uint8_t bits;
-  int remain;
-
-  remain = end - pim_msg_curr;
-  pim_msg_curr = pim_msg_addr_encode_ipv4_ucast (pim_msg_curr, buf_size - PIM_MSG_HEADER_LEN, upstream);
-  if (!pim_msg_curr) {
-    char dst_str[INET_ADDRSTRLEN];
-    pim_inet4_dump("<dst?>", upstream, dst_str, sizeof(dst_str));
-    zlog_warn("%s: failure encoding destination address %s: space left=%d",
-             __PRETTY_FUNCTION__, dst_str, remain);
-    return -3;
-  }
 
-  remain = end - pim_msg_curr;
-  if (remain < 4) {
-    zlog_warn("%s: group will not fit: space left=%d",
-           __PRETTY_FUNCTION__, remain);
-    return -4;
-  }
-
-  *pim_msg_curr = 0; /* reserved */
-  ++pim_msg_curr;
-  *pim_msg_curr = 1; /* number of groups */
-  ++pim_msg_curr;
+  /* number of joined/pruned sources */
+  grp->joins  = htons(is_join ? 1 : 0);
+  grp->prunes = htons(is_join ? 0 : 1);
 
-  *((uint16_t *) pim_msg_curr) = htons(holdtime);
-  ++pim_msg_curr;
-  ++pim_msg_curr;
-
-  remain = end - pim_msg_curr;
-  pim_msg_curr = pim_msg_addr_encode_ipv4_group (pim_msg_curr, remain,
-                                                up->sg.grp);
-  if (!pim_msg_curr) {
-    char group_str[INET_ADDRSTRLEN];
-    pim_inet4_dump("<grp?>", up->sg.grp, group_str, sizeof(group_str));
-    zlog_warn("%s: failure encoding group address %s: space left=%d",
-             __PRETTY_FUNCTION__, group_str, remain);
-    return -5;
-  }
-
-  remain = end - pim_msg_curr;
-  if (remain < 4) {
-    zlog_warn("%s: sources will not fit: space left=%d",
-             __PRETTY_FUNCTION__, remain);
-    return -6;
-  }
-
-  /* number of joined sources */
-  joins = (uint16_t *)pim_msg_curr;
-  *joins = htons(is_join ? 1 : 0);
-  ++pim_msg_curr;
-  ++pim_msg_curr;
-
-  /* number of pruned sources */
-  prunes = (uint16_t *)pim_msg_curr;
-  *prunes = htons(is_join ? 0 : 1);
-  ++pim_msg_curr;
-  ++pim_msg_curr;
-
-  remain = end - pim_msg_curr;
   if (up->sg.src.s_addr == INADDR_ANY)
     {
       struct pim_rpf *rpf = pim_rp_g (up->sg.grp);
@@ -196,15 +114,14 @@ pim_msg_join_prune_encode (uint8_t *buf, int buf_size, int is_join,
       bits = PIM_ENCODE_SPARSE_BIT;
       stosend = up->sg.src;
     }
-  pim_msg_curr = pim_msg_addr_encode_ipv4_source (pim_msg_curr, remain, stosend, bits);
-  if (!pim_msg_curr) {
+
+  if (!pim_msg_addr_encode_ipv4_source ((uint8_t *)&grp->s[0], stosend, bits)) {
     char source_str[INET_ADDRSTRLEN];
     pim_inet4_dump("<src?>", up->sg.src, source_str, sizeof(source_str));
-    zlog_warn("%s: failure encoding source address %s: space left=%d",
-             __PRETTY_FUNCTION__, source_str, remain);
-    return -7;
+    zlog_warn("%s: failure encoding source address %s",
+              __PRETTY_FUNCTION__, source_str);
+    return 0;
   }
-  remain = pim_msg_curr - pim_msg;
 
   /*
    * This is not implemented correctly at this point in time
@@ -218,61 +135,162 @@ pim_msg_join_prune_encode (uint8_t *buf, int buf_size, int is_join,
       int send_prune = 0;
 
       zlog_debug ("%s: Considering (%s) children for (S,G,rpt) prune",
-                 __PRETTY_FUNCTION__, up->sg_str);
+                  __PRETTY_FUNCTION__, up->sg_str);
       for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
-       {
-         if (child->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
-           {
-             if (!pim_rpf_is_same(&up->rpf, &child->rpf))
-               {
-                 send_prune = 1;
-                 if (PIM_DEBUG_PIM_PACKETS)
-                   zlog_debug ("%s: SPT Bit and RPF'(%s) != RPF'(S,G): Add Prune (%s,rpt) to compound message",
-                               __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
-               }
-             else
-               if (PIM_DEBUG_PIM_PACKETS)
-                 zlog_debug ("%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)",
-                             __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
-           }
-         else if (pim_upstream_is_sg_rpt (child))
-           {
-             if (pim_upstream_empty_inherited_olist (child))
-               {
-                 send_prune = 1;
-                 if (PIM_DEBUG_PIM_PACKETS)
-                   zlog_debug ("%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message",
-                               __PRETTY_FUNCTION__, child->sg_str);
-               }
-             else if (!pim_rpf_is_same (&up->rpf, &child->rpf))
-               {
-                 send_prune = 1;
-                 if (PIM_DEBUG_PIM_PACKETS)
-                   zlog_debug ("%s: RPF'(%s) != RPF'(%s,rpt), Add Prune to compound message",
-                               __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
-               }
-             else
-               if (PIM_DEBUG_PIM_PACKETS)
-                 zlog_debug ("%s: RPF'(%s) == RPF'(%s,rpt), Do not add Prune to compound message",
-                             __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
-           }
-         else
-           if (PIM_DEBUG_PIM_PACKETS)
-             zlog_debug ("%s: SPT bit is not set for (%s)",
-                         __PRETTY_FUNCTION__, child->sg_str);
-         if (send_prune)
-           {
-             pim_msg_curr = pim_msg_addr_encode_ipv4_source (pim_msg_curr, remain,
-                                                             child->sg.src,
-                                                             PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_RPT_BIT);
-             remain = pim_msg_curr - pim_msg;
-             *prunes = htons(ntohs(*prunes) + 1);
-             send_prune = 0;
-           }
-       }
+        {
+          if (child->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
+            {
+              if (!pim_rpf_is_same(&up->rpf, &child->rpf))
+                {
+                  send_prune = 1;
+                  if (PIM_DEBUG_PIM_PACKETS)
+                    zlog_debug ("%s: SPT Bit and RPF'(%s) != RPF'(S,G): Add Prune (%s,rpt) to compound message",
+                                __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+                }
+              else
+                if (PIM_DEBUG_PIM_PACKETS)
+                  zlog_debug ("%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)",
+                              __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+            }
+          else if (pim_upstream_is_sg_rpt (child))
+            {
+              if (pim_upstream_empty_inherited_olist (child))
+                {
+                  send_prune = 1;
+                  if (PIM_DEBUG_PIM_PACKETS)
+                    zlog_debug ("%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message",
+                                __PRETTY_FUNCTION__, child->sg_str);
+                }
+              else if (!pim_rpf_is_same (&up->rpf, &child->rpf))
+                {
+                  send_prune = 1;
+                  if (PIM_DEBUG_PIM_PACKETS)
+                    zlog_debug ("%s: RPF'(%s) != RPF'(%s,rpt), Add Prune to compound message",
+                                __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+                }
+              else
+                if (PIM_DEBUG_PIM_PACKETS)
+                  zlog_debug ("%s: RPF'(%s) == RPF'(%s,rpt), Do not add Prune to compound message",
+                              __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+            }
+          else
+            if (PIM_DEBUG_PIM_PACKETS)
+              zlog_debug ("%s: SPT bit is not set for (%s)",
+                          __PRETTY_FUNCTION__, child->sg_str);
+          if (send_prune)
+            {
+              pim_msg_curr = pim_msg_addr_encode_ipv4_source (pim_msg_curr, remain,
+                                                              child->sg.src,
+                                                              PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_RPT_BIT);
+              remain = pim_msg_curr - pim_msg;
+              *prunes = htons(ntohs(*prunes) + 1);
+              send_prune = 0;
+            }
+        }
     }
 #endif
-  pim_msg_build_header (pim_msg, remain, PIM_MSG_TYPE_JOIN_PRUNE);
 
-  return remain;
+  return sizeof (*grp);
+}
+
+/*
+ * J/P Message Format
+ *
+ * While the RFC clearly states that this is 32 bits wide, it
+ * is cheating.  These fields:
+ * Encoded-Unicast format   (6 bytes MIN)
+ * Encoded-Group format     (8 bytes MIN)
+ * Encoded-Source format    (8 bytes MIN)
+ * are *not* 32 bits wide.
+ *
+ * Nor does the RFC explicitly call out the size for:
+ * Reserved                 (1 byte)
+ * Num Groups               (1 byte)
+ * Holdtime                 (2 bytes)
+ * Number of Joined Sources (2 bytes)
+ * Number of Pruned Sources (2 bytes)
+ *
+ * This leads to a missleading representation from casual
+ * reading and making assumptions.  Be careful!
+ *
+ *   0                   1                   2                   3
+ *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |PIM Ver| Type  |   Reserved    |           Checksum            |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |        Upstream Neighbor Address (Encoded-Unicast format)     |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |  Reserved     | Num groups    |          Holdtime             |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |         Multicast Group Address 1 (Encoded-Group format)      |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |   Number of Joined Sources    |   Number of Pruned Sources    |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |        Joined Source Address 1 (Encoded-Source format)        |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                             .                                 |
+ *  |                             .                                 |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |        Joined Source Address n (Encoded-Source format)        |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |        Pruned Source Address 1 (Encoded-Source format)        |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                             .                                 |
+ *  |                             .                                 |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |        Pruned Source Address n (Encoded-Source format)        |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |         Multicast Group Address m (Encoded-Group format)      |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |   Number of Joined Sources    |   Number of Pruned Sources    |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |        Joined Source Address 1 (Encoded-Source format)        |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                             .                                 |
+ *  |                             .                                 |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |        Joined Source Address n (Encoded-Source format)        |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |        Pruned Source Address 1 (Encoded-Source format)        |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                             .                                 |
+ *  |                             .                                 |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |        Pruned Source Address n (Encoded-Source format)        |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+int
+pim_msg_join_prune_encode (uint8_t *buf, size_t buf_size, int is_join,
+                           struct pim_upstream *up,
+                           struct in_addr upstream, int holdtime)
+{
+  struct pim_jp *msg = (struct pim_jp *)buf;
+
+  assert(buf_size > sizeof (struct pim_jp));
+
+  if (!pim_msg_addr_encode_ipv4_ucast ((uint8_t *)&msg->addr, upstream)) {
+    char dst_str[INET_ADDRSTRLEN];
+    pim_inet4_dump("<dst?>", upstream, dst_str, sizeof(dst_str));
+    zlog_warn("%s: failure encoding destination address %s",
+             __PRETTY_FUNCTION__, dst_str);
+    return -3;
+  }
+
+  msg->reserved   = 0;
+  msg->num_groups = 1;
+  msg->holdtime   = htons(holdtime);
+
+  if (!pim_msg_addr_encode_ipv4_group ((uint8_t *)&msg->groups[0].g, up->sg.grp)) {
+    char group_str[INET_ADDRSTRLEN];
+    pim_inet4_dump("<grp?>", up->sg.grp, group_str, sizeof(group_str));
+    zlog_warn("%s: failure encoding group address %s",
+              __PRETTY_FUNCTION__, group_str);
+    return -5;
+  }
+
+  pim_msg_build_jp_groups (&msg->groups[0], up, is_join);
+
+  pim_msg_build_header (buf, sizeof (struct pim_jp), PIM_MSG_TYPE_JOIN_PRUNE);
+
+  return sizeof (struct pim_jp);
 }
index 5229f85c72a9a0cac2a7619458ab2b273be98fd0..3af8486d5d0a99f13f401c9cd950acbbbf67b616 100644 (file)
 */
 #define PIM_MSG_ADDRESS_FAMILY_IPV4 (1)
 
-void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size,
-                         uint8_t pim_msg_type);
-uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf,
-                                       int buf_size,
-                                       struct in_addr addr);
-uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf,
-                                       int buf_size,
-                                       struct in_addr addr);
+/*
+ * Network Order pim_msg_hdr
+ */
+struct pim_msg_header {
+  uint8_t  type:4;
+  uint8_t  ver:4;
+  uint8_t  reserved;
+  uint16_t checksum;
+} __attribute__ ((packed));
+
+struct pim_encoded_ipv4_unicast {
+  uint8_t  family;
+  uint8_t  reserved;
+  struct in_addr addr;
+} __attribute__ ((packed));
+
+struct pim_encoded_group_ipv4 {
+  uint8_t        ne;
+  uint8_t        family;
+  uint8_t        reserved;
+  uint8_t        mask;
+  struct in_addr addr;
+} __attribute__ ((packed));
+
+struct pim_encoded_source_ipv4 {
+  uint8_t        ne;
+  uint8_t        family;
+  uint8_t        bits;
+  uint8_t        mask;
+  struct in_addr addr;
+} __attribute__ ((packed));
+
+struct pim_jp_groups {
+  struct pim_encoded_group_ipv4  g;
+  uint16_t                       joins;
+  uint16_t                       prunes;
+  struct pim_encoded_source_ipv4 s[1];
+} __attribute__ ((packed));
+
+struct pim_jp {
+  struct pim_msg_header           header;
+  struct pim_encoded_ipv4_unicast addr;
+  uint8_t                         reserved;
+  uint8_t                         num_groups;
+  uint16_t                        holdtime;
+  struct pim_jp_groups            groups[1];
+} __attribute__ ((packed));
+
+void pim_msg_build_header(uint8_t *pim_msg, size_t pim_msg_size, uint8_t pim_msg_type);
+uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, struct in_addr addr);
+uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, struct in_addr addr);
 
 #define PIM_ENCODE_SPARSE_BIT      0x04
 #define PIM_ENCODE_WC_BIT          0x02
 #define PIM_ENCODE_RPT_BIT         0x01
 uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf,
-                                        int buf_size,
-                                        struct in_addr addr,
-                                        uint8_t bits);
+                                         struct in_addr addr, uint8_t bits);
 
 
-int pim_msg_join_prune_encode (uint8_t *buf, int buf_size, int is_join,
-                              struct pim_upstream *up,
-                              struct in_addr upstream, int holdtime);
+int pim_msg_join_prune_encode (uint8_t *buf, size_t buf_size, int is_join,
+                               struct pim_upstream *up,
+                               struct in_addr upstream, int holdtime);
 #endif /* PIM_MSG_H */
index 4c5eff4883e36992d52f1b712630815c5ad56c29..3e9d6c5a896e35e9b3c894d43bd632315d8c8567 100644 (file)
@@ -133,27 +133,40 @@ void pim_channel_oil_free(struct channel_oil *c_oil)
   XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil);
 }
 
-static void
-pim_del_channel_oil (struct channel_oil *c_oil)
+static struct channel_oil *
+pim_find_channel_oil(struct prefix_sg *sg)
 {
-  /*
-    notice that listnode_delete() can't be moved
-    into pim_channel_oil_free() because the later is
-    called by list_delete_all_node()
-  */
-  listnode_delete(pim_channel_oil_list, c_oil);
-  hash_release (pim_channel_oil_hash, c_oil);
+  struct channel_oil *c_oil = NULL;
+  struct channel_oil lookup;
+
+  lookup.oil.mfcc_mcastgrp = sg->grp;
+  lookup.oil.mfcc_origin   = sg->src;
+
+  c_oil = hash_lookup (pim_channel_oil_hash, &lookup);
 
-  pim_channel_oil_free(c_oil);
+  return c_oil;
 }
 
-static struct channel_oil *
-pim_add_channel_oil (struct prefix_sg *sg,
-                   int input_vif_index)
+struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg,
+                                       int input_vif_index)
 {
   struct channel_oil *c_oil;
   struct interface *ifp;
 
+  c_oil = pim_find_channel_oil(sg);
+  if (c_oil) {
+    if (c_oil->oil.mfcc_parent != input_vif_index)
+      {
+        c_oil->oil_inherited_rescan = 1;
+        if (PIM_DEBUG_MROUTE)
+          zlog_debug ("%s: Existing channel oil %s points to %d, modifying to point at %d",
+                      __PRETTY_FUNCTION__, pim_str_sg_dump(sg), c_oil->oil.mfcc_parent, input_vif_index);
+      }
+    c_oil->oil.mfcc_parent = input_vif_index;
+    ++c_oil->oil_ref_count;
+    return c_oil;
+  }
+
   ifp = pim_if_find_by_vif_index(input_vif_index);
   if (!ifp) {
     /* warning only */
@@ -181,47 +194,20 @@ pim_add_channel_oil (struct prefix_sg *sg,
   return c_oil;
 }
 
-static struct channel_oil *pim_find_channel_oil(struct prefix_sg *sg)
-{
-  struct channel_oil *c_oil = NULL;
-  struct channel_oil lookup;
-
-  lookup.oil.mfcc_mcastgrp = sg->grp;
-  lookup.oil.mfcc_origin   = sg->src;
-
-  c_oil = hash_lookup (pim_channel_oil_hash, &lookup);
-
-  return c_oil;
-}
-
-struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg,
-                                       int input_vif_index)
-{
-  struct channel_oil *c_oil;
-
-  c_oil = pim_find_channel_oil(sg);
-  if (c_oil) {
-    if (c_oil->oil.mfcc_parent != input_vif_index)
-      {
-       c_oil->oil_inherited_rescan = 1;
-       if (PIM_DEBUG_MROUTE)
-         zlog_debug ("%s: Existing channel oil %s points to %d, modifying to point at %d",
-                     __PRETTY_FUNCTION__, pim_str_sg_dump(sg), c_oil->oil.mfcc_parent, input_vif_index);
-      }
-    c_oil->oil.mfcc_parent = input_vif_index;
-    ++c_oil->oil_ref_count;
-    return c_oil;
-  }
-
-  return pim_add_channel_oil(sg, input_vif_index);
-}
-
 void pim_channel_oil_del(struct channel_oil *c_oil)
 {
   --c_oil->oil_ref_count;
 
   if (c_oil->oil_ref_count < 1) {
-    pim_del_channel_oil(c_oil);
+    /*
+     * notice that listnode_delete() can't be moved
+     * into pim_channel_oil_free() because the later is
+     * called by list_delete_all_node()
+     */
+    listnode_delete(pim_channel_oil_list, c_oil);
+    hash_release (pim_channel_oil_hash, c_oil);
+
+    pim_channel_oil_free(c_oil);
   }
 }
 
index f727d3e6275f5931c702a714c23e3391f5783b0c..471d8aa39e232fda505f993dbaf098448b8a40fe 100644 (file)
@@ -135,11 +135,10 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
   char dst_str[INET_ADDRSTRLEN];
   uint8_t *pim_msg;
   int pim_msg_len;
-  uint8_t pim_version;
-  enum pim_msg_type pim_type;
   uint16_t pim_checksum; /* received checksum */
   uint16_t checksum;     /* computed checksum */
   struct pim_neighbor *neigh;
+  struct pim_msg_header *header;
 
   if (len < sizeof(*ip_hdr)) {
     if (PIM_DEBUG_PIM_PACKETS)
@@ -151,29 +150,10 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
   ip_hdr = (struct ip *) buf;
   ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
 
-  if (ip_hdr->ip_p != PIM_IP_PROTO_PIM) {
-    if (PIM_DEBUG_PIM_PACKETS)
-      zlog_debug("IP packet protocol=%d is not PIM=%d",
-                ip_hdr->ip_p, PIM_IP_PROTO_PIM);
-    return -1;
-  }
-
-  if (ip_hlen < PIM_IP_HEADER_MIN_LEN) {
-    if (PIM_DEBUG_PIM_PACKETS)
-      zlog_debug("IP packet header size=%zu shorter than minimum=%d",
-                ip_hlen, PIM_IP_HEADER_MIN_LEN);
-    return -1;
-  }
-  if (ip_hlen > PIM_IP_HEADER_MAX_LEN) {
-    if (PIM_DEBUG_PIM_PACKETS)
-      zlog_debug("IP packet header size=%zu greater than maximum=%d",
-                ip_hlen, PIM_IP_HEADER_MAX_LEN);
-    return -1;
-  }
-
   pim_msg = buf + ip_hlen;
   pim_msg_len = len - ip_hlen;
 
+  header = (struct pim_msg_header *)pim_msg;
   if (pim_msg_len < PIM_PIM_MIN_LEN) {
     if (PIM_DEBUG_PIM_PACKETS)
       zlog_debug("PIM message size=%d shorter than minimum=%d",
@@ -181,42 +161,63 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
     return -1;
   }
 
-  pim_version = PIM_MSG_HDR_GET_VERSION(pim_msg);
-  pim_type    = PIM_MSG_HDR_GET_TYPE(pim_msg);
-
-  if (pim_version != PIM_PROTO_VERSION) {
+  if (header->ver != PIM_PROTO_VERSION) {
     if (PIM_DEBUG_PIM_PACKETS)
       zlog_debug("Ignoring PIM pkt from %s with unsupported version: %d",
-                ifp->name, pim_version);
+                ifp->name, header->ver);
     return -1;
   }
 
   /* save received checksum */
-  pim_checksum = PIM_MSG_HDR_GET_CHECKSUM(pim_msg);
+  pim_checksum = header->checksum;
 
   /* for computing checksum */
-  *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0;
+  header->checksum = 0;
 
-  checksum = in_cksum(pim_msg, pim_msg_len);
-  if (checksum != pim_checksum) {
-    if (PIM_DEBUG_PIM_PACKETS)
-      zlog_debug("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
-                ifp->name, pim_checksum, checksum);
-    return -1;
-  }
+  if (header->type == PIM_MSG_TYPE_REGISTER)
+    {
+      /* First 8 byte header checksum */
+      checksum = in_cksum (pim_msg, PIM_MSG_REGISTER_LEN);
+      if (checksum != pim_checksum)
+        {
+          checksum = in_cksum (pim_msg, pim_msg_len);
+          if (checksum != pim_checksum)
+            {
+              if (PIM_DEBUG_PIM_PACKETS)
+                zlog_debug
+                  ("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
+                   ifp->name, pim_checksum, checksum);
+
+              return -1;
+            }
+        }
+    }
+  else
+    {
+      checksum = in_cksum (pim_msg, pim_msg_len);
+      if (checksum != pim_checksum)
+        {
+          if (PIM_DEBUG_PIM_PACKETS)
+            zlog_debug
+              ("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
+               ifp->name, pim_checksum, checksum);
+
+          return -1;
+        }
+    }
 
   if (PIM_DEBUG_PIM_PACKETS) {
     pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
     pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str, sizeof(dst_str));
     zlog_debug("Recv PIM %s packet from %s to %s on %s: ttl=%d pim_version=%d pim_msg_size=%d checksum=%x",
-              pim_pim_msgtype2str (pim_type), src_str, dst_str, ifp->name,
-              ip_hdr->ip_ttl, pim_version, pim_msg_len, checksum);
+              pim_pim_msgtype2str (header->type), src_str, dst_str, ifp->name,
+              ip_hdr->ip_ttl, header->ver, pim_msg_len, checksum);
     if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
       pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len);
     }
   }
 
-  switch (pim_type)
+  switch (header->type)
     {
     case PIM_MSG_TYPE_HELLO:
       return pim_hello_recv (ifp,
@@ -241,7 +242,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
        if (PIM_DEBUG_PIM_PACKETS)
          zlog_debug("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
                     __FILE__, __PRETTY_FUNCTION__,
-                    pim_type, src_str, ifp->name);
+                    header->type, src_str, ifp->name);
        return -1;
       }
       pim_neighbor_timer_reset(neigh, neigh->holdtime);
@@ -256,7 +257,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
        if (PIM_DEBUG_PIM_PACKETS)
          zlog_debug("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
                     __FILE__, __PRETTY_FUNCTION__,
-                    pim_type, src_str, ifp->name);
+                    header->type, src_str, ifp->name);
        return -1;
       }
       pim_neighbor_timer_reset(neigh, neigh->holdtime);
@@ -268,7 +269,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
     default:
       if (PIM_DEBUG_PIM_PACKETS) {
        zlog_debug("Recv PIM packet type %d which is not currently understood",
-                  pim_type);
+                  header->type);
       }
       return -1;
     }
@@ -384,7 +385,6 @@ static void pim_sock_read_on(struct interface *ifp)
               pim_ifp->pim_sock_fd);
   }
   pim_ifp->t_pim_sock_read = NULL;
-  zassert(!pim_ifp->t_pim_sock_read);
   THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp,
                 pim_ifp->pim_sock_fd);
 }
@@ -533,6 +533,8 @@ pim_msg_send(int fd, struct in_addr src,
   socklen_t          tolen;
   unsigned char      buffer[10000];
   unsigned char      *msg_start;
+  uint8_t            ttl = MAXTTL;
+  struct pim_msg_header *header;
   struct ip *ip;
 
   memset (buffer, 0, 10000);
@@ -541,23 +543,53 @@ pim_msg_send(int fd, struct in_addr src,
   msg_start = buffer + sizeof (struct ip);
   memcpy (msg_start, pim_msg, pim_msg_size);
 
-  ip = (struct ip *)buffer;
+  header = (struct pim_msg_header *)pim_msg;
+  /*
+   * Omnios apparently doesn't have a #define for IP default
+   * ttl that is the same as all other platforms.
+   */
+#ifndef IPDEFTTL
+#define IPDEFTTL   64
+#endif
+  /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */
+  switch (header->type)
+    {
+    case PIM_MSG_TYPE_HELLO:
+    case PIM_MSG_TYPE_JOIN_PRUNE:
+    case PIM_MSG_TYPE_BOOTSTRAP:
+    case PIM_MSG_TYPE_ASSERT:
+      ttl = 1;
+      break;
+    case PIM_MSG_TYPE_REGISTER:
+    case PIM_MSG_TYPE_REG_STOP:
+    case PIM_MSG_TYPE_GRAFT:
+    case PIM_MSG_TYPE_GRAFT_ACK:
+    case PIM_MSG_TYPE_CANDIDATE:
+      ttl = IPDEFTTL;
+      break;
+    default:
+      ttl = MAXTTL;
+      break;
+    }
+
+  ip = (struct ip *) buffer;
   ip->ip_id = htons (++ip_id);
   ip->ip_hl = 5;
   ip->ip_v = 4;
   ip->ip_p = PIM_IP_PROTO_PIM;
   ip->ip_src = src;
   ip->ip_dst = dst;
-  ip->ip_ttl = MAXTTL;
+  ip->ip_ttl = ttl;
   ip->ip_len = htons (sendlen);
 
   if (PIM_DEBUG_PIM_PACKETS) {
+    struct pim_msg_header *header = (struct pim_msg_header *)pim_msg;
     char dst_str[INET_ADDRSTRLEN];
     pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
     zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
               __PRETTY_FUNCTION__,
               dst_str, ifname, pim_msg_size,
-              *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg));
+              header->checksum);
   }
 
   memset(&to, 0, sizeof(to));
@@ -616,8 +648,7 @@ static int hello_send(struct interface *ifp,
   zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
   zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
 
-  pim_msg_build_header(pim_msg, pim_msg_size,
-                      PIM_MSG_TYPE_HELLO);
+  pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_HELLO);
 
   if (pim_msg_send(pim_ifp->pim_sock_fd,
                   pim_ifp->primary_address,
index 00c5f9012e3f4fb68e2021d4cda733369bf7801c..690b6c05cd7a32f4478c213a36cb82d71f6fe43f 100644 (file)
@@ -48,15 +48,6 @@ enum pim_msg_type {
   PIM_MSG_TYPE_CANDIDATE
 };
 
-#define PIM_MSG_HDR_OFFSET_VERSION(pim_msg) (pim_msg)
-#define PIM_MSG_HDR_OFFSET_TYPE(pim_msg) (pim_msg)
-#define PIM_MSG_HDR_OFFSET_RESERVED(pim_msg) (((char *)(pim_msg)) + 1)
-#define PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) (((char *)(pim_msg)) + 2)
-
-#define PIM_MSG_HDR_GET_VERSION(pim_msg) ((*(uint8_t*) PIM_MSG_HDR_OFFSET_VERSION(pim_msg)) >> 4)
-#define PIM_MSG_HDR_GET_TYPE(pim_msg) ((*(uint8_t*) PIM_MSG_HDR_OFFSET_TYPE(pim_msg)) & 0xF)
-#define PIM_MSG_HDR_GET_CHECKSUM(pim_msg) (*(uint16_t*) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg))
-
 void pim_ifstat_reset(struct interface *ifp);
 void pim_sock_reset(struct interface *ifp);
 int pim_sock_add(struct interface *ifp);
index ae00e347b5f3d1c0d99d8f359789c499e76b2362..40e035c3f4349439a82cda37513c86579ac1eb53 100644 (file)
@@ -184,14 +184,13 @@ static int nexthop_mismatch(const struct pim_nexthop *nh1,
     (nh1->mrib_route_metric != nh2->mrib_route_metric);
 }
 
-enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_rpf_addr)
+enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old)
 {
-  struct prefix       save_rpf_addr;
-  struct pim_nexthop  save_nexthop;
   struct pim_rpf     *rpf = &up->rpf;
+  struct pim_rpf     saved;
 
-  save_nexthop  = rpf->source_nexthop; /* detect change in pim_nexthop */
-  save_rpf_addr = rpf->rpf_addr;       /* detect change in RPF'(S,G) */
+  saved.source_nexthop = rpf->source_nexthop;
+  saved.rpf_addr = rpf->rpf_addr;
 
   if (pim_nexthop_lookup(&rpf->source_nexthop,
                          up->upstream_addr,
@@ -211,7 +210,7 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_
   }
 
   /* detect change in pim_nexthop */
-  if (nexthop_mismatch(&rpf->source_nexthop, &save_nexthop)) {
+  if (nexthop_mismatch(&rpf->source_nexthop, &saved.source_nexthop)) {
 
     if (PIM_DEBUG_ZEBRA) {
       char nhaddr_str[PREFIX_STRLEN];
@@ -231,27 +230,29 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_
   }
 
   /* detect change in RPF_interface(S) */
-  if (save_nexthop.interface != rpf->source_nexthop.interface) {
+  if (saved.source_nexthop.interface != rpf->source_nexthop.interface) {
 
     if (PIM_DEBUG_ZEBRA) {
       zlog_debug("%s %s: (S,G)=%s RPF_interface(S) changed from %s to %s",
                 __FILE__, __PRETTY_FUNCTION__,
                 up->sg_str,
-                save_nexthop.interface ? save_nexthop.interface->name : "<oldif?>",
+                saved.source_nexthop.interface ? saved.source_nexthop.interface->name : "<oldif?>",
                 rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<newif?>");
       /* warning only */
     }
 
-    pim_upstream_rpf_interface_changed(up, save_nexthop.interface);
+    pim_upstream_rpf_interface_changed(up, saved.source_nexthop.interface);
   }
 
   /* detect change in RPF'(S,G) */
-  if (save_rpf_addr.u.prefix4.s_addr != rpf->rpf_addr.u.prefix4.s_addr) {
+  if (saved.rpf_addr.u.prefix4.s_addr != rpf->rpf_addr.u.prefix4.s_addr) {
 
     /* return old rpf to caller ? */
-    if (old_rpf_addr)
-      *old_rpf_addr = save_rpf_addr.u.prefix4;
-
+    if (old)
+      {
+        old->source_nexthop = saved.source_nexthop;
+        old->rpf_addr = saved.rpf_addr;
+      }
     return PIM_RPF_CHANGED;
   }
 
index bb7777532486c107d1d8839a4a10389f23a84d8d..51e84b45931b86cd568baefe62c5fe5bc0d34634 100644 (file)
@@ -63,7 +63,7 @@ struct pim_upstream;
 extern long long nexthop_lookups_avoided;
 
 int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, int neighbor_needed);
-enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_rpf_addr);
+enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old);
 
 int pim_rpf_addr_is_inaddr_none (struct pim_rpf *rpf);
 int pim_rpf_addr_is_inaddr_any (struct pim_rpf *rpf);
index e1ccec387ace4d03891dfc4e5ebb933660884369..daaa95ab570dc1a3d4cbfa72f77b03e14df6d699 100644 (file)
@@ -316,27 +316,34 @@ int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr
 int
 pim_static_write_mroute (struct vty *vty, struct interface *ifp)
 {
+  struct pim_interface *pim_ifp = ifp->info;
   struct listnode *node;
   struct static_route *sroute;
   int count = 0;
   char sbuf[INET_ADDRSTRLEN];
   char gbuf[INET_ADDRSTRLEN];
 
+  if (!pim_ifp)
+    return 0;
+
   for (ALL_LIST_ELEMENTS_RO (qpim_static_route_list, node, sroute))
     {
       pim_inet4_dump ("<ifaddr?>", sroute->group, gbuf, sizeof (gbuf));
       pim_inet4_dump ("<ifaddr?>", sroute->source, sbuf, sizeof (sbuf));
-      if (sroute->iif == ifp->ifindex)
-       {
-         int i;
-         for (i = 0; i < MAXVIFS; i++)
-           if (sroute->oif_ttls[i])
-             {
-               struct interface *oifp = if_lookup_by_index (i);
-               vty_out (vty, " ip mroute %s %s %s%s", oifp->name, gbuf, sbuf, VTY_NEWLINE);
-               count ++;
-             }
-       }
+      if (sroute->iif == pim_ifp->mroute_vif_index)
+        {
+          int i;
+          for (i = 0; i < MAXVIFS; i++)
+            if (sroute->oif_ttls[i])
+              {
+                struct interface *oifp = pim_if_find_by_vif_index (i);
+                if (sroute->source.s_addr == 0)
+                  vty_out (vty, " ip mroute %s %s%s", oifp->name, gbuf, VTY_NEWLINE);
+                else
+                  vty_out (vty, " ip mroute %s %s %s%s", oifp->name, gbuf, sbuf, VTY_NEWLINE);
+                count ++;
+              }
+        }
     }
 
   return count;
index 4ae49c0fd47709ed3bac04999db98d2fc82bda0c..1712acaa1ed2d0ff7b80e8be27e1f88dd99dc83d 100644 (file)
@@ -171,9 +171,7 @@ pim_upstream_del(struct pim_upstream *up, const char *name)
   THREAD_OFF(up->t_msdp_reg_timer);
 
   if (up->join_state == PIM_UPSTREAM_JOINED) {
-    pim_joinprune_send (up->rpf.source_nexthop.interface,
-                      up->rpf.rpf_addr.u.prefix4,
-                      up, 0);
+    pim_joinprune_send (&up->rpf, up, 0);
     if (up->sg.src.s_addr == INADDR_ANY) {
         /* if a (*, G) entry in the joined state is being deleted we
          * need to notify MSDP */
@@ -231,10 +229,7 @@ pim_upstream_send_join (struct pim_upstream *up)
   }
 
   /* send Join(S,G) to the current upstream neighbor */
-  pim_joinprune_send(up->rpf.source_nexthop.interface,
-                    up->rpf.rpf_addr.u.prefix4,
-                    up,
-                    1 /* join */);
+  pim_joinprune_send(&up->rpf, up, 1 /* join */);
 }
 
 static int on_join_timer(struct thread *t)
@@ -334,8 +329,7 @@ void pim_upstream_join_suppress(struct pim_upstream *up,
 }
 
 void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
-                                                   struct pim_upstream *up,
-                                                   struct in_addr rpf_addr)
+                                                    struct pim_upstream *up)
 {
   long join_timer_remain_msec;
   int t_override_msec;
@@ -345,7 +339,7 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
 
   if (PIM_DEBUG_TRACE) {
     char rpf_str[INET_ADDRSTRLEN];
-    pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
+    pim_inet4_dump("<rpf?>", up->rpf.rpf_addr.u.prefix4, rpf_str, sizeof(rpf_str));
     zlog_debug("%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
               debug_label,
               up->sg_str, rpf_str,
@@ -488,10 +482,7 @@ pim_upstream_switch(struct pim_upstream *up,
     forward_off(up);
     if (old_state == PIM_UPSTREAM_JOINED)
       pim_msdp_up_join_state_changed(up);
-    pim_joinprune_send(up->rpf.source_nexthop.interface,
-                      up->rpf.rpf_addr.u.prefix4,
-                      up,
-                      0 /* prune */);
+    pim_joinprune_send(&up->rpf, up, 0 /* prune */);
     if (up->t_join_timer)
       THREAD_OFF(up->t_join_timer);
   }
@@ -662,7 +653,7 @@ struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
   return up;
 }
 
-static int
+int
 pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up,
                                              struct pim_ifchannel *ch)
 {
@@ -803,7 +794,7 @@ void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
       continue;
 
     pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
-                                                  up, neigh_addr);
+                                                   up);
   }
 }
 
index 1a50c0c6e3aacfc89cbd0e4b772a3f2752b4da3f..f36b6fba8b0c0e8abd37183271997ea3e5ea4a02 100644 (file)
@@ -129,14 +129,17 @@ struct pim_upstream *pim_upstream_add (struct prefix_sg *sg,
 void pim_upstream_del(struct pim_upstream *up, const char *name);
 
 int pim_upstream_evaluate_join_desired(struct pim_upstream *up);
+int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
+                                                 struct pim_ifchannel *ch);
 void pim_upstream_update_join_desired(struct pim_upstream *up);
 
 void pim_upstream_join_suppress(struct pim_upstream *up,
                                struct in_addr rpf_addr,
                                int holdtime);
+
 void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
-                                                   struct pim_upstream *up,
-                                                   struct in_addr rpf_addr);
+                                                    struct pim_upstream *up);
+
 void pim_upstream_join_timer_restart(struct pim_upstream *up);
 void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr);
 void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
index 1bb4852c6b0dfdea11365e113e9cd72654f06346..0f92b4a7b0f96757fd217d0bff15bf301ffcc65f 100644 (file)
@@ -366,12 +366,11 @@ static void scan_upstream_rpf_cache()
   struct pim_upstream *up;
 
   for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
-    struct in_addr      old_rpf_addr;
-    struct interface    *old_interface;
     enum pim_rpf_result rpf_result;
+    struct pim_rpf      old;
 
-    old_interface = up->rpf.source_nexthop.interface;
-    rpf_result = pim_rpf_update(up, &old_rpf_addr);
+    old.source_nexthop.interface = up->rpf.source_nexthop.interface;
+    rpf_result = pim_rpf_update(up, &old);
     if (rpf_result == PIM_RPF_FAILURE)
       continue;
 
@@ -412,14 +411,10 @@ static void scan_upstream_rpf_cache()
 
     
        /* send Prune(S,G) to the old upstream neighbor */
-       pim_joinprune_send(old_interface, old_rpf_addr,
-                          up, 0 /* prune */);
+       pim_joinprune_send(&old, up, 0 /* prune */);
        
        /* send Join(S,G) to the current upstream neighbor */
-       pim_joinprune_send(up->rpf.source_nexthop.interface,
-                          up->rpf.rpf_addr.u.prefix4,
-                          up,
-                          1 /* join */);
+       pim_joinprune_send(&up->rpf, up, 1 /* join */);
 
        pim_upstream_join_timer_restart(up);
       } /* up->join_state == PIM_UPSTREAM_JOINED */
index e1a8e820b70b68e608e6062a7090b94a1a906d8e..7ec31c7d50a16d738c88fe3b0b1cfdba1d2e056b 100644 (file)
@@ -455,7 +455,8 @@ pim_zlookup_sg_statistics (struct channel_oil *c_oil)
 
       more.src = c_oil->oil.mfcc_origin;
       more.grp = c_oil->oil.mfcc_mcastgrp;
-      zlog_debug ("Sending Request for New Channel Oil Information(%s)", pim_str_sg_dump (&more));
+      zlog_debug ("Sending Request for New Channel Oil Information(%s) VIIF %d",
+            pim_str_sg_dump (&more), c_oil->oil.mfcc_parent);
     }
 
   if (!ifp)
index 1f8dcdfb29b6833fdbd1b73a886f25c90e4393b9..0da8452ab52ef0d3b9df4545af5e96f7d86e27b2 100644 (file)
 #define PIMD_DEFAULT_CONFIG "pimd.conf"
 #define PIMD_VTY_PORT       2611
 
-#define PIM_IP_HEADER_MIN_LEN         (20)
-#define PIM_IP_HEADER_MAX_LEN         (60)
 #define PIM_IP_PROTO_IGMP             (2)
 #define PIM_IP_PROTO_PIM              (103)
 #define PIM_IGMP_MIN_LEN              (8)
+
+/*
+ * PIM MSG Header Format
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |PIM Ver| Type  |   Reserved    |           Checksum            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
 #define PIM_MSG_HEADER_LEN            (4)
 #define PIM_PIM_MIN_LEN               PIM_MSG_HEADER_LEN
+
+#define PIM_ENCODED_IPV4_UCAST_SIZE    (6)
+#define PIM_ENCODED_IPV4_GROUP_SIZE    (8)
+#define PIM_ENCODED_IPV4_SOURCE_SIZE   (8)
+
+/*
+ * J/P Message Format, Group Header
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |        Upstream Neighbor Address (Encoded-Unicast format)     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |  Reserved     | Num groups    |          Holdtime             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |         Multicast Group Address 1 (Encoded-Group format)      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Number of Joined Sources    |   Number of Pruned Sources    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+#define PIM_JP_GROUP_HEADER_SIZE     (PIM_ENCODED_IPV4_UCAST_SIZE + \
+                                      1 + 1 + 2 +                   \
+                                      PIM_ENCODED_IPV4_GROUP_SIZE + \
+                                      2 + 2)
+
 #define PIM_PROTO_VERSION             (2)
 
 #define MCAST_ALL_SYSTEMS      "224.0.0.1"
index 9166af61421fbceb07ffe2fd80d76aa683c11c85..9174191cb3c3c3ac3e1e68ffa2b7cccae9d115d6 100644 (file)
@@ -97,10 +97,10 @@ validate (struct ecommunity *ecom, const struct test_spec *sp)
   char *str1, *str2;
     
   printf ("got:\n  %s\n", ecommunity_str (ecom));
-  str1 = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
+  str1 = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0);
   etmp = ecommunity_str2com (str1, 0, 1);
   if (etmp)
-    str2 = ecommunity_ecom2str (etmp, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
+    str2 = ecommunity_ecom2str (etmp, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0);
   else
     str2 = NULL;
   
index 397612c31536a9d7dcd3bd380b30304df93bce9b..883cac0cc657e0cbbe7b89faf840ea9c760f424d 100644 (file)
@@ -725,11 +725,10 @@ parse_test (struct peer *peer, struct test_segment *t, int type)
   if (!parse_ret)
     {
       if (type == BGP_ATTR_MP_REACH_NLRI)
-        nlri_ret = bgp_nlri_parse (peer, &attr, &nlri);
+        nlri_ret = bgp_nlri_parse (peer, &attr, &nlri, 0);
       else
-        nlri_ret = bgp_nlri_parse (peer, NULL, &nlri);
+        nlri_ret = bgp_nlri_parse (peer, &attr, &nlri, 1);
     }
-  zlog_err("xxxxxxxxxxxxxxxx nlri ret %u", nlri_ret);
   handle_result (peer, t, parse_ret, nlri_ret);
 }
 
index 2ecaadbb5382a848edd438b3d5896bebc1ee683e..8524ab408305ad35c1c048d0de503eea042fda68 100755 (executable)
--- a/tools/frr
+++ b/tools/frr
@@ -21,7 +21,7 @@ V_PATH=/var/run/frr
 # Local Daemon selection may be done by using /etc/frr/daemons.
 # See /usr/share/doc/frr/README.Debian.gz for further information.
 # Keep zebra first and do not list watchfrr!
-DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd"
+DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd"
 MAX_INSTANCES=5
 RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py
 
@@ -61,7 +61,7 @@ started()
 vtysh_b ()
 {
         # Rember, that all variables have been incremented by 1 in convert_daemon_prios()
-        if [ "$vtysh_enable" = 2 -a -f $C_PATH/Frr.conf ]; then
+        if [ "$vtysh_enable" = 2 -a -f $C_PATH/frr.conf ]; then
                 /usr/bin/vtysh -b -n
         fi
 }
@@ -73,7 +73,7 @@ vtysh_b ()
 check_daemon()
 {
         # If the integrated config file is used the others are not checked.
-        if [ -r "$C_PATH/Frr.conf" ]; then
+        if [ -r "$C_PATH/frr.conf" ]; then
           return 0
         fi
 
@@ -543,10 +543,10 @@ case "$1" in
     reload)
        # Just apply the commands that have changed, no restart necessary
        [ ! -x "$RELOAD_SCRIPT" ] && echo "frr-reload script not available" && exit 0
-       NEW_CONFIG_FILE="${2:-$C_PATH/Frr.conf}"
+       NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}"
        [ ! -r $NEW_CONFIG_FILE ] && echo "Unable to read new configuration file $NEW_CONFIG_FILE" && exit 1
-       echo "Applying only incremental changes to running configuration from Frr.conf"
-       "$RELOAD_SCRIPT" --reload /etc/frr/Frr.conf
+       echo "Applying only incremental changes to running configuration from frr.conf"
+       "$RELOAD_SCRIPT" --reload /etc/frr/frr.conf
        exit $?
        ;;
 
index 53e412ca951af43f0f540f6e10f55c6e479e8626..4c2630009987e442469c549bd18a692e83903f4a 100755 (executable)
@@ -490,7 +490,7 @@ def line_to_vtysh_conft(ctx_keys, line, delete):
 
 def line_for_vtysh_file(ctx_keys, line, delete):
     """
-    Return the command as it would appear in Frr.conf
+    Return the command as it would appear in frr.conf
     """
     cmd = []
 
@@ -861,7 +861,7 @@ if __name__ == '__main__':
     parser.add_argument('--debug', action='store_true', help='Enable debugs', default=False)
     parser.add_argument('--stdout', action='store_true', help='Log to STDOUT', default=False)
     parser.add_argument('filename', help='Location of new frr config file')
-    parser.add_argument('--overwrite', action='store_true', help='Overwrite Frr.conf with running config output', default=False)
+    parser.add_argument('--overwrite', action='store_true', help='Overwrite frr.conf with running config output', default=False)
     args = parser.parse_args()
 
     # Logging
@@ -995,7 +995,20 @@ if __name__ == '__main__':
 
             (lines_to_add, lines_to_del) = compare_context_objects(newconf, running)
 
-            if lines_to_del:
+            # Only do deletes on the first pass. The reason being if we
+            # configure a bgp neighbor via "neighbor swp1 interface" quagga
+            # will automatically add:
+            #
+            # interface swp1
+            #  ipv6 nd ra-interval 10
+            #  no ipv6 nd suppress-ra
+            # !
+            #
+            # but those lines aren't in the config we are reloading against so
+            # on the 2nd pass they will show up in lines_to_del.  This could
+            # apply to other scenarios as well where configuring FOO adds BAR
+            # to the config.
+            if lines_to_del and x == 0:
                 for (ctx_keys, line) in lines_to_del:
 
                     if line == '!':
@@ -1070,5 +1083,5 @@ if __name__ == '__main__':
                     os.unlink(filename)
 
         # Make these changes persistent
-        if args.overwrite or args.filename != '/etc/frr/Frr.conf':
+        if args.overwrite or args.filename != '/etc/frr/frr.conf':
             subprocess.call(['/usr/bin/vtysh', '-c', 'write'])
index efc23ece888cf73e661e2d404b028e4ea4cd45e6..51dbbe2f32da5be2a6437486fd796bcbcdd67511 100644 (file)
@@ -17,6 +17,6 @@ Restart=on-abnormal
 LimitNOFILE=1024
 ExecStart=/usr/lib/frr/frr start
 ExecStop=/usr/lib/frr/frr stop
-ExecReload=/usr/lib/frr/frr-reload.py --reload /etc/frr/Frr.conf
+ExecReload=/usr/lib/frr/frr-reload.py --reload /etc/frr/frr.conf
 [Install]
 WantedBy=network-online.target
index 6427b8c165fc4bcaf7ba3c2a7e452513e80fdefe..38f28e453010c00d79a48370cff0023b9d7d1f56 100644 (file)
@@ -307,7 +307,7 @@ vtysh_execute_func (const char *line, int pager)
           || saved_node == BGP_ENCAP_NODE || saved_node == BGP_ENCAPV6_NODE
            || saved_node == BGP_IPV4_NODE
           || saved_node == BGP_IPV6_NODE || saved_node == BGP_IPV4M_NODE
-          || saved_node == BGP_IPV6M_NODE)
+          || saved_node == BGP_IPV6M_NODE || saved_node == BGP_EVPN_NODE)
          && (tried == 1))
        {
          vtysh_execute("exit-address-family");
@@ -561,7 +561,8 @@ vtysh_mark_file (const char *filename)
        {
          if ((prev_node == BGP_VPNV4_NODE || prev_node == BGP_IPV4_NODE
               || prev_node == BGP_IPV6_NODE || prev_node == BGP_IPV4M_NODE
-              || prev_node == BGP_IPV6M_NODE || prev_node == BGP_VPNV6_NODE)
+              || prev_node == BGP_IPV6M_NODE || prev_node == BGP_VPNV6_NODE
+               || prev_node == BGP_EVPN_NODE)
              && (tried == 1))
            {
              fprintf(stdout, "exit-address-family\n");
@@ -956,6 +957,12 @@ static struct cmd_node bgp_ipv6m_node =
   "%s(config-router-af)# "
 };
 
+static struct cmd_node bgp_evpn_node =
+{
+  BGP_EVPN_NODE,
+  "%s(config-router-af)# "
+};
+
 static struct cmd_node bgp_vnc_defaults_node =
 {
   BGP_VNC_DEFAULTS_NODE,
@@ -1203,6 +1210,21 @@ DEFUNSH (VTYSH_BGPD,
   return CMD_SUCCESS;
 }
 
+DEFUNSH (VTYSH_BGPD,
+        address_family_evpn,
+        address_family_evpn_cmd,
+        "address-family <l2vpn evpn>",
+         "Enter Address Family command mode\n"
+         "EVPN Address family\n"
+         "Layer2 VPN Address family\n"
+         "Ethernet Virtual Private Network Subsequent Address Family\n")
+{
+#if defined(HAVE_EVPN)
+  vty->node = BGP_EVPN_NODE;
+#endif /* HAVE_EVPN */
+  return CMD_SUCCESS;
+}
+
 #if defined (ENABLE_BGP_VNC)
 DEFUNSH (VTYSH_BGPD,
          vnc_defaults,
@@ -1511,6 +1533,7 @@ vtysh_exit (struct vty *vty)
     case BGP_IPV6_NODE:
     case BGP_IPV6M_NODE:
     case BGP_VRF_POLICY_NODE:
+    case BGP_EVPN_NODE:
     case BGP_VNC_DEFAULTS_NODE:
     case BGP_VNC_NVE_GROUP_NODE:
     case BGP_VNC_L2_GROUP_NODE:
@@ -2550,7 +2573,7 @@ DEFUN (vtysh_write_memory,
 
   fprintf (stdout, "Note: this version of vtysh never writes vtysh.conf\n");
 
-  /* If integrated Frr.conf explicitely set. */
+  /* If integrated frr.conf explicitely set. */
   if (want_config_integrated())
     {
       ret = CMD_WARNING;
@@ -2896,7 +2919,7 @@ vtysh_connect (struct vtysh_client *vclient)
 
   memset (&addr, 0, sizeof (struct sockaddr_un));
   addr.sun_family = AF_UNIX;
-  strncpy (addr.sun_path, path, strlen (path));
+  strlcpy (addr.sun_path, path, sizeof (addr.sun_path));
 #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
   len = addr.sun_len = SUN_LEN(&addr);
 #else
@@ -3114,6 +3137,7 @@ vtysh_init_vty (void)
   install_node (&bgp_ipv6_node, NULL);
   install_node (&bgp_ipv6m_node, NULL);
   install_node (&bgp_vrf_policy_node, NULL);
+  install_node (&bgp_evpn_node, NULL);
   install_node (&bgp_vnc_defaults_node, NULL);
   install_node (&bgp_vnc_nve_group_node, NULL);
   install_node (&bgp_vnc_l2_group_node, NULL);
@@ -3150,6 +3174,7 @@ vtysh_init_vty (void)
   vtysh_install_default (BGP_IPV4M_NODE);
   vtysh_install_default (BGP_IPV6_NODE);
   vtysh_install_default (BGP_IPV6M_NODE);
+  vtysh_install_default (BGP_EVPN_NODE);
 #if ENABLE_BGP_VNC
   vtysh_install_default (BGP_VRF_POLICY_NODE);
   vtysh_install_default (BGP_VNC_DEFAULTS_NODE);
@@ -3222,6 +3247,7 @@ vtysh_init_vty (void)
   install_element (BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd);
   install_element (BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd);
   install_element (BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd);
+  install_element (BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd);
 #if defined (ENABLE_BGP_VNC)
   install_element (BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd);
   install_element (BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd);
@@ -3267,6 +3293,7 @@ vtysh_init_vty (void)
   install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd);
   install_element (BGP_IPV6M_NODE, &vtysh_end_all_cmd);
   install_element (BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd);
+  install_element (BGP_EVPN_NODE, &vtysh_end_all_cmd);
   install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd);
   install_element (BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd);
   install_element (BGP_VNC_L2_GROUP_NODE, &vtysh_end_all_cmd);
@@ -3322,6 +3349,7 @@ vtysh_init_vty (void)
 #endif
   install_element (BGP_NODE, &address_family_ipv4_unicast_cmd);
   install_element (BGP_NODE, &address_family_ipv6_cmd);
+  install_element (BGP_NODE, &address_family_evpn_cmd);
   install_element (BGP_VPNV4_NODE, &exit_address_family_cmd);
   install_element (BGP_VPNV6_NODE, &exit_address_family_cmd);
   install_element (BGP_ENCAP_NODE, &exit_address_family_cmd);
@@ -3330,6 +3358,7 @@ vtysh_init_vty (void)
   install_element (BGP_IPV4M_NODE, &exit_address_family_cmd);
   install_element (BGP_IPV6_NODE, &exit_address_family_cmd);
   install_element (BGP_IPV6M_NODE, &exit_address_family_cmd);
+  install_element (BGP_EVPN_NODE, &exit_address_family_cmd);
 
   install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd);
   install_element (BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd);
index 39bf64f307ecd3275f15e25cc9f1273c46bbe9d4..ad31195ac4a28124015d6ae3ae7e515b681268e4 100644 (file)
@@ -49,7 +49,7 @@ DECLARE_MGROUP(MVTYSH)
 
 /* vtysh local configuration file. */
 #define VTYSH_DEFAULT_CONFIG "vtysh.conf"
-#define FRR_DEFAULT_CONFIG "Frr.conf"
+#define FRR_DEFAULT_CONFIG "frr.conf"
 
 enum vtysh_write_integrated {
        WRITE_INTEGRATED_UNSPECIFIED,
index 561eda045418c05e2529a62a2b37cd67f0961647..a24571a2bec97149413d77a1b4b2bd7ba4ae12cd 100644 (file)
@@ -151,7 +151,7 @@ usage (int status)
            "-m, --markfile           Mark input file with context end\n" \
            "    --vty_socket         Override vty socket path\n" \
            "    --config_dir         Override config directory path\n" \
-           "-w, --writeconfig        Write integrated config (Frr.conf) and exit\n" \
+           "-w, --writeconfig        Write integrated config (frr.conf) and exit\n" \
            "-h, --help               Display this help and exit\n\n" \
            "Note that multiple commands may be executed from the command\n" \
            "line by passing multiple -c args, or by embedding linefeed\n" \
@@ -355,7 +355,7 @@ main (int argc, char **argv, char **env)
          strlcat(vtysh_config_always, vtysh_configfile_name, 
              sizeof(vtysh_config_always));
          /* 
-          * Overwrite location for Frr.conf
+          * Overwrite location for frr.conf
           */
          vtysh_configfile_name = strrchr(FRR_DEFAULT_CONFIG, '/');
          if (vtysh_configfile_name)
index bf3e1510a7410763a0602457862dd8447bf90abb..64af7d7f4a59dac6f7857f665cece9e6567cc5aa 100644 (file)
@@ -35,7 +35,7 @@ DEFUN(config_write_integrated,
       config_write_integrated_cmd,
       "write integrated",
       "Write running configuration to memory, network, or terminal\n"
-      "Write integrated all-daemon Frr.conf file\n")
+      "Write integrated all-daemon frr.conf file\n")
 {
        pid_t child;
        sigset_t oldmask, sigmask;
index 660fad65307bfdd27781f5bd7d31b3850174ae12..65fc8789f9064c571d2319816034a637f9e59e93 100644 (file)
@@ -302,7 +302,7 @@ netlink_vrf_change (struct nlmsghdr *h, struct rtattr *tb, const char *name)
    during bootstrap. */
 static int
 netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                   ns_id_t ns_id)
+                   ns_id_t ns_id, int startup)
 {
   int len;
   struct ifinfomsg *ifi;
@@ -403,7 +403,7 @@ interface_lookup_netlink (struct zebra_ns *zns)
   ret = netlink_request (AF_PACKET, RTM_GETLINK, &zns->netlink_cmd);
   if (ret < 0)
     return ret;
-  ret = netlink_parse_info (netlink_interface, &zns->netlink_cmd, zns, 0);
+  ret = netlink_parse_info (netlink_interface, &zns->netlink_cmd, zns, 0, 1);
   if (ret < 0)
     return ret;
 
@@ -411,7 +411,7 @@ interface_lookup_netlink (struct zebra_ns *zns)
   ret = netlink_request (AF_INET, RTM_GETADDR, &zns->netlink_cmd);
   if (ret < 0)
     return ret;
-  ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0);
+  ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0, 1);
   if (ret < 0)
     return ret;
 
@@ -419,7 +419,7 @@ interface_lookup_netlink (struct zebra_ns *zns)
   ret = netlink_request (AF_INET6, RTM_GETADDR, &zns->netlink_cmd);
   if (ret < 0)
     return ret;
-  ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0);
+  ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0, 1);
   if (ret < 0)
     return ret;
 
@@ -475,7 +475,7 @@ netlink_address (int cmd, int family, struct interface *ifp,
     addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
                strlen (ifc->label) + 1);
 
-  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
+  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
 }
 
 int
@@ -492,7 +492,7 @@ kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
 
 int
 netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                        ns_id_t ns_id)
+                        ns_id_t ns_id, int startup)
 {
   int len;
   struct ifaddrmsg *ifa;
@@ -630,7 +630,7 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h,
 
 int
 netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                     ns_id_t ns_id)
+                     ns_id_t ns_id, int startup)
 {
   int len;
   struct ifinfomsg *ifi;
index aac67916c034986a7382915617c0f49c3dceeb4d..6fa39ccab24ee9b53b5a184797d8f94a5983167e 100644 (file)
@@ -25,9 +25,9 @@
 #ifdef HAVE_NETLINK
 
 extern int netlink_interface_addr (struct sockaddr_nl *snl,
-                                   struct nlmsghdr *h, ns_id_t ns_id);
+                                   struct nlmsghdr *h, ns_id_t ns_id, int startup);
 extern int netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                                ns_id_t ns_id);
+                                ns_id_t ns_id, int startup);
 extern int interface_lookup_netlink (struct zebra_ns *zns);
 
 #endif /* HAVE_NETLINK */
index 058d14481e979a0ab693a66a8c30ebfc9f2e5c21..c9c2d90eac399f8e303b3909bea01fa0cfa20081 100644 (file)
@@ -125,7 +125,7 @@ extern struct zebra_privs_t zserv_privs;
 
 int
 netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h,
-    ns_id_t ns_id)
+                     ns_id_t ns_id, int startup)
 {
   zlog_warn ("netlink_talk: ignoring message type 0x%04x NS %u", h->nlmsg_type,
              ns_id);
@@ -239,7 +239,7 @@ netlink_socket (struct nlsock *nl, unsigned long groups, ns_id_t ns_id)
 
 static int
 netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h,
-    ns_id_t ns_id)
+                           ns_id_t ns_id, int startup)
 {
   /* JF: Ignore messages that aren't from the kernel */
   if ( snl->nl_pid != 0 )
@@ -251,22 +251,22 @@ netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h,
   switch (h->nlmsg_type)
     {
     case RTM_NEWROUTE:
-      return netlink_route_change (snl, h, ns_id);
+      return netlink_route_change (snl, h, ns_id, startup);
       break;
     case RTM_DELROUTE:
-      return netlink_route_change (snl, h, ns_id);
+      return netlink_route_change (snl, h, ns_id, startup);
       break;
     case RTM_NEWLINK:
-      return netlink_link_change (snl, h, ns_id);
+      return netlink_link_change (snl, h, ns_id, startup);
       break;
     case RTM_DELLINK:
-      return netlink_link_change (snl, h, ns_id);
+      return netlink_link_change (snl, h, ns_id, startup);
       break;
     case RTM_NEWADDR:
-      return netlink_interface_addr (snl, h, ns_id);
+      return netlink_interface_addr (snl, h, ns_id, startup);
       break;
     case RTM_DELADDR:
-      return netlink_interface_addr (snl, h, ns_id);
+      return netlink_interface_addr (snl, h, ns_id, startup);
       break;
     default:
       zlog_warn ("Unknown netlink nlmsg_type %d vrf %u\n", h->nlmsg_type,
@@ -280,7 +280,7 @@ static int
 kernel_read (struct thread *thread)
 {
   struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG (thread);
-  netlink_parse_info (netlink_information_fetch, &zns->netlink, zns, 5);
+  netlink_parse_info (netlink_information_fetch, &zns->netlink, zns, 5, 0);
   zns->t_netlink = thread_add_read (zebrad.master, kernel_read, zns,
                                      zns->netlink.sock);
 
@@ -444,12 +444,23 @@ nl_rttype_to_str (u_char rttype)
   return lookup (rttype_str, rttype);
 }
 
-/* Receive message from netlink interface and pass those information
-   to the given function. */
+/*
+ * netlink_parse_info
+ *
+ * Receive message from netlink interface and pass those information
+ *  to the given function.
+ *
+ * filter  -> Function to call to read the results
+ * nl      -> netlink socket information
+ * zns     -> The zebra namespace data
+ * count   -> How many we should read in, 0 means as much as possible
+ * startup -> Are we reading in under startup conditions? passed to
+ *            the filter.
+ */
 int
 netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
-                                   ns_id_t),
-                    struct nlsock *nl, struct zebra_ns *zns, int count)
+                                   ns_id_t, int),
+                    struct nlsock *nl, struct zebra_ns *zns, int count, int startup)
 {
   int status;
   int ret = 0;
@@ -613,7 +624,7 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
               continue;
             }
 
-          error = (*filter) (&snl, h, zns->ns_id);
+          error = (*filter) (&snl, h, zns->ns_id, startup);
           if (error < 0)
             {
               zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
@@ -637,11 +648,23 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
   return ret;
 }
 
-/* sendmsg() to netlink socket then recvmsg(). */
+/*
+ * netlink_talk
+ *
+ * sendmsg() to netlink socket then recvmsg().
+ * Calls netlink_parse_info to parse returned data
+ *
+ * filter   -> The filter to read final results from kernel
+ * nlmsghdr -> The data to send to the kernel
+ * nl       -> The netlink socket information
+ * zns      -> The zebra namespace information
+ * startup  -> Are we reading in under startup conditions
+ *             This is passed through eventually to filter.
+ */
 int
 netlink_talk (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
-                            ns_id_t),
-             struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns)
+                             ns_id_t, int startup),
+              struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns, int startup)
 {
   int status;
   struct sockaddr_nl snl;
@@ -697,7 +720,7 @@ netlink_talk (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
    * Get reply from netlink socket.
    * The reply should either be an acknowlegement or an error.
    */
-  return netlink_parse_info (filter, nl, zns, 0);
+  return netlink_parse_info (filter, nl, zns, 0, startup);
 }
 
 /* Get type specified information from netlink. */
index f17f1380c25c3aaf6ba59f20e771bd00dabdd3fc..adbcf71f636fa7c3607de14c66c33cb652792a4f 100644 (file)
@@ -44,14 +44,15 @@ extern const char * nl_family_to_str (u_char family);
 extern const char * nl_rttype_to_str (u_char rttype);
 
 extern int netlink_parse_info (int (*filter) (struct sockaddr_nl *,
-                               struct nlmsghdr *, ns_id_t), struct nlsock *nl,
-                               struct zebra_ns *zns, int count);
+                                              struct nlmsghdr *, ns_id_t, int),
+                               struct nlsock *nl, struct zebra_ns *zns,
+                               int count, int startup);
 extern int netlink_talk_filter (struct sockaddr_nl *, struct nlmsghdr *,
-                               ns_id_t);
+                               ns_id_t, int startup);
 extern int netlink_talk (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
-                                       ns_id_t),
+                                       ns_id_t, int startup),
                         struct nlmsghdr *n, struct nlsock *nl,
-                         struct zebra_ns *zns);
+                         struct zebra_ns *zns, int startup);
 extern int netlink_request (int family, int type, struct nlsock *nl);
 
 #endif /* HAVE_NETLINK */
index 79c9ea7023fedd568d76ea9ff3c6fb488a37a50e..b72ce84cd6b007d4b412ae6846fda62b6736a820 100644 (file)
@@ -96,6 +96,7 @@ struct option longopts[] =
   { "vty_addr",     required_argument, NULL, 'A'},
   { "vty_port",     required_argument, NULL, 'P'},
   { "vty_socket",   required_argument, NULL, OPTION_VTYSOCK },
+  { "ecmp",         required_argument, NULL, 'e'},
   { "retain",       no_argument,       NULL, 'r'},
   { "dryrun",       no_argument,       NULL, 'C'},
 #ifdef HAVE_NETLINK
@@ -135,6 +136,8 @@ char config_default[] = SYSCONFDIR DEFAULT_CONFIG_FILE;
 /* Process ID saved for use by init system */
 const char *pid_file = PATH_ZEBRA_PID;
 
+unsigned int multipath_num = MULTIPATH_NUM;
+
 /* Help information display. */
 static void
 usage (char *progname, int status)
@@ -328,6 +331,14 @@ main (int argc, char **argv)
        case 'A':
          vty_addr = optarg;
          break;
+        case 'e':
+          multipath_num = atoi (optarg);
+          if (multipath_num > MULTIPATH_NUM || multipath_num <= 0)
+            {
+              zlog_err ("Multipath Number specified must be less than %d and greater than 0", MULTIPATH_NUM);
+              return 1;
+            }
+          break;
         case 'i':
           pid_file = optarg;
           break;
index b246b89a53ab03efe64aa9fec36479e6203df9cc..c0cde50baf46ad9319381138662abf421176d6de 100644 (file)
@@ -314,8 +314,8 @@ extern void rib_lookup_and_dump (struct prefix_ipv4 *, vrf_id_t);
 extern void rib_lookup_and_pushup (struct prefix_ipv4 *, vrf_id_t);
 #define rib_dump(prefix, src, rib) _rib_dump(__func__, prefix, src, rib)
 extern void _rib_dump (const char *,
-                      union prefix46constptr,
-                      union prefix46constptr, const struct rib *);
+                      union prefixconstptr,
+                      union prefixconstptr, const struct rib *);
 extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *,
                                   vrf_id_t);
 #define ZEBRA_RIB_LOOKUP_ERROR -1
index d88dc05b2875b531ee62f33d17c0fd4f894b235b..6ac13144962dac11ab0ec4ec78e3198858fd6c20 100644 (file)
@@ -126,8 +126,8 @@ vrf_lookup_by_table (u_int32_t table_id)
 
 /* Looking up routing table by netlink interface. */
 static int
-netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                       ns_id_t ns_id)
+netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
+                                   ns_id_t ns_id, int startup)
 {
   int len;
   struct rtmsg *rtm;
@@ -151,9 +151,9 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
 
   rtm = NLMSG_DATA (h);
 
-  if (h->nlmsg_type != RTM_NEWROUTE)
+  if (startup && h->nlmsg_type != RTM_NEWROUTE)
     return 0;
-  if (rtm->rtm_type != RTN_UNICAST)
+  if (startup && rtm->rtm_type != RTN_UNICAST)
     return 0;
 
   len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
@@ -170,6 +170,11 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
   if (rtm->rtm_protocol == RTPROT_KERNEL)
     return 0;
 
+  if (!startup &&
+      rtm->rtm_protocol == RTPROT_ZEBRA &&
+      h->nlmsg_type == RTM_NEWROUTE)
+    return 0;
+
   /* We don't care about change notifications for the MPLS table. */
   /* TODO: Revisit this. */
   if (rtm->rtm_family == AF_MPLS)
@@ -213,19 +218,22 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
   if (tb[RTA_GATEWAY])
     gate = RTA_DATA (tb[RTA_GATEWAY]);
 
-  if (tb[RTA_PRIORITY])
-    metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
-
-  if (tb[RTA_METRICS])
+  if (h->nlmsg_type == RTM_NEWROUTE)
     {
-      struct rtattr *mxrta[RTAX_MAX+1];
+      if (tb[RTA_PRIORITY])
+        metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
 
-      memset (mxrta, 0, sizeof mxrta);
-      netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
-                            RTA_PAYLOAD(tb[RTA_METRICS]));
+      if (tb[RTA_METRICS])
+        {
+          struct rtattr *mxrta[RTAX_MAX+1];
+
+          memset (mxrta, 0, sizeof mxrta);
+          netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
+                                RTA_PAYLOAD(tb[RTA_METRICS]));
 
-      if (mxrta[RTAX_MTU])
-        mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
+          if (mxrta[RTAX_MTU])
+            mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
+        }
     }
 
   if (rtm->rtm_family == AF_INET)
@@ -233,14 +241,48 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
       p.family = AF_INET;
       memcpy (&p.u.prefix4, dest, 4);
       p.prefixlen = rtm->rtm_dst_len;
+    }
+  else if (rtm->rtm_family == AF_INET6)
+    {
+      p.family = AF_INET6;
+      memcpy (&p.u.prefix6, dest, 16);
+      p.prefixlen = rtm->rtm_dst_len;
+
+      src_p.family = AF_INET6;
+      memcpy (&src_p.prefix, src, 16);
+      src_p.prefixlen = rtm->rtm_src_len;
+    }
 
-      if (rtm->rtm_src_len != 0)
-       return 0;
+  if (rtm->rtm_src_len != 0)
+    {
+      char buf[PREFIX_STRLEN];
+      zlog_warn ("unsupported IPv[4|6] sourcedest route (dest %s vrf %u)",
+                 prefix2str (&p, buf, sizeof(buf)), vrf_id);
+      return 0;
+    }
+
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    {
+      char buf[PREFIX_STRLEN];
+      char buf2[PREFIX_STRLEN];
+      zlog_debug ("%s %s%s%s vrf %u",
+                  nl_msg_type_to_str (h->nlmsg_type),
+                  prefix2str (&p, buf, sizeof(buf)),
+                  src_p.prefixlen ? " from " : "",
+                  src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2)) : "",
+                  vrf_id);
+    }
+
+  afi_t afi = AFI_IP;
+  if (rtm->rtm_family == AF_INET6)
+    afi = AFI_IP6;
 
+  if (h->nlmsg_type == RTM_NEWROUTE)
+    {
       if (!tb[RTA_MULTIPATH])
-       rib_add (AFI_IP, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
-                0, flags, &p, NULL, gate, prefsrc, index,
-                table, metric, mtu, 0);
+        rib_add (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
+                 0, flags, &p, NULL, gate, prefsrc, index,
+                 table, metric, mtu, 0);
       else
         {
           /* This is a multipath route */
@@ -280,10 +322,20 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
 
               if (gate)
                 {
-                  if (index)
-                    rib_nexthop_ipv4_ifindex_add (rib, gate, prefsrc, index);
-                  else
-                    rib_nexthop_ipv4_add (rib, gate, prefsrc);
+                  if (rtm->rtm_family == AF_INET)
+                    {
+                      if (index)
+                        rib_nexthop_ipv4_ifindex_add (rib, gate, prefsrc, index);
+                      else
+                        rib_nexthop_ipv4_add (rib, gate, prefsrc);
+                    }
+                  else if (rtm->rtm_family == AF_INET6)
+                    {
+                      if (index)
+                        rib_nexthop_ipv6_ifindex_add (rib, gate, index);
+                      else
+                        rib_nexthop_ipv6_add (rib,gate);
+                    }
                 }
               else
                 rib_nexthop_ifindex_add (rib, index);
@@ -292,250 +344,49 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
               rtnh = RTNH_NEXT(rtnh);
             }
 
-         zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
-                                rib->nexthop_num);
+          zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
+                                 rib->nexthop_num);
           if (rib->nexthop_num == 0)
             XFREE (MTYPE_RIB, rib);
           else
             rib_add_multipath (AFI_IP, SAFI_UNICAST, &p, NULL, rib);
         }
     }
-  if (rtm->rtm_family == AF_INET6)
-    {
-      p.family = AF_INET6;
-      memcpy (&p.u.prefix6, dest, 16);
-      p.prefixlen = rtm->rtm_dst_len;
-
-      src_p.family = AF_INET6;
-      memcpy (&src_p.prefix, src, 16);
-      src_p.prefixlen = rtm->rtm_src_len;
-
-      rib_add (AFI_IP6, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
-               0, flags, &p, &src_p, gate, prefsrc, index,
-              table, metric, mtu, 0);
-    }
-
-  return 0;
-}
-
-/* Routing information change from the kernel. */
-static int
-netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                      ns_id_t ns_id)
-{
-  int len;
-  struct rtmsg *rtm;
-  struct rtattr *tb[RTA_MAX + 1];
-  u_char zebra_flags = 0;
-  struct prefix p;
-  vrf_id_t vrf_id = VRF_DEFAULT;
-  char anyaddr[16] = { 0 };
-
-  int index = 0;
-  int table;
-  int metric = 0;
-  u_int32_t mtu = 0;
-
-  void *dest = NULL;
-  void *gate = NULL;
-  void *prefsrc = NULL;                /* IPv4 preferred source host address */
-  void *src = NULL;            /* IPv6 srcdest   source prefix */
-
-  rtm = NLMSG_DATA (h);
-
-  len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
-
-  memset (tb, 0, sizeof tb);
-  netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
-
-  if (rtm->rtm_flags & RTM_F_CLONED)
-    return 0;
-  if (rtm->rtm_protocol == RTPROT_REDIRECT)
-    return 0;
-  if (rtm->rtm_protocol == RTPROT_KERNEL)
-    return 0;
-
-  if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
-    return 0;
-  if (rtm->rtm_protocol == RTPROT_ZEBRA)
-    SET_FLAG(zebra_flags, ZEBRA_FLAG_SELFROUTE);
-
-  /* Table corresponding to route. */
-  if (tb[RTA_TABLE])
-    table = *(int *) RTA_DATA (tb[RTA_TABLE]);
   else
-    table = rtm->rtm_table;
-
-  /* Map to VRF */
-  vrf_id = vrf_lookup_by_table(table);
-  if (vrf_id == VRF_DEFAULT)
     {
-      if (!is_zebra_valid_kernel_table(table) &&
-          !is_zebra_main_routing_table(table))
-        return 0;
-    }
-
-  if (tb[RTA_OIF])
-    index = *(int *) RTA_DATA (tb[RTA_OIF]);
-
-  if (tb[RTA_DST])
-    dest = RTA_DATA (tb[RTA_DST]);
-  else
-    dest = anyaddr;
-
-  if (tb[RTA_SRC])
-    src = RTA_DATA (tb[RTA_SRC]);
-  else
-    src = anyaddr;
-
-  if (tb[RTA_GATEWAY])
-    gate = RTA_DATA (tb[RTA_GATEWAY]);
-
-  if (tb[RTA_PREFSRC])
-    prefsrc = RTA_DATA (tb[RTA_PREFSRC]);
-
-  if (h->nlmsg_type == RTM_NEWROUTE)
-    {
-      if (tb[RTA_PRIORITY])
-        metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
-
-      if (tb[RTA_METRICS])
+      if (!tb[RTA_MULTIPATH])
+        rib_delete (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, flags,
+                    &p, NULL, gate, index, table);
+      else
         {
-          struct rtattr *mxrta[RTAX_MAX+1];
-
-          memset (mxrta, 0, sizeof mxrta);
-          netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
-                                RTA_PAYLOAD(tb[RTA_METRICS]));
-
-          if (mxrta[RTAX_MTU])
-            mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
-        }
-    }
-
-  if (rtm->rtm_family == AF_INET)
-    {
-      p.family = AF_INET;
-      memcpy (&p.u.prefix4, dest, 4);
-      p.prefixlen = rtm->rtm_dst_len;
-
-      if (rtm->rtm_src_len != 0)
-       {
-         zlog_warn ("unsupported IPv4 sourcedest route (dest %s/%d)",
-                    inet_ntoa (p.u.prefix4), p.prefixlen);
-         return 0;
-       }
+          struct rtnexthop *rtnh =
+            (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
 
-      if (IS_ZEBRA_DEBUG_KERNEL)
-        {
-          char buf[PREFIX_STRLEN];
-          zlog_debug ("%s %s vrf %u",
-                      nl_msg_type_to_str (h->nlmsg_type),
-                      prefix2str (&p, buf, sizeof(buf)), vrf_id);
-        }
+          len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
 
-      if (h->nlmsg_type == RTM_NEWROUTE)
-        {
-          if (!tb[RTA_MULTIPATH])
-            rib_add (AFI_IP, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
-                     0, 0, &p, NULL, gate, prefsrc, index,
-                     table, metric, mtu, 0);
-          else
+          for (;;)
             {
-              /* This is a multipath route */
-
-              struct rib *rib;
-              struct rtnexthop *rtnh =
-                (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
-
-              len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
-
-              rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
-              rib->type = ZEBRA_ROUTE_KERNEL;
-              rib->distance = 0;
-              rib->flags = 0;
-              rib->metric = metric;
-              rib->mtu = mtu;
-              rib->vrf_id = vrf_id;
-              rib->table = table;
-              rib->nexthop_num = 0;
-              rib->uptime = time (NULL);
-
-              for (;;)
-                {
-                  if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
-                    break;
-
-                  index = rtnh->rtnh_ifindex;
-                  gate = 0;
-                  if (rtnh->rtnh_len > sizeof (*rtnh))
-                    {
-                      memset (tb, 0, sizeof (tb));
-                      netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
-                                            rtnh->rtnh_len - sizeof (*rtnh));
-                      if (tb[RTA_GATEWAY])
-                        gate = RTA_DATA (tb[RTA_GATEWAY]);
-                    }
-
-                  if (gate)
-                    {
-                      if (index)
-                        rib_nexthop_ipv4_ifindex_add (rib, gate, prefsrc, index);
-                      else
-                        rib_nexthop_ipv4_add (rib, gate, prefsrc);
-                    }
-                  else
-                    rib_nexthop_ifindex_add (rib, index);
+              if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
+                break;
 
-                  len -= NLMSG_ALIGN(rtnh->rtnh_len);
-                  rtnh = RTNH_NEXT(rtnh);
+              gate = NULL;
+              if (rtnh->rtnh_len > sizeof (*rtnh))
+                {
+                  memset (tb, 0, sizeof (tb));
+                  netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
+                                        rtnh->rtnh_len - sizeof (*rtnh));
+                  if (tb[RTA_GATEWAY])
+                    gate = RTA_DATA (tb[RTA_GATEWAY]);
                 }
 
-             zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
-                                    rib->nexthop_num);
+              if (gate)
+                rib_delete (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, flags,
+                            &p, NULL, gate, index, table);
 
-              if (rib->nexthop_num == 0)
-                XFREE (MTYPE_RIB, rib);
-              else
-                rib_add_multipath (AFI_IP, SAFI_UNICAST, &p, NULL, rib);
+              len -= NLMSG_ALIGN(rtnh->rtnh_len);
+              rtnh = RTNH_NEXT(rtnh);
             }
         }
-      else
-        rib_delete (AFI_IP, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, zebra_flags,
-                   &p, NULL, gate, index, table);
-    }
-
-  if (rtm->rtm_family == AF_INET6)
-    {
-      struct prefix p;
-      struct prefix_ipv6 src_p;
-
-      p.family = AF_INET6;
-      memcpy (&p.u.prefix6, dest, 16);
-      p.prefixlen = rtm->rtm_dst_len;
-
-      src_p.family = AF_INET6;
-      memcpy (&src_p.prefix, src, 16);
-      src_p.prefixlen = rtm->rtm_src_len;
-
-      if (IS_ZEBRA_DEBUG_KERNEL)
-        {
-         char buf[PREFIX_STRLEN];
-         char buf2[PREFIX_STRLEN];
-          zlog_debug ("%s %s%s%s vrf %u",
-                      nl_msg_type_to_str (h->nlmsg_type),
-                      prefix2str (&p, buf, sizeof(buf)),
-                      src_p.prefixlen ? " from " : "",
-                      src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2)) : "",
-                      vrf_id);
-        }
-
-      if (h->nlmsg_type == RTM_NEWROUTE)
-        rib_add (AFI_IP6, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
-                0, 0, &p, &src_p, gate, prefsrc, index,
-                table, metric, mtu, 0);
-      else
-        rib_delete (AFI_IP6, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
-                   0, zebra_flags, &p, &src_p, gate, index, table);
     }
 
   return 0;
@@ -545,7 +396,7 @@ static struct mcast_route_data *mroute = NULL;
 
 static int
 netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                                    ns_id_t ns_id)
+                                     ns_id_t ns_id, int startup)
 {
   int len;
   struct rtmsg *rtm;
@@ -629,7 +480,7 @@ netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h
 
 int
 netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                     ns_id_t ns_id)
+                     ns_id_t ns_id, int startup)
 {
   int len;
   vrf_id_t vrf_id = ns_id;
@@ -665,10 +516,10 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
   switch (rtm->rtm_type)
     {
     case RTN_UNICAST:
-      netlink_route_change_read_unicast (snl, h, ns_id);
+      netlink_route_change_read_unicast (snl, h, ns_id, startup);
       break;
     case RTN_MULTICAST:
-      netlink_route_change_read_multicast (snl, h, ns_id);
+      netlink_route_change_read_multicast (snl, h, ns_id, startup);
       break;
     default:
       return 0;
@@ -689,7 +540,7 @@ netlink_route_read (struct zebra_ns *zns)
   ret = netlink_request (AF_INET, RTM_GETROUTE, &zns->netlink_cmd);
   if (ret < 0)
     return ret;
-  ret = netlink_parse_info (netlink_routing_table, &zns->netlink_cmd, zns, 0);
+  ret = netlink_parse_info (netlink_route_change_read_unicast, &zns->netlink_cmd, zns, 0, 1);
   if (ret < 0)
     return ret;
 
@@ -697,7 +548,7 @@ netlink_route_read (struct zebra_ns *zns)
   ret = netlink_request (AF_INET6, RTM_GETROUTE, &zns->netlink_cmd);
   if (ret < 0)
     return ret;
-  ret = netlink_parse_info (netlink_routing_table, &zns->netlink_cmd, zns, 0);
+  ret = netlink_parse_info (netlink_route_change_read_unicast, &zns->netlink_cmd, zns, 0, 1);
   if (ret < 0)
     return ret;
 
@@ -1244,7 +1095,7 @@ netlink_neigh_update (int cmd, int ifindex, uint32_t addr, char *lla, int llalen
   addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4);
   addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
 
-  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
+  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
 }
 
 /* Routing table change via netlink interface. */
@@ -1257,7 +1108,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct prefix *src_p,
   struct sockaddr_nl snl;
   struct nexthop *nexthop = NULL, *tnexthop;
   int recursing;
-  int nexthop_num;
+  unsigned int nexthop_num;
   int discard;
   int family = PREFIX_FAMILY(p);
   const char *routedesc;
@@ -1373,7 +1224,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct prefix *src_p,
     }
 
   /* Singlepath case. */
-  if (nexthop_num == 1 || MULTIPATH_NUM == 1)
+  if (nexthop_num == 1 || multipath_num == 1)
     {
       nexthop_num = 0;
       for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
@@ -1449,7 +1300,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct prefix *src_p,
       nexthop_num = 0;
       for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
         {
-          if (nexthop_num >= MULTIPATH_NUM)
+          if (nexthop_num >= multipath_num)
             break;
 
           if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
@@ -1542,7 +1393,7 @@ skip:
   snl.nl_family = AF_NETLINK;
 
   /* Talk to netlink socket. */
-  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
+  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
 }
 
 int
@@ -1572,7 +1423,7 @@ kernel_get_ipmr_sg_stats (void *in)
   addattr_l (&req.n, sizeof (req), RTA_SRC, &mroute->sg.src.s_addr, 4);
   addattr_l (&req.n, sizeof (req), RTA_DST, &mroute->sg.grp.s_addr, 4);
 
-  suc = netlink_talk (netlink_route_change_read_multicast, &req.n, &zns->netlink_cmd, zns);
+  suc = netlink_talk (netlink_route_change_read_multicast, &req.n, &zns->netlink_cmd, zns, 0);
 
   mroute = NULL;
   return suc;
@@ -1606,7 +1457,7 @@ netlink_mpls_multipath (int cmd, zebra_lsp_t *lsp)
   mpls_lse_t lse;
   zebra_nhlfe_t *nhlfe;
   struct nexthop *nexthop = NULL;
-  int nexthop_num;
+  unsigned int nexthop_num;
   const char *routedesc;
   struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT);
 
@@ -1670,7 +1521,7 @@ netlink_mpls_multipath (int cmd, zebra_lsp_t *lsp)
   /* Fill nexthops (paths) based on single-path or multipath. The paths
    * chosen depend on the operation.
    */
-  if (nexthop_num == 1 || MULTIPATH_NUM == 1)
+  if (nexthop_num == 1 || multipath_num == 1)
     {
       routedesc = "single hop";
       _netlink_mpls_debug(cmd, lsp->ile.in_label, routedesc);
@@ -1728,7 +1579,7 @@ netlink_mpls_multipath (int cmd, zebra_lsp_t *lsp)
           if (!nexthop)
             continue;
 
-          if (MULTIPATH_NUM != 0 && nexthop_num >= MULTIPATH_NUM)
+          if (nexthop_num >= multipath_num)
             break;
 
           if ((cmd == RTM_NEWROUTE &&
@@ -1766,7 +1617,7 @@ netlink_mpls_multipath (int cmd, zebra_lsp_t *lsp)
     }
 
   /* Talk to netlink socket. */
-  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
+  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
 }
 
 /*
index 7183525fba6ec8c48052afb6893f78833233cdbb..93ee622e3530bcdc446f1f959eca7aad24801e13 100644 (file)
@@ -34,7 +34,7 @@ extern int
 netlink_mpls_multipath (int cmd, zebra_lsp_t *lsp);
 
 extern int netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                                 ns_id_t ns_id);
+                                 ns_id_t ns_id, int startup);
 extern int netlink_route_read (struct zebra_ns *zns);
 
 #endif /* HAVE_NETLINK */
index 9fffc9e611474babd23e240ba34d3689c0d138c5..92ab5df2c38fc17fe50b5aad456b8cd90e5a4eb8 100644 (file)
@@ -137,7 +137,7 @@ typedef struct netlink_route_info_t_
   u_char af;
   struct prefix *prefix;
   uint32_t *metric;
-  int num_nhs;
+  unsigned int num_nhs;
 
   /*
    * Nexthop structures
@@ -289,7 +289,7 @@ netlink_route_info_fill (netlink_route_info_t *ri, int cmd,
 
   for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
     {
-      if (ri->num_nhs >= MULTIPATH_NUM)
+      if (ri->num_nhs >= multipath_num)
         break;
 
       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
@@ -325,7 +325,7 @@ netlink_route_info_encode (netlink_route_info_t *ri, char *in_buf,
                           size_t in_buf_len)
 {
   size_t bytelen;
-  int nexthop_num = 0;
+  unsigned int nexthop_num = 0;
   size_t buf_offset;
   netlink_nh_info_t *nhi;
 
@@ -447,7 +447,7 @@ static void
 zfpm_log_route_info (netlink_route_info_t *ri, const char *label)
 {
   netlink_nh_info_t *nhi;
-  int i;
+  unsigned int i;
 
   zfpm_debug ("%s : %s %s/%d, Proto: %s, Metric: %u", label,
              nl_msg_type_to_str (ri->nlmsg_type),
index 702c355f1acf453d928665aacb0dabafc3ce3006..fba57c68f5bc02b7a9d2ea68971207b13cfc47d7 100644 (file)
@@ -149,7 +149,7 @@ create_add_route_message (qpb_allocator_t *allocator, rib_dest_t *dest,
   struct nexthop *nexthop, *tnexthop;
   int recursing;
   uint num_nhs, u;
-  struct nexthop *nexthops[MAX (MULTIPATH_NUM, 64)];
+  struct nexthop *nexthops[MULTIPATH_NUM];
 
   msg = QPB_ALLOC(allocator, typeof(*msg));
   if (!msg) {
@@ -198,7 +198,7 @@ create_add_route_message (qpb_allocator_t *allocator, rib_dest_t *dest,
   num_nhs = 0;
   for (ALL_NEXTHOPS_RO (rib->nexthop, nexthop, tnexthop, recursing))
     {
-      if (MULTIPATH_NUM != 0 && num_nhs >= MULTIPATH_NUM)
+      if (num_nhs >= multipath_num)
         break;
 
       if (num_nhs >= ZEBRA_NUM_OF(nexthops))
index 1127f568c08f775bec73eca5c6af521b7db03a3a..b68b03e0c40394466ed7d7047b0d2cfd2c48e4d1 100644 (file)
@@ -138,7 +138,7 @@ kernel_lsp_cmd (int action, zebra_lsp_t *lsp)
       if (!nexthop)
         continue;
 
-      if (MULTIPATH_NUM != 0 && nexthop_num >= MULTIPATH_NUM)
+      if (nexthop_num >= multipath_num)
         break;
 
       /* XXX */
index 13418c509e55607abedb02cf7a0de1421558542f..08874f22fc161a834b58fba35b8cb06b84d91fca 100644 (file)
@@ -2135,8 +2135,8 @@ rib_delnode (struct route_node *rn, struct rib *rib)
  */
 
 void _rib_dump (const char * func,
-                union prefix46constptr pp,
-                union prefix46constptr src_pp,
+                union prefixconstptr pp,
+                union prefixconstptr src_pp,
                 const struct rib * rib)
 {
   const struct prefix *p = pp.p;
index 37c048f6279c0a28b7603532245740121aebae26..60364410a855e937470bb73f0c48e102e75d3f79 100644 (file)
@@ -1050,12 +1050,12 @@ zread_interface_delete (struct zserv *client, u_short length, struct zebra_vrf *
 void
 zserv_nexthop_num_warn (const char *caller, const struct prefix *p, const unsigned int nexthop_num)
 {
-  if (nexthop_num > MULTIPATH_NUM)
+  if (nexthop_num > multipath_num)
     {
       char buff[PREFIX2STR_BUFFER];
       prefix2str(p, buff, sizeof (buff));
       zlog_warn("%s: Prefix %s has %d nexthops, but we can only use the first %d",
-               caller, buff, nexthop_num, MULTIPATH_NUM);
+               caller, buff, nexthop_num, multipath_num);
     }
 }
 
@@ -1197,7 +1197,7 @@ zread_ipv4_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
   api.safi = stream_getw (s);
 
   /* IPv4 prefix. */
-  memset (&p, 0, sizeof (struct prefix_ipv4));
+  memset (&p, 0, sizeof (struct prefix));
   p.family = AF_INET;
   p.prefixlen = stream_getc (s);
   stream_get (&p.u.prefix4, s, PSIZE (p.prefixlen));
@@ -1274,7 +1274,7 @@ zread_ipv4_nexthop_lookup_mrib (struct zserv *client, u_short length, struct zeb
 static int
 zread_ipv4_route_ipv6_nexthop_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
 {
-  int i;
+  unsigned int i;
   struct stream *s;
   struct in6_addr nexthop;
   struct rib *rib;
@@ -1318,9 +1318,9 @@ zread_ipv4_route_ipv6_nexthop_add (struct zserv *client, u_short length, struct
    * next-hop-addr/next-hop-ifindices. */
   if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP))
     {
-      int nh_count = 0;
-      int if_count = 0;
-      int max_nh_if = 0;
+      unsigned int nh_count = 0;
+      unsigned int if_count = 0;
+      unsigned int max_nh_if = 0;
 
       nexthop_num = stream_getc (s);
       zserv_nexthop_num_warn(__func__, (const struct prefix *)&p, nexthop_num);
@@ -1332,12 +1332,12 @@ zread_ipv4_route_ipv6_nexthop_add (struct zserv *client, u_short length, struct
            {
            case NEXTHOP_TYPE_IPV6:
              stream_get (&nexthop, s, 16);
-              if (nh_count < MULTIPATH_NUM) {
+              if (nh_count < multipath_num) {
                nexthops[nh_count++] = nexthop;
               }
              break;
            case NEXTHOP_TYPE_IFINDEX:
-              if (if_count < MULTIPATH_NUM) {
+              if (if_count < multipath_num) {
                ifindices[if_count++] = stream_getl (s);
               }
              break;
@@ -1401,7 +1401,7 @@ zread_ipv4_route_ipv6_nexthop_add (struct zserv *client, u_short length, struct
 static int
 zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
 {
-  int i;
+  unsigned int i;
   struct stream *s;
   struct in6_addr nexthop;
   struct rib *rib;
@@ -1454,9 +1454,9 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
    * next-hop-addr/next-hop-ifindices. */
   if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP))
     {
-      int nh_count = 0;
-      int if_count = 0;
-      int max_nh_if = 0;
+      unsigned int nh_count = 0;
+      unsigned int if_count = 0;
+      unsigned int max_nh_if = 0;
 
       nexthop_num = stream_getc (s);
       zserv_nexthop_num_warn(__func__, (const struct prefix *)&p, nexthop_num);
@@ -1468,12 +1468,12 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
            {
            case NEXTHOP_TYPE_IPV6:
              stream_get (&nexthop, s, 16);
-              if (nh_count < MULTIPATH_NUM) {
+              if (nh_count < multipath_num) {
                nexthops[nh_count++] = nexthop;
               }
              break;
            case NEXTHOP_TYPE_IFINDEX:
-              if (if_count < MULTIPATH_NUM) {
+              if (if_count < multipath_num) {
                ifindices[if_count++] = stream_getl (s);
               }
              break;
index a5a9979468b28db42cfb6835ec68e4bc6cb97175..21cf1004bf62b33c03399ea2c3273f0b253ccf15 100644 (file)
@@ -135,6 +135,7 @@ struct zebra_t
   struct work_queue *lsp_process_q;
 };
 extern struct zebra_t zebrad;
+extern unsigned int multipath_num;
 
 /* Prototypes. */
 extern void zebra_init (void);