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 \
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@
# 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 [] =
#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;
#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;
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;
}
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)
{
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);
}
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);
}
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);
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
#ifndef _QUAGGA_BGP_ATTR_H
#define _QUAGGA_BGP_ATTR_H
+#include "bgp_attr_evpn.h"
+
/* Simple bit mapping. */
#define BITMAP_NBBY 8
#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.
#if ENABLE_BGP_VNC
struct bgp_attr_encap_subtlv *vnc_subtlvs; /* VNC-specific */
#endif
+ /* EVPN */
+ struct overlay_index evpn_overlay;
};
/* BGP core attribute structure. */
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);
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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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 */
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;
}
}
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
#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;
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;
+}
/* 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;
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 */
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;
}
find->refcnt++;
if (! find->str)
- find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY);
+ find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY, 0);
return find;
}
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;
/* 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++)
break;
case ECOMMUNITY_ENCODE_OPAQUE:
+ if(filter == ECOMMUNITY_ROUTE_TARGET)
+ {
+ continue;
+ }
if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP)
{
uint16_t tunneltype;
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;
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;
+}
#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
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 */
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);
}
}
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. */
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
"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,
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
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 {
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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 */
{ "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'},
--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\
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... */
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;
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;
#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"
#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;
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. */
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,
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. */
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,
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. */
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)
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;
}
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;
}
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 *);
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;
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;
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;
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;
&& ! 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",
#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"
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;
}
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;
}
{
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;
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 *);
#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[];
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);
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;
struct bgp *bgp;
struct attr *riattr;
struct peer_af *paf;
- char buf[SU_ADDRSTRLEN];
+ char buf[PREFIX_STRLEN];
int ret;
int transparent;
int reflect;
* 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;
}
(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;
}
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;
}
}
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;
}
}
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
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;
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
/* 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)
{
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. */
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))
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
}
}
#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)
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)
{
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)
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;
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;
}
/* 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);
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)
{
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;
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;
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
/* 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. */
{
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);
}
#if ENABLE_BGP_VNC
u_int32_t label = 0;
#endif
+ union gw_addr add;
assert (bgp_static);
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)
{
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);
/* Register new BGP information. */
bgp_info_add (rn, new);
-
/* route_node_get lock */
bgp_unlock_node (rn);
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;
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;
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;
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)
{
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)
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);
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;
/* 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;
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);
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)
{
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;
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);
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];
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];
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);
* 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)
{
{
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));
}
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
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));
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
json_object *json_out = NULL;
struct attr *attr;
u_int32_t label = 0;
-
+
if (!binfo->extra)
return;
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));
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];
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,
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));
}
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);
}
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))
{
"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;
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);
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;
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;
"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;
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;
"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)
}
#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)
{
"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;
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;
"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;
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;
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))
{
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
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)
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);
#include "bgp_table.h"
struct bgp_nexthop_cache;
+struct bgp_route_evpn;
enum bgp_show_type
{
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;
/* 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) \
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);
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,
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);
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;
#include "bgpd/bgp_updgrp.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_nht.h"
+#include "bgpd/bgp_mplsvpn.h"
/********************
* PRIVATE FUNCTIONS
}
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);
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. */
int num_pfx = 0;
int addpath_encode = 0;
u_int32_t addpath_tx_id = 0;
+ struct prefix_rd *prd = NULL;
if (!subgrp)
return NULL;
else
{
/* Encode the prefix in MP_REACH_NLRI attribute */
- struct prefix_rd *prd = NULL;
u_char *tag = NULL;
if (rn->prn)
(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)
{
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. */
int num_pfx = 0;
int addpath_encode = 0;
u_int32_t addpath_tx_id = 0;
+ struct prefix_rd *prd = NULL;
+
if (!subgrp)
return NULL;
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;
}
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--;
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);
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);
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);
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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 */
case BGP_ENCAPV6_NODE:
afi = AFI_IP6;
break;
+ case BGP_EVPN_NODE:
+ afi = AFI_L2VPN;
+ break;
default:
afi = AFI_IP;
break;
case BGP_IPV6M_NODE:
safi = SAFI_MULTICAST;
break;
+ case BGP_EVPN_NODE:
+ safi = SAFI_EVPN;
+ break;
default:
safi = SAFI_UNICAST;
break;
else if (!strcmp(afi_str, "ipv6")) {
afi = AFI_IP6;
}
+ else if (!strcmp(afi_str, "l2vpn")) {
+ afi = AFI_L2VPN;
+ }
return afi;
}
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.
* 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.
* 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;
{
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;
}
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
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",
|| 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;
}
}
afi++;
if (! afi_wildcard ||
- afi == AFI_ETHER) /* special case, not handled yet */
+ afi == AFI_L2VPN) /* special case, not handled yet */
afi = AFI_MAX;
}
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";
}
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";
}
1
};
+static struct cmd_node bgp_evpn_node =
+{
+ BGP_EVPN_NODE,
+ "%s(config-router-evpn)# ",
+ 1
+};
+
static void community_list_vty (void);
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);
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);
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);
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
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);
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);
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);
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);
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);
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 */
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()\
#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); \
#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"
#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)
/* 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);
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 */
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;
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;
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,
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;
/* 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
#if ENABLE_BGP_VNC
rfapi_init ();
#endif
+ bgp_ethernetvpn_init ();
/* Access list initialize. */
access_list_init ();
BGP_AF_IPV6_VPN,
BGP_AF_IPV4_ENCAP,
BGP_AF_IPV6_ENCAP,
+ BGP_AF_L2VPN_EVPN,
BGP_AF_MAX
};
} bgp_policy_type_e;
extern struct bgp_master *bm;
+extern unsigned int multipath_num;
/* Prototypes. */
extern void bgp_terminate (void);
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;
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
#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);
__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);
}
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);
&cursor))
{
- if (it->imported_vpn[AFI_ETHER])
+ if (it->imported_vpn[AFI_L2VPN])
{
lni = lni_as_ptr;
if (first_l2)
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);
}
}
}
{
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);
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))
{
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 */
{
case AFI_IP:
case AFI_IP6:
- case AFI_ETHER:
+ case AFI_L2VPN:
rt = import_table->imported_vpn[afi];
break;
* 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__);
rfd,
&pfx_mac_buf, /* prefix */
p, /* aux prefix: IP addr */
- AFI_ETHER,
+ AFI_L2VPN,
prd,
attr,
type,
#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
rfd,
&pfx_mac_buf, /* prefix */
p, /* aux_prefix: IP */
- AFI_ETHER,
+ AFI_L2VPN,
prd,
attr,
type,
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)
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];
}
}
__func__, import_table, it_node, buf_prefix);
#endif
- if (AFI_ETHER == afi)
+ if (AFI_L2VPN == afi)
{
struct rfapi_monitor_eth *m;
struct skiplist *sl;
/*
* All-routes L2 monitors
*/
- if (AFI_ETHER == afi)
+ if (AFI_L2VPN == afi)
{
struct rfapi_monitor_eth *e;
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);
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
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);
}
/*
* 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)
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
#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) )))
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);
}
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 =
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 =
continue;
}
- afi = AFI_ETHER;
+ afi = AFI_L2VPN;
rfapiL2o2Qprefix (pL2o, &pfx);
}
else
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
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);
}
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);
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;
}
s = ecommunity_ecom2str (it->rt_import_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
if (pLni)
{
{
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);
}
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);
}
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);
}
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 */
}
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 */
}
}
}
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);
}
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 */
}
}
}
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);
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 */
}
}
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);
}
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 */
}
}
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 */
}
}
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);
}
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
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);
}
}
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 */
}
}
}
api.nexthop = nhp_ary;
api.ifindex_num = 0;
api.instance = 0;
+ api.safi = SAFI_UNICAST;
if (BGP_DEBUG (zebra, ZEBRA))
{
api.ifindex_num = 1;
api.ifindex = &ifindex;
api.instance = 0;
+ api.safi = SAFI_UNICAST;
if (BGP_DEBUG (zebra, ZEBRA))
{
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 ---------------------------
ripd=no
ripngd=no
isisd=no
-
+pimd=no
+ldpd=no
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
===========================
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.
fi
# Exceptions for vtysh.
- f=$d/Frr.conf
+ f=$d/frr.conf
if [ -f $d/Zebra.conf ]; then
mv $d/Zebra.conf $f
fi
--- /dev/null
+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)
--- /dev/null
+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)
--- /dev/null
+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
--- /dev/null
+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)
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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.
.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
@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
@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.
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
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.
@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.
@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
@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.
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.
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;
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");
}
isis_spf_schedule (lsp->area, lsp->level);
- isis_spf_schedule6 (lsp->area, lsp->level);
if (lsp->pdu)
stream_free (lsp->pdu);
ntohs (lsp->lsp_header->pdu_len) - 12, 12);
isis_spf_schedule (lsp->area, lsp->level);
- isis_spf_schedule6 (lsp->area, lsp->level);
return;
}
if (lsp->lsp_header->seq_num != 0)
{
isis_spf_schedule (lsp->area, lsp->level);
- isis_spf_schedule6 (lsp->area, lsp->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;
}
if (circuit->u.bc.run_dr_elect[0])
- retval = isis_dr_elect (circuit, 1);
+ isis_dr_elect (circuit, 1);
retval = send_hello (circuit, 1);
}
if (circuit->u.bc.run_dr_elect[1])
- retval = isis_dr_elect (circuit, 2);
+ isis_dr_elect (circuit, 2);
retval = send_hello (circuit, 2);
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))
{
#include "hash.h"
#include "if.h"
#include "table.h"
+#include "spf_backoff.h"
#include "isis_constants.h"
#include "isis_common.h"
#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)
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);
out:
isis_route_validate (area);
- spftree->pending = 0;
spftree->runcount++;
spftree->last_run_timestamp = time (NULL);
monotime(&time_now);
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;
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))
{
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;
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))
{
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;
}
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
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 */
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 */
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:
{
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);
*/
#include <zebra.h>
-#include <command.h>
+
+#include "command.h"
+#include "spf_backoff.h"
#include "isis_circuit.h"
#include "isis_csm.h"
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,
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);
+
}
#include "prefix.h"
#include "table.h"
#include "qobj.h"
+#include "spf_backoff.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
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);
vty_out (vty, "debug isis lsp-sched%s", VTY_NEWLINE);
write++;
}
+ write += spf_backoff_write_config(vty);
return write;
}
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",
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);
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);
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]);
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)
{
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);
install_element (ISIS_NODE, &log_adj_changes_cmd);
install_element (ISIS_NODE, &no_log_adj_changes_cmd);
+
+ spf_backoff_cmd_init();
}
[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)
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,
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);
}
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);
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;
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 */
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);
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);
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;
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:
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)
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)
{
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");
+}
{
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);
}
{
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);
}
#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)
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;
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));
/* Optional Parameters */
while (len > 0) {
struct tlv tlv;
+ uint16_t tlv_type;
uint16_t tlv_len;
if (len < sizeof(tlv)) {
}
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);
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;
}
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)
{
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));
+}
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)
{
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);
}
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;
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
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);
/* 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))
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)
{
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)
}
/* 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)
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);
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;
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);
!(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;
}
/*
}
}
+ /*
+ * 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.
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;
}
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);
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:
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) {
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 */
case TLV_TYPE_ATMLABEL:
case TLV_TYPE_FRLABEL:
switch (type) {
+ case MSG_TYPE_LABELMAPPING:
case MSG_TYPE_LABELWITHDRAW:
case MSG_TYPE_LABELRELEASE:
/* unsupported */
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. */
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:
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);
return (ibuf_add(buf, <, 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(<, 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)
{
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;
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;
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;
}
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);
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);
}
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));
+}
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 *);
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;
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) {
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 */
}
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) {
__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) {
__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) {
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;
}
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;
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");
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);
}
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;
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;
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);
}
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;
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,
}
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;
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));
}
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);
/* 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 */
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;
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);
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);
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 *);
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);
}
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 {
/* 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
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? */
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;
}
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;
*/
}
+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)
{
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);
/* 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);
}
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);
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);
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);
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) {
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))
/*
}
}
+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 */
#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
#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
#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
#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;
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)) \
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
#include "imsg.h"
#include "thread.h"
#include "qobj.h"
+#include "prefix.h"
#include "filter.h"
#include "ldp.h"
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;
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;
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);
char ifname[IF_NAMESIZE];
unsigned short ifindex;
int flags;
+ uint8_t mac[ETHER_ADDR_LEN];
int mtu;
};
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);
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 +
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;
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) {
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;
}
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) {
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:
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));
}
}
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)
/* 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 *);
/* 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 */
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 *);
const char *
log_map(const struct map *map)
{
- static char buf[64];
+ static char buf[128];
switch (map->type) {
case MAP_TYPE_WILDCARD:
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 ("???");
}
return ("initialization");
case MSG_TYPE_KEEPALIVE:
return ("keepalive");
+ case MSG_TYPE_CAPABILITY:
+ return ("capability");
case MSG_TYPE_ADDR:
return ("address");
case MSG_TYPE_ADDRWITHDRAW:
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:
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);
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)));
}
#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)
{
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__);
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;
}
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
/* Optional Parameters */
while (len > 0) {
struct tlv tlv;
+ uint16_t tlv_type;
uint16_t tlv_len;
if (len < sizeof(tlv)) {
}
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);
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:
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;
}
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);
}
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)
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);
}
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");
+}
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);
return (0);
}
break;
- default:
- break;
}
/* switch LDP packet type */
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);
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;
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;
* 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);
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;
}
}
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;
}
if (hdr.sadb_msg_type == SADB_GETSPI) {
- if (spip == NULL) {
+ if (spi == NULL) {
explicit_bzero(data, len);
free(data);
return (0);
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;
}
}
event_counter.c \
grammar_sandbox.c \
srcdest_table.c \
+ spf_backoff.c \
strlcpy.c \
strlcat.c
skiplist.h qobj.h wheel.h \
event_counter.h \
monotime.h \
+ spf_backoff.h \
srcdest_table.h
noinst_HEADERS = \
case BGP_IPV4M_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
+ case BGP_EVPN_NODE:
ret = BGP_NODE;
break;
case KEYCHAIN_KEY_NODE:
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:
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:
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);
}
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 */
(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 */
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),
#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!
* 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 */
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;
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;
}
else if (family == AF_INET6)
return AFI_IP6;
else if (family == AF_ETHERNET)
- return AFI_ETHER;
+ return AFI_L2VPN;
return 0;
}
return "IPv4";
case AFI_IP6:
return "IPv6";
- case AFI_ETHER:
- return "ethernet";
+ case AFI_L2VPN:
+ return "l2vpn";
case AFI_MAX:
return "bad-value";
default:
return "encap";
case SAFI_MPLS_VPN:
return "vpn";
+ case SAFI_EVPN:
+ return "evpn";
}
return NULL;
}
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",
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;
}
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;
}
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;
*/
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
struct ethaddr prefix_eth; /* AF_ETHERNET */
u_char val[8];
uintptr_t ptr;
+ struct evpn_addr prefix_evpn;
} u __attribute__ ((aligned (8)));
};
* 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
#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 *);
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
}
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;
}
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;
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);
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
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:
};
/* 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")
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. */
#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
#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. */
return AFI_IP;
if (afi == IANA_AFI_IPV6)
return AFI_IP6;
+ if (afi == IANA_AFI_L2VPN)
+ return AFI_L2VPN;
return AFI_MAX;
}
return IANA_AFI_IPV4;
if (afi == AFI_IP6)
return IANA_AFI_IPV6;
+ if (afi == AFI_L2VPN)
+ return IANA_AFI_L2VPN;
return IANA_AFI_RESERVED;
}
return SAFI_MPLS_VPN;
if (safi == IANA_SAFI_ENCAP)
return SAFI_ENCAP;
+ if (safi == IANA_SAFI_EVPN)
+ return SAFI_EVPN;
return SAFI_MAX;
}
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;
}
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)
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)
}
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);
.arch-ids
*~
*.loT
-
+*.a
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);
}
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);
/* 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));
/* 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));
#include "vrf.h"
#include "linklist.h"
#include "plist.h"
+#include "hash.h"
#include "pimd.h"
#include "pim_iface.h"
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;
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 */
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);
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;
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
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;
#include "memory.h"
#include "if.h"
#include "vrf.h"
+#include "hash.h"
+#include "jhash.h"
#include "pimd.h"
#include "pim_str.h"
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);
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;
__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,
/* 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;
/* 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
{
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 */
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 */
}
__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);
__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);
/*
}
}
}
+
+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;
+}
#include "if.h"
#include "prefix.h"
+struct pim_ifchannel;
#include "pim_upstream.h"
enum pim_ifmembership {
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 */
#include "memory.h"
#include "prefix.h"
#include "if.h"
+#include "hash.h"
+#include "jhash.h"
#include "pimd.h"
#include "pim_igmp.h"
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;
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);
}
zassert(!listcount(igmp->igmp_group_list));
list_free(igmp->igmp_group_list);
+ hash_free(igmp->igmp_group_hash);
XFREE(MTYPE_PIM_IGMP_SOCKET, igmp);
}
}
}
+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)
}
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;
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,
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];
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,
void igmp_source_delete(struct igmp_source *source)
{
struct igmp_group *group;
+ struct in_addr src;
group = source->source_group;
*/
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)
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;
}
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;
}
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 */
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;
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)
{
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));
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;
__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
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)
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;
}
#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);
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
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);
}
*/
#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 */
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 */
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);
}
}
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)
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",
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,
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);
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);
default:
if (PIM_DEBUG_PIM_PACKETS) {
zlog_debug("Recv PIM packet type %d which is not currently understood",
- pim_type);
+ header->type);
}
return -1;
}
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);
}
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);
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));
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,
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);
(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,
}
/* 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];
}
/* 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;
}
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);
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;
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 */
}
/* 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)
}
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;
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,
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);
}
return up;
}
-static int
+int
pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up,
struct pim_ifchannel *ch)
{
continue;
pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
- up, neigh_addr);
+ up);
}
}
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,
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;
/* 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 */
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)
#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"
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;
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);
}
# 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
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
}
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
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 $?
;;
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 = []
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
(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 == '!':
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'])
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
|| 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");
{
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");
"%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,
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,
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:
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;
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
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);
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);
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);
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);
#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);
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);
/* 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,
"-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" \
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)
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;
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;
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;
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;
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;
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
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;
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;
#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 */
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);
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 )
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,
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);
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;
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);
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;
* 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. */
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 */
{ "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
/* 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)
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;
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
/* 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;
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));
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)
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)
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 */
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);
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;
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;
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;
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;
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;
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;
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. */
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;
}
/* 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))
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))
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
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;
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);
/* 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);
if (!nexthop)
continue;
- if (MULTIPATH_NUM != 0 && nexthop_num >= MULTIPATH_NUM)
+ if (nexthop_num >= multipath_num)
break;
if ((cmd == RTM_NEWROUTE &&
}
/* 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);
}
/*
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 */
u_char af;
struct prefix *prefix;
uint32_t *metric;
- int num_nhs;
+ unsigned int num_nhs;
/*
* Nexthop structures
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))
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;
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),
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) {
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))
if (!nexthop)
continue;
- if (MULTIPATH_NUM != 0 && nexthop_num >= MULTIPATH_NUM)
+ if (nexthop_num >= multipath_num)
break;
/* XXX */
*/
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;
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);
}
}
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));
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;
* 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);
{
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;
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;
* 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);
{
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;
struct work_queue *lsp_process_q;
};
extern struct zebra_t zebrad;
+extern unsigned int multipath_num;
/* Prototypes. */
extern void zebra_init (void);