summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@cumulusnetworks.com>2017-05-02 17:38:06 +0200
committerGitHub <noreply@github.com>2017-05-02 17:38:06 +0200
commitb46be72b4aff1d413e89bc26a70a29934afe9d85 (patch)
treecd556a135211559b7e636db619dbf5257f874e86
parentvtysh: remove unused compilation file (diff)
parentMerge pull request #377 from qlyoung/frr-pthreads (diff)
downloadfrr-b46be72b4aff1d413e89bc26a70a29934afe9d85.tar.xz
frr-b46be72b4aff1d413e89bc26a70a29934afe9d85.zip
Merge branch 'master' into EIGRP
-rw-r--r--bgpd/Makefile.am5
-rw-r--r--bgpd/bgp_attr.c98
-rw-r--r--bgpd/bgp_attr.h7
-rw-r--r--bgpd/bgp_debug.c4
-rw-r--r--bgpd/bgp_fsm.c2
-rw-r--r--bgpd/bgp_label.c338
-rw-r--r--bgpd/bgp_label.h125
-rw-r--r--bgpd/bgp_main.c2
-rw-r--r--bgpd/bgp_nht.c18
-rw-r--r--bgpd/bgp_open.c8
-rw-r--r--bgpd/bgp_packet.c5
-rw-r--r--bgpd/bgp_route.c381
-rw-r--r--bgpd/bgp_route.h17
-rw-r--r--bgpd/bgp_table.h4
-rw-r--r--bgpd/bgp_updgrp_adv.c2
-rw-r--r--bgpd/bgp_updgrp_packet.c39
-rw-r--r--bgpd/bgp_vty.c301
-rw-r--r--bgpd/bgp_vty.h4
-rw-r--r--bgpd/bgp_zebra.c157
-rw-r--r--bgpd/bgp_zebra.h6
-rw-r--r--bgpd/bgpd.c18
-rw-r--r--bgpd/bgpd.h14
-rwxr-xr-xconfigure.ac4
-rw-r--r--debian/frr.dirs1
-rw-r--r--debian/frr.install1
-rw-r--r--doc/Building_FRR_on_Ubuntu1604.md36
-rw-r--r--isisd/Makefile.am4
-rw-r--r--isisd/isis_adjacency.c20
-rw-r--r--isisd/isis_adjacency.h3
-rw-r--r--isisd/isis_bpf.c33
-rw-r--r--isisd/isis_circuit.c22
-rw-r--r--isisd/isis_circuit.h3
-rw-r--r--isisd/isis_constants.h10
-rw-r--r--isisd/isis_lsp.c424
-rw-r--r--isisd/isis_lsp.h2
-rw-r--r--isisd/isis_mt.c724
-rw-r--r--isisd/isis_mt.h146
-rw-r--r--isisd/isis_pdu.c48
-rw-r--r--isisd/isis_pfpacket.c5
-rw-r--r--isisd/isis_spf.c718
-rw-r--r--isisd/isis_spf.h10
-rw-r--r--isisd/isis_tlv.c687
-rw-r--r--isisd/isis_tlv.h24
-rw-r--r--isisd/isis_vty.c46
-rw-r--r--isisd/isisd.c91
-rw-r--r--isisd/isisd.h2
-rw-r--r--ldpd/lde.c10
-rw-r--r--ldpd/ldpe.c10
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/command.c6
-rw-r--r--lib/command.h2
-rw-r--r--lib/frr_pthread.c184
-rw-r--r--lib/frr_pthread.h145
-rw-r--r--lib/mpls.h8
-rw-r--r--lib/nexthop.c22
-rw-r--r--lib/nexthop.h1
-rw-r--r--lib/prefix.h2
-rw-r--r--lib/stream.c25
-rw-r--r--lib/stream.h3
-rw-r--r--lib/thread.c377
-rw-r--r--lib/thread.h6
-rw-r--r--lib/vty.c2
-rw-r--r--lib/zclient.c53
-rw-r--r--lib/zclient.h11
-rw-r--r--lib/zebra.h11
-rw-r--r--tools/etc/iproute2/rt_protos.d/frr.conf8
-rwxr-xr-xtools/frr9
-rw-r--r--vtysh/vtysh.c81
-rw-r--r--zebra/Makefile.am6
-rw-r--r--zebra/interface.c1
-rw-r--r--zebra/kernel_netlink.c5
-rw-r--r--zebra/rib.h2
-rw-r--r--zebra/rt_netlink.c47
-rw-r--r--zebra/rt_netlink.h8
-rw-r--r--zebra/zebra_mpls.c1092
-rw-r--r--zebra/zebra_mpls.h146
-rw-r--r--zebra/zebra_mpls_null.c206
-rw-r--r--zebra/zebra_mpls_vty.c230
-rw-r--r--zebra/zebra_rib.c47
-rw-r--r--zebra/zebra_vrf.h13
-rw-r--r--zebra/zserv.c172
81 files changed, 6415 insertions, 1157 deletions
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am
index b6ed9a4d6..4ea045552 100644
--- a/bgpd/Makefile.am
+++ b/bgpd/Makefile.am
@@ -81,7 +81,7 @@ libbgp_a_SOURCES = \
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_attr_evpn.c \
- bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c
+ bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c
noinst_HEADERS = \
bgp_memory.h \
@@ -92,7 +92,8 @@ noinst_HEADERS = \
bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
bgp_advertise.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_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h bgp_vpn.h
+ $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h \
+ bgp_vpn.h bgp_label.h
bgpd_SOURCES = bgp_main.c
bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 1fccd25c8..a25ebf477 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -78,7 +78,8 @@ static const struct message attr_str [] =
#if ENABLE_BGP_VNC
{ BGP_ATTR_VNC, "VNC" },
#endif
- { BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" }
+ { BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" },
+ { BGP_ATTR_LABEL_INDEX, "LABEL_INDEX" }
};
static const int attr_str_max = array_size(attr_str);
@@ -676,6 +677,7 @@ attrhash_key_make (void *p)
MIX(extra->mp_nexthop_global_in.s_addr);
MIX(extra->originator_id.s_addr);
MIX(extra->tag);
+ MIX(extra->label_index);
}
if (attr->aspath)
@@ -730,6 +732,7 @@ attrhash_cmp (const void *p1, const void *p2)
&& ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
&& ae1->weight == ae2->weight
&& ae1->tag == ae2->tag
+ && ae1->label_index == ae2->label_index
&& ae1->mp_nexthop_len == ae2->mp_nexthop_len
&& IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
&& IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
@@ -1287,6 +1290,7 @@ const u_int8_t attr_flags_values [] = {
[BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_LARGE_COMMUNITIES]= BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_LABEL_INDEX] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
};
static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
@@ -2274,6 +2278,52 @@ bgp_attr_encap(
return 0;
}
+/* Label index attribute */
+static bgp_attr_parse_ret_t
+bgp_attr_label_index (struct bgp_attr_parser_args *args, struct bgp_nlri *mp_update)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+ u_int32_t label_index;
+
+ /* Length check. */
+ if (length != 8)
+ {
+ zlog_err ("Bad label index length %d", length);
+
+ return bgp_attr_malformed (args,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ /* First u32 is currently unused - reserved and flags (undefined) */
+ stream_getl (peer->ibuf);
+
+ /* Fetch the label index and see if it is valid. */
+ label_index = stream_getl (peer->ibuf);
+ if (label_index == BGP_INVALID_LABEL_INDEX)
+ return bgp_attr_malformed (args,
+ BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
+
+ /* Store label index; subsequently, we'll check on address-family */
+ (bgp_attr_extra_get (attr))->label_index = label_index;
+
+ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX);
+
+ /*
+ * Ignore the Label index attribute unless received for labeled-unicast
+ * SAFI. We reset the flag, though it is probably unnecesary.
+ */
+ if (!mp_update->length || mp_update->safi != SAFI_LABELED_UNICAST)
+ {
+ attr->extra->label_index = BGP_INVALID_LABEL_INDEX;
+ attr->flag &= ~ATTR_FLAG_BIT(BGP_ATTR_LABEL_INDEX);
+ }
+ return BGP_ATTR_PARSE_PROCEED;
+}
+
/* BGP unknown attribute treatment. */
static bgp_attr_parse_ret_t
bgp_attr_unknown (struct bgp_attr_parser_args *args)
@@ -2572,6 +2622,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
case BGP_ATTR_ENCAP:
ret = bgp_attr_encap (type, peer, length, attr, flag, startp);
break;
+ case BGP_ATTR_LABEL_INDEX:
+ ret = bgp_attr_label_index (&attr_args, mp_update);
+ break;
default:
ret = bgp_attr_unknown (&attr_args);
break;
@@ -2740,6 +2793,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
if (nh_afi == AFI_MAX)
nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->extra->mp_nexthop_len);
+
/* Nexthop */
switch (nh_afi)
{
@@ -2748,6 +2802,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
{
case SAFI_UNICAST:
case SAFI_MULTICAST:
+ case SAFI_LABELED_UNICAST:
bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
stream_putc (s, 4);
stream_put_ipv4 (s, attr->nexthop.s_addr);
@@ -2772,6 +2827,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
{
case SAFI_UNICAST:
case SAFI_MULTICAST:
+ case SAFI_LABELED_UNICAST:
{
struct attr_extra *attre = attr->extra;
@@ -2875,6 +2931,11 @@ bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi,
{
bgp_packet_mpattr_route_type_5(s, p, prd, tag, attr);
}
+ else if (safi == SAFI_LABELED_UNICAST)
+ {
+ /* Prefix write with label. */
+ stream_put_labeled_prefix(s, p, tag);
+ }
else
stream_put_prefix_addpath (s, p, addpath_encode, addpath_tx_id);
}
@@ -3112,7 +3173,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
stream_putc (s, 4);
stream_put_ipv4 (s, attr->nexthop.s_addr);
}
- else if (safi == SAFI_UNICAST && peer_cap_enhe(from))
+ else if (peer_cap_enhe(from))
{
/*
* Likely this is the case when an IPv4 prefix was received with
@@ -3348,6 +3409,23 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
}
}
+ /* Label index attribute. */
+ if (safi == SAFI_LABELED_UNICAST)
+ {
+ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+ {
+ u_int32_t label_index;
+
+ assert (attr->extra);
+ label_index = attr->extra->label_index;
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_LABEL_INDEX);
+ stream_putc (s, 8);
+ stream_putl (s, 0);
+ stream_putl (s, label_index);
+ }
+ }
+
if ( send_as4_path )
{
/* If the peer is NOT As4 capable, AND */
@@ -3439,6 +3517,11 @@ bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
u_char *tag, int addpath_encode,
u_int32_t addpath_tx_id, struct attr *attr)
{
+ u_char wlabel[3] = {0x80, 0x00, 0x00};
+
+ if (safi == SAFI_LABELED_UNICAST)
+ tag = wlabel;
+
return bgp_packet_mpattr_prefix (s, afi, safi, p, prd,
tag, addpath_encode, addpath_tx_id, attr);
}
@@ -3626,6 +3709,17 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
}
+ /* Label index */
+ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+ {
+ assert (attr->extra);
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_LABEL_INDEX);
+ stream_putc (s, 8);
+ stream_putl (s, 0);
+ stream_putl (s, attr->extra->label_index);
+ }
+
/* Return total size of attribute. */
len = stream_get_endp (s) - cp - 2;
stream_putw_at (s, cp, len);
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 015039c6c..d57e944aa 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -134,6 +134,9 @@ struct attr_extra
/* route tag */
route_tag_t tag;
+ /* Label index */
+ u_int32_t label_index;
+
uint16_t encap_tunneltype; /* grr */
struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */
@@ -160,7 +163,7 @@ struct attr
unsigned long refcnt;
/* Flag of attribute is set or not. */
- u_int32_t flag;
+ uint64_t flag;
/* Apart from in6_addr, the remaining static attributes */
struct in_addr nexthop;
@@ -201,7 +204,7 @@ struct transit
u_char *val;
};
-#define ATTR_FLAG_BIT(X) (1 << ((X) - 1))
+#define ATTR_FLAG_BIT(X) (1ULL << ((X) - 1))
#define BGP_CLUSTER_LIST_LENGTH(attr) \
(((attr)->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) ? \
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 232f53c77..8e4d8bf4f 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -450,6 +450,10 @@ bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size)
snprintf (buf + strlen (buf), size - strlen (buf), ", path %s",
aspath_print (attr->aspath));
+ if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)))
+ snprintf (buf + strlen (buf), size - strlen (buf), ", label-index %u",
+ attr->extra->label_index);
+
if (strlen (buf) > 1)
return 1;
else
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 2bbdca595..b17888482 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -1142,9 +1142,11 @@ bgp_stop (struct peer *peer)
/* Reset prefix count */
peer->pcount[AFI_IP][SAFI_UNICAST] = 0;
peer->pcount[AFI_IP][SAFI_MULTICAST] = 0;
+ peer->pcount[AFI_IP][SAFI_LABELED_UNICAST] = 0;
peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0;
peer->pcount[AFI_IP6][SAFI_UNICAST] = 0;
peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0;
+ peer->pcount[AFI_IP6][SAFI_LABELED_UNICAST] = 0;
#endif /* 0 */
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) &&
diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c
new file mode 100644
index 000000000..615eca588
--- /dev/null
+++ b/bgpd/bgp_label.c
@@ -0,0 +1,338 @@
+/* BGP carrying label information
+ * Copyright (C) 2013 Cumulus Networks, Inc.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra 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.
+ *
+ * GNU Zebra 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 GNU Zebra; 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 "thread.h"
+#include "prefix.h"
+#include "zclient.h"
+#include "stream.h"
+#include "network.h"
+#include "log.h"
+#include "memory.h"
+#include "nexthop.h"
+#include "mpls.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_label.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_debug.h"
+
+extern struct zclient *zclient;
+
+int
+bgp_parse_fec_update (void)
+{
+ struct stream *s;
+ struct bgp_node *rn;
+ struct bgp *bgp;
+ struct bgp_table *table;
+ struct prefix p;
+ u_int32_t label;
+ afi_t afi;
+ safi_t safi;
+
+ s = zclient->ibuf;
+
+ memset(&p, 0, sizeof(struct prefix));
+ p.family = stream_getw(s);
+ p.prefixlen = stream_getc(s);
+ stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
+ label = stream_getl(s);
+
+ /* hack for the bgp instance & SAFI = have to send/receive it */
+ afi = family2afi(p.family);
+ safi = SAFI_LABELED_UNICAST;
+ bgp = bgp_get_default();
+ if (!bgp)
+ {
+ zlog_debug("no default bgp instance");
+ return -1;
+ }
+
+ table = bgp->rib[afi][safi];
+ if (!table)
+ {
+ zlog_debug("no %u labeled-unicast table", p.family);
+ return -1;
+ }
+ rn = bgp_node_lookup(table, &p);
+ if (!rn)
+ {
+ zlog_debug("no node for the prefix");
+ return -1;
+ }
+
+ /* treat it as implicit withdraw - the label is invalid */
+ if (label == MPLS_INVALID_LABEL)
+ bgp_unset_valid_label(rn->local_label);
+ else
+ {
+ label_ntop(label, 1, rn->local_label);
+ bgp_set_valid_label(rn->local_label);
+ }
+ SET_FLAG(rn->flags, BGP_NODE_LABEL_CHANGED);
+ bgp_unlock_node (rn);
+ bgp_process (bgp, rn, afi, safi);
+ return 1;
+}
+
+u_char *
+bgp_adv_label (struct bgp_node *rn, struct bgp_info *ri, struct peer *to,
+ afi_t afi, safi_t safi)
+{
+ struct peer *from;
+ u_char *remote_label;
+ int reflect;
+
+ if (!rn || !ri || !to)
+ return NULL;
+
+ remote_label = ri->extra ? ri->extra->tag : NULL;
+ from = ri->peer;
+ reflect = ((from->sort == BGP_PEER_IBGP) && (to->sort == BGP_PEER_IBGP));
+
+ if (reflect && !CHECK_FLAG(to->af_flags[afi][safi],
+ PEER_FLAG_FORCE_NEXTHOP_SELF))
+ return remote_label;
+
+ if (CHECK_FLAG(to->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED))
+ return remote_label;
+
+ return rn->local_label;
+}
+
+void
+bgp_reg_dereg_for_label (struct bgp_node *rn, struct bgp_info *ri,
+ int reg)
+{
+ struct stream *s;
+ struct prefix *p;
+ int command;
+ u_int16_t flags = 0;
+ size_t flags_pos = 0;
+
+ /* Check socket. */
+ if (!zclient || zclient->sock < 0)
+ return;
+
+ p = &(rn->p);
+ s = zclient->obuf;
+ stream_reset (s);
+ command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER;
+ zclient_create_header (s, command, VRF_DEFAULT);
+ flags_pos = stream_get_endp (s); /* save position of 'flags' */
+ stream_putw(s, flags); /* initial flags */
+ stream_putw(s, PREFIX_FAMILY(p));
+ stream_put_prefix(s, p);
+ if (reg)
+ {
+ assert (ri);
+ if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+ {
+ assert (ri->attr->extra);
+ flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX;
+ stream_putl (s, ri->attr->extra->label_index);
+ }
+ SET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
+ }
+ else
+ UNSET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
+
+ /* Set length and flags */
+ stream_putw_at (s, 0, stream_get_endp (s));
+ stream_putw_at (s, flags_pos, flags);
+
+ zclient_send_message(zclient);
+}
+
+static int
+bgp_nlri_get_labels (struct peer *peer, u_char *pnt, u_char plen,
+ u_char label[])
+{
+ u_char *data = pnt;
+ u_char *lim = pnt + plen;
+ u_char llen = 0;
+
+ for (; data < lim; data += BGP_LABEL_BYTES)
+ {
+ memcpy(label, data, BGP_LABEL_BYTES);
+ llen += 3;
+ if (bgp_is_withdraw_label(label) || label_bos(label))
+ break;
+ }
+ if (!(bgp_is_withdraw_label(label) || label_bos(label)))
+ zlog_warn("%s: [Update:RCVD] invalid label - no bottom of stack",
+ peer->host);
+
+ return llen;
+}
+
+int
+bgp_nlri_parse_label (struct peer *peer, struct attr *attr,
+ struct bgp_nlri *packet)
+{
+ u_char *pnt;
+ u_char *lim;
+ struct prefix p;
+ int psize = 0;
+ int prefixlen;
+ afi_t afi;
+ safi_t safi;
+ int addpath_encoded;
+ u_int32_t addpath_id;
+ u_char label[3];
+ u_char llen;
+
+ /* Check peer status. */
+ if (peer->status != Established)
+ return 0;
+
+ pnt = packet->nlri;
+ lim = pnt + packet->length;
+ afi = packet->afi;
+ safi = packet->safi;
+ addpath_id = 0;
+
+ addpath_encoded = (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV) &&
+ CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV));
+
+ for (; pnt < lim; pnt += psize)
+ {
+ /* Clear prefix structure. */
+ memset (&p, 0, sizeof (struct prefix));
+ llen = 0;
+
+ if (addpath_encoded)
+ {
+
+ /* When packet overflow occurs return immediately. */
+ if (pnt + BGP_ADDPATH_ID_LEN > lim)
+ return -1;
+
+ addpath_id = ntohl(*((uint32_t*) pnt));
+ pnt += BGP_ADDPATH_ID_LEN;
+ }
+
+ /* Fetch prefix length. */
+ prefixlen = *pnt++;
+ p.family = afi2family (packet->afi);
+ psize = PSIZE (prefixlen);
+
+ /* sanity check against packet data */
+ if ((pnt + psize) > lim)
+ {
+ zlog_err ("%s [Error] Update packet error / L-U (prefix length %d exceeds packet size %u)",
+ peer->host,
+ prefixlen, (uint)(lim-pnt));
+ return -1;
+ }
+
+ /* Fill in the labels */
+ llen = bgp_nlri_get_labels(peer, pnt, psize, label);
+ // zlog_debug("rcvd label [%x/%x/%x], llen=%d\n", label[0], label[1], label[2], llen);
+ p.prefixlen = prefixlen - BSIZE(llen);
+
+ /* There needs to be at least one label */
+ if (prefixlen < 24)
+ {
+ zlog_err ("%s [Error] Update packet error"
+ " (wrong label length %d)",
+ peer->host, prefixlen);
+ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_INVAL_NETWORK);
+ return -1;
+ }
+
+ if ((afi == AFI_IP && p.prefixlen > 32)
+ || (afi == AFI_IP6 && p.prefixlen > 128))
+ return -1;
+
+ /* Fetch prefix from NLRI packet */
+ memcpy (&p.u.prefix, pnt + llen, psize - llen);
+
+ /* Check address. */
+ if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
+ {
+ if (IN_CLASSD (ntohl (p.u.prefix4.s_addr)))
+ {
+ /* From RFC4271 Section 6.3:
+ *
+ * If a prefix in the NLRI field is semantically incorrect
+ * (e.g., an unexpected multicast IP address), an error SHOULD
+ * be logged locally, and the prefix SHOULD be ignored.
+ */
+ zlog_err ("%s: IPv4 labeled-unicast NLRI is multicast address %s, ignoring",
+ peer->host, inet_ntoa (p.u.prefix4));
+ continue;
+ }
+ }
+
+ /* Check address. */
+ if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
+ {
+ if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6))
+ {
+ char buf[BUFSIZ];
+
+ zlog_err ("%s: IPv6 labeled-unicast NLRI is link-local address %s, ignoring",
+ peer->host, inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ));
+
+ continue;
+ }
+
+ if (IN6_IS_ADDR_MULTICAST (&p.u.prefix6))
+ {
+ char buf[BUFSIZ];
+
+ zlog_err ("%s: IPv6 unicast NLRI is multicast address %s, ignoring",
+ peer->host, inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ));
+
+ continue;
+ }
+ }
+
+ if (attr)
+ {
+ bgp_update (peer, &p, addpath_id, attr, packet->afi, SAFI_LABELED_UNICAST,
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label, 0, NULL);
+ }
+ else
+ {
+ bgp_withdraw (peer, &p, addpath_id, attr, packet->afi, SAFI_LABELED_UNICAST,
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label, NULL);
+ }
+ }
+
+ /* Packet length consistency check. */
+ if (pnt != lim)
+ {
+ zlog_err ("%s [Error] Update packet error / L-U (%zu data remaining after parsing)",
+ peer->host, lim - pnt);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h
new file mode 100644
index 000000000..49a7b945a
--- /dev/null
+++ b/bgpd/bgp_label.h
@@ -0,0 +1,125 @@
+/* BGP carrying Label information
+ * Copyright (C) 2013 Cumulus Networks, Inc.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra 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.
+ *
+ * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _BGP_LABEL_H
+#define _BGP_LABEL_H
+
+#define BGP_LABEL_BYTES 3
+#define BGP_LABEL_BITS 24
+#define BGP_WITHDRAW_LABEL 0x800000
+
+struct bgp_node;
+struct bgp_info;
+struct peer;
+
+extern void bgp_reg_dereg_for_label (struct bgp_node *rn, struct bgp_info *ri,
+ int reg);
+extern int bgp_parse_fec_update(void);
+extern u_char * bgp_adv_label(struct bgp_node *rn, struct bgp_info *ri,
+ struct peer *to, afi_t afi, safi_t safi);
+
+extern int bgp_nlri_parse_label (struct peer *peer, struct attr *attr,
+ struct bgp_nlri *packet);
+
+static inline int
+bgp_labeled_safi (safi_t safi)
+{
+ if ((safi == SAFI_LABELED_UNICAST) || (safi == SAFI_MPLS_VPN))
+ return 1;
+ return 0;
+}
+
+static inline int
+bgp_is_withdraw_label (u_char *pkt)
+{
+ if ((pkt[0] == 0x80) && (pkt[1] == 0x00) && (pkt[2] == 0x00))
+ return 1;
+ return 0;
+}
+
+static inline u_char *
+bgp_encode_withdraw_label (u_char *pkt)
+{
+ *pkt++ = 0x80; *pkt++ = 0x00; *pkt++ = 0x00;
+ return pkt;
+}
+
+static inline int
+bgp_is_valid_label (u_char *t)
+{
+ if (!t)
+ return 0;
+ return (t[2] & 0x02);
+}
+
+static inline void
+bgp_set_valid_label (u_char *t)
+{
+ if (t)
+ t[2] |= 0x02;
+}
+
+static inline void
+bgp_unset_valid_label (u_char *t)
+{
+ if (t)
+ t[2] &= ~0x02;
+}
+
+static inline void
+bgp_register_for_label (struct bgp_node *rn, struct bgp_info *ri)
+{
+ bgp_reg_dereg_for_label (rn, ri, 1);
+}
+
+static inline void
+bgp_unregister_for_label (struct bgp_node *rn)
+{
+ bgp_reg_dereg_for_label (rn, NULL, 0);
+}
+
+/* Label stream to value */
+static inline u_int32_t
+label_pton (u_char t[])
+{
+ return ((((unsigned int) t[0]) << 12) | (((unsigned int) t[1]) << 4) |
+ ((unsigned int) ((t[2] & 0xF0) >> 4)));
+}
+
+/* Encode label values */
+static inline void
+label_ntop (u_int32_t l, int bos, u_char t[])
+{
+ t[0] = ((l & 0x000FF000) >> 12);
+ t[1] = ((l & 0x00000FF0) >> 4);
+ t[2] = ((l & 0x0000000F) << 4);
+ if (bos)
+ t[2] |= 0x01;
+}
+
+/* Return BOS value of label stream */
+static inline u_char
+label_bos (u_char t[])
+{
+ return (t[2] & 0x01);
+};
+
+#endif /* _BGP_LABEL_H */
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 1773070fe..3b844cf70 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -237,6 +237,8 @@ bgp_exit (int status)
stream_free (bgp_nexthop_buf);
if (bgp_ifindices_buf)
stream_free (bgp_ifindices_buf);
+ if (bgp_label_buf)
+ stream_free (bgp_label_buf);
/* reverse bgp_master_init */
if (bm->master)
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index b0362b553..1e8dc5d97 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -404,8 +404,9 @@ bgp_parse_nexthop_update (int command, vrf_id_t vrf_id)
{
char buf[PREFIX2STR_BUFFER];
prefix2str(&p, buf, sizeof (buf));
- zlog_debug("%d: NH update for %s - metric %d (cur %d) #nhops %d (cur %d)",
- vrf_id, buf, metric, bnc->metric, nexthop_num, bnc->nexthop_num);
+ zlog_debug("%d: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x",
+ vrf_id, buf, metric, bnc->metric, nexthop_num, bnc->nexthop_num,
+ bnc->flags);
}
if (metric != bnc->metric)
@@ -678,6 +679,8 @@ evaluate_paths (struct bgp_nexthop_cache *bnc)
struct bgp *bgp = bnc->bgp;
int afi;
struct peer *peer = (struct peer *)bnc->nht_info;
+ struct bgp_table *table;
+ safi_t safi;
if (BGP_DEBUG(nht, NHT))
{
@@ -695,7 +698,10 @@ evaluate_paths (struct bgp_nexthop_cache *bnc)
continue;
rn = path->net;
+ assert (rn && bgp_node_table (rn));
afi = family2afi(rn->p.family);
+ table = bgp_node_table (rn);
+ safi = table->safi;
/* Path becomes valid/invalid depending on whether the nexthop
* reachable/unreachable.
@@ -705,15 +711,13 @@ evaluate_paths (struct bgp_nexthop_cache *bnc)
{
if (CHECK_FLAG (path->flags, BGP_INFO_VALID))
{
- bgp_aggregate_decrement (bgp, &rn->p, path,
- afi, SAFI_UNICAST);
+ bgp_aggregate_decrement (bgp, &rn->p, path, afi, safi);
bgp_info_unset_flag (rn, path, BGP_INFO_VALID);
}
else
{
bgp_info_set_flag (rn, path, BGP_INFO_VALID);
- bgp_aggregate_increment (bgp, &rn->p, path,
- afi, SAFI_UNICAST);
+ bgp_aggregate_increment (bgp, &rn->p, path, afi, safi);
}
}
@@ -727,7 +731,7 @@ evaluate_paths (struct bgp_nexthop_cache *bnc)
CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED))
SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED);
- bgp_process(bgp, rn, afi, SAFI_UNICAST);
+ bgp_process(bgp, rn, afi, safi);
}
if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED))
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 51079f31e..83fc3fe97 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -108,6 +108,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso
case SAFI_MULTICAST:
json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "multicast");
break;
+ case SAFI_LABELED_UNICAST:
+ json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "labeled-unicast");
+ break;
case SAFI_MPLS_VPN:
json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "MPLS-labeled VPN");
break;
@@ -148,6 +151,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso
case SAFI_MULTICAST:
vty_out (vty, "SAFI Multicast");
break;
+ case SAFI_LABELED_UNICAST:
+ vty_out (vty, "SAFI Labeled-unicast");
+ break;
case SAFI_MPLS_VPN:
vty_out (vty, "SAFI MPLS-labeled VPN");
break;
@@ -1143,10 +1149,12 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability)
{
if (! peer->afc_nego[AFI_IP][SAFI_UNICAST]
&& ! peer->afc_nego[AFI_IP][SAFI_MULTICAST]
+ && ! peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST]
&& ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
&& ! peer->afc_nego[AFI_IP][SAFI_ENCAP]
&& ! peer->afc_nego[AFI_IP6][SAFI_UNICAST]
&& ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST]
+ && ! peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST]
&& ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]
&& ! peer->afc_nego[AFI_IP6][SAFI_ENCAP]
&& ! peer->afc_nego[AFI_L2VPN][SAFI_EVPN])
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 853fcc869..3b1305560 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -55,6 +55,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_advertise.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_updgrp.h"
+#include "bgpd/bgp_label.h"
/* Set up BGP packet marker and packet type. */
int
@@ -1153,8 +1154,10 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
{
peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST];
peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST];
+ peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] = peer->afc[AFI_IP][SAFI_LABELED_UNICAST];
peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST];
peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST];
+ peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] = peer->afc[AFI_IP6][SAFI_LABELED_UNICAST];
}
/* When collision is detected and this peer is closed. Retrun
@@ -1342,6 +1345,8 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet, i
case SAFI_UNICAST:
case SAFI_MULTICAST:
return bgp_nlri_parse_ip (peer, mp_withdraw?NULL:attr, packet);
+ case SAFI_LABELED_UNICAST:
+ return bgp_nlri_parse_label (peer, mp_withdraw?NULL:attr, packet);
case SAFI_MPLS_VPN:
return bgp_nlri_parse_vpn (peer, mp_withdraw?NULL:attr, packet);
case SAFI_ENCAP:
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 32cf0bcb8..88147e2b6 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -35,6 +35,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "thread.h"
#include "workqueue.h"
#include "queue.h"
+#include "mpls.h"
#include "memory.h"
#include "lib/json.h"
@@ -62,6 +63,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_mpath.h"
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_updgrp.h"
+#include "bgpd/bgp_label.h"
#if ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
@@ -296,6 +298,20 @@ bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri)
}
}
+static int
+bgp_label_index_differs (struct bgp_info *ri1, struct bgp_info *ri2)
+{
+ u_int32_t ri1_label_index = BGP_INVALID_LABEL_INDEX;
+ u_int32_t ri2_label_index = BGP_INVALID_LABEL_INDEX;
+
+ if (ri1->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+ ri1_label_index = ri1->attr->extra->label_index;
+
+ if (ri2->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+ ri2_label_index = ri2->attr->extra->label_index;
+
+ return (!(ri1_label_index == ri2_label_index));
+}
/* Set/unset bgp_info flags, adjusting any other state as needed.
* This is here primarily to keep prefix-count in check.
@@ -1187,7 +1203,8 @@ subgroup_announce_reset_nhop (u_char family, struct attr *attr)
}
int
-subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
+subgroup_announce_check (struct bgp_node *rn, struct bgp_info *ri,
+ struct update_subgroup *subgrp,
struct prefix *p, struct attr *attr)
{
struct bgp_filter *filter;
@@ -1261,6 +1278,21 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
return 0;
}
+ /* If it's labeled safi, make sure the route has a valid label. */
+ if (bgp_labeled_safi(safi))
+ {
+ u_char *tag = bgp_adv_label(rn, ri, peer, afi, safi);
+ if (!bgp_is_valid_label(tag))
+ {
+ if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
+ zlog_debug ("u%" PRIu64 ":s%" PRIu64 " %s/%d is filtered - no label (%p)",
+ subgrp->update_group->id, subgrp->id,
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen, tag);
+ return 0;
+ }
+ }
+
/* Do not send back route to sender. */
if (onlypeer && from == onlypeer)
{
@@ -1804,7 +1836,7 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp,
/* Announcement to the subgroup. If the route is filtered withdraw it. */
if (selected)
{
- if (subgroup_announce_check(selected, subgrp, p, &attr))
+ if (subgroup_announce_check(rn, selected, subgrp, p, &attr))
bgp_adj_out_set_subgroup(rn, subgrp, &attr, selected);
else
bgp_adj_out_unset_subgroup(rn, subgrp, 1, selected->addpath_tx_id);
@@ -1914,7 +1946,39 @@ bgp_process_main (struct work_queue *wq, void *data)
old_select = old_and_new.old;
new_select = old_and_new.new;
- /* Nothing to do. */
+ /* Do we need to allocate or free labels?
+ * Right now, since we only deal with per-prefix labels, it is not necessary
+ * to do this upon changes to best path except of the label index changes.
+ */
+ bgp_table_lock (bgp_node_table (rn));
+ if (bgp_labeled_safi (safi))
+ {
+ if (new_select)
+ {
+ if (!old_select ||
+ bgp_label_index_differs (new_select, old_select) ||
+ new_select->sub_type != old_select->sub_type)
+ {
+ if (new_select->sub_type == BGP_ROUTE_STATIC &&
+ new_select->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+ {
+ if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
+ bgp_unregister_for_label (rn);
+ label_ntop (MPLS_IMP_NULL_LABEL, 1, rn->local_label);
+ bgp_set_valid_label(rn->local_label);
+ }
+ else
+ bgp_register_for_label (rn, new_select);
+ }
+ }
+ else if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
+ bgp_unregister_for_label (rn);
+ }
+
+ /* If best route remains the same and this is not due to user-initiated
+ * clear, see exactly what needs to be done.
+ */
+
if (old_select && old_select == new_select &&
!CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR) &&
!CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED) &&
@@ -1926,10 +1990,26 @@ bgp_process_main (struct work_queue *wq, void *data)
vnc_import_bgp_add_route(bgp, p, old_select);
vnc_import_bgp_exterior_add_route(bgp, p, old_select);
#endif
- bgp_zebra_announce (p, old_select, bgp, afi, safi);
+ if (bgp_fibupd_safi(safi) &&
+ !bgp->name &&
+ !bgp_option_check (BGP_OPT_NO_FIB) &&
+ new_select->type == ZEBRA_ROUTE_BGP &&
+ new_select->sub_type == BGP_ROUTE_NORMAL)
+ bgp_zebra_announce (rn, p, old_select, bgp, afi, safi);
}
UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
bgp_zebra_clear_route_change_flags (rn);
+
+ /* If there is a change of interest to peers, reannounce the route. */
+ if (CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED) ||
+ CHECK_FLAG (rn->flags, BGP_NODE_LABEL_CHANGED))
+ {
+ group_announce_route(bgp, afi, safi, rn, new_select);
+
+ UNSET_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED);
+ UNSET_FLAG (rn->flags, BGP_NODE_LABEL_CHANGED);
+ }
+
UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
return WQ_SUCCESS;
}
@@ -1978,7 +2058,7 @@ bgp_process_main (struct work_queue *wq, void *data)
group_announce_route(bgp, afi, safi, rn, new_select);
/* FIB update. */
- if ((safi == SAFI_UNICAST || safi == SAFI_MULTICAST) &&
+ if (bgp_fibupd_safi(safi) &&
(bgp->inst_type != BGP_INSTANCE_TYPE_VIEW) &&
!bgp_option_check (BGP_OPT_NO_FIB))
{
@@ -1986,7 +2066,7 @@ bgp_process_main (struct work_queue *wq, void *data)
&& new_select->type == ZEBRA_ROUTE_BGP
&& (new_select->sub_type == BGP_ROUTE_NORMAL ||
new_select->sub_type == BGP_ROUTE_AGGREGATE))
- bgp_zebra_announce (p, new_select, bgp, afi, safi);
+ bgp_zebra_announce (rn, p, new_select, bgp, afi, safi);
else
{
/* Withdraw the route from the kernel. */
@@ -2406,6 +2486,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
struct bgp_info *new;
const char *reason;
char pfx_buf[BGP_PRD_PATH_STRLEN];
+ char label_buf[20];
int connected = 0;
int do_loop_check = 1;
#if ENABLE_BGP_VNC
@@ -2417,6 +2498,9 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
bgp = peer->bgp;
rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd);
+ label_buf[0] = '\0';
+ if (bgp_labeled_safi(safi))
+ sprintf (label_buf, "label %u", label_pton(tag));
/* When peer's soft reconfiguration enabled. Record input packet in
Adj-RIBs-In. */
@@ -2516,6 +2600,8 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
/* Same attribute comes in. */
if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED)
&& attrhash_cmp (ri->attr, attr_new)
+ && (!bgp_labeled_safi(safi) ||
+ memcmp ((bgp_info_extra_get (ri))->tag, tag, 3) == 0)
&& (overlay_index_equal(afi, ri, evpn==NULL?NULL:&evpn->eth_s_id,
evpn==NULL?NULL:&evpn->gw_ip)))
{
@@ -2524,9 +2610,9 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
&& CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
{
if (bgp_debug_update(peer, p, NULL, 1))
- zlog_debug ("%s rcvd %s", peer->host,
+ zlog_debug ("%s rcvd %s %s", peer->host,
bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
- addpath_id, pfx_buf, sizeof (pfx_buf)));
+ addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf);
if (bgp_damp_update (ri, rn, afi, safi) != BGP_DAMP_SUPPRESSED)
{
@@ -2544,10 +2630,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
peer->rcvd_attr_printed = 1;
}
- zlog_debug ("%s rcvd %s...duplicate ignored",
+ zlog_debug ("%s rcvd %s %s...duplicate ignored",
peer->host,
bgp_debug_rdpfxpath2str (prd, p, addpath_id ?
- 1 : 0, addpath_id, pfx_buf, sizeof (pfx_buf)));
+ 1 : 0, addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf);
}
/* graceful restart STALE flag unset. */
@@ -2568,18 +2654,18 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
{
if (bgp_debug_update(peer, p, NULL, 1))
- zlog_debug ("%s rcvd %s, flapped quicker than processing",
+ zlog_debug ("%s rcvd %s %s, flapped quicker than processing",
peer->host,
bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
- addpath_id, pfx_buf, sizeof (pfx_buf)));
+ addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf);
bgp_info_restore (rn, ri);
}
/* Received Logging. */
if (bgp_debug_update(peer, p, NULL, 1))
- zlog_debug ("%s rcvd %s", peer->host,
+ zlog_debug ("%s rcvd %s %s", peer->host,
bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
- addpath_id, pfx_buf, sizeof (pfx_buf)));
+ addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf);
/* graceful restart STALE flag unset. */
if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
@@ -2637,7 +2723,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
ri->attr = attr_new;
/* Update MPLS tag. */
- if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN)
+ if (bgp_labeled_safi(safi))
memcpy ((bgp_info_extra_get (ri))->tag, tag, 3);
#if ENABLE_BGP_VNC
@@ -2678,8 +2764,9 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
}
}
- /* Nexthop reachability check. */
- if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST)
+ /* Nexthop reachability check - for unicast and labeled-unicast.. */
+ if ((afi == AFI_IP || afi == AFI_IP6) &&
+ (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST))
{
if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 &&
! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
@@ -2759,16 +2846,16 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
peer->rcvd_attr_printed = 1;
}
- zlog_debug ("%s rcvd %s", peer->host,
+ zlog_debug ("%s rcvd %s%s ", peer->host,
bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
- addpath_id, pfx_buf, sizeof (pfx_buf)));
+ addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf);
}
/* Make new BGP info. */
new = info_make(type, sub_type, 0, peer, attr_new, rn);
/* Update MPLS tag. */
- if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN)
+ if (bgp_labeled_safi(safi) || safi == SAFI_EVPN)
memcpy ((bgp_info_extra_get (new))->tag, tag, 3);
/* Update Overlay Index */
@@ -2778,7 +2865,8 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
evpn==NULL?NULL:&evpn->gw_ip);
}
/* Nexthop reachability check. */
- if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST)
+ if ((afi == AFI_IP || afi == AFI_IP6) &&
+ (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST))
{
if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 &&
! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
@@ -2873,10 +2961,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
peer->rcvd_attr_printed = 1;
}
- zlog_debug ("%s rcvd UPDATE about %s -- DENIED due to: %s",
+ zlog_debug ("%s rcvd UPDATE about %s %s -- DENIED due to: %s",
peer->host,
bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
- addpath_id, pfx_buf, sizeof (pfx_buf)), reason);
+ addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf, reason);
}
if (ri)
@@ -3702,9 +3790,9 @@ bgp_static_free (struct bgp_static *bgp_static)
XFREE (MTYPE_BGP_STATIC, bgp_static);
}
-static void
-bgp_static_update_main (struct bgp *bgp, struct prefix *p,
- struct bgp_static *bgp_static, afi_t afi, safi_t safi)
+void
+bgp_static_update (struct bgp *bgp, struct prefix *p,
+ struct bgp_static *bgp_static, afi_t afi, safi_t safi)
{
struct bgp_node *rn;
struct bgp_info *ri;
@@ -3732,6 +3820,13 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
if (bgp_static->atomic)
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
+ /* Store label index, if required. */
+ if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX)
+ {
+ (bgp_attr_extra_get (&attr))->label_index = bgp_static->label_index;
+ attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX);
+ }
+
/* Apply route-map. */
if (bgp_static->rmap.name)
{
@@ -3818,9 +3913,11 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
#endif
/* Nexthop reachability check. */
- if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
+ if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK) &&
+ safi == SAFI_UNICAST)
{
- if (bgp_find_or_add_nexthop (bgp, afi, ri, NULL, 0))
+ if (bgp_find_or_add_nexthop (bgp, afi, ri, NULL, 0) &&
+ safi == SAFI_UNICAST)
bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
else
{
@@ -3904,13 +4001,6 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
}
void
-bgp_static_update (struct bgp *bgp, struct prefix *p,
- struct bgp_static *bgp_static, afi_t afi, safi_t safi)
-{
- bgp_static_update_main (bgp, p, bgp_static, afi, safi);
-}
-
-void
bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi,
safi_t safi)
{
@@ -4158,7 +4248,8 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p,
route should be installed as valid. */
static int
bgp_static_set (struct vty *vty, const char *ip_str,
- afi_t afi, safi_t safi, const char *rmap, int backdoor)
+ afi_t afi, safi_t safi, const char *rmap, int backdoor,
+ u_int32_t label_index)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int ret;
@@ -4191,6 +4282,13 @@ bgp_static_set (struct vty *vty, const char *ip_str,
/* Configuration change. */
bgp_static = rn->info;
+ /* Label index cannot be changed. */
+ if (bgp_static->label_index != label_index)
+ {
+ vty_out (vty, "%% Label index cannot be changed%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
/* Check previous routes are installed into BGP. */
if (bgp_static->valid && bgp_static->backdoor != backdoor)
need_update = 1;
@@ -4222,6 +4320,7 @@ bgp_static_set (struct vty *vty, const char *ip_str,
bgp_static->valid = 0;
bgp_static->igpmetric = 0;
bgp_static->igpnexthop.s_addr = 0;
+ bgp_static->label_index = label_index;
if (rmap)
{
@@ -4748,7 +4847,8 @@ DEFUN (bgp_network,
{
int idx_ipv4_prefixlen = 1;
return bgp_static_set (vty, argv[idx_ipv4_prefixlen]->arg,
- AFI_IP, bgp_node_safi (vty), NULL, 0);
+ AFI_IP, bgp_node_safi (vty), NULL, 0,
+ BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_route_map,
@@ -4762,7 +4862,8 @@ DEFUN (bgp_network_route_map,
int idx_ipv4_prefixlen = 1;
int idx_word = 3;
return bgp_static_set (vty, argv[idx_ipv4_prefixlen]->arg,
- AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0);
+ AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0,
+ BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_backdoor,
@@ -4774,7 +4875,7 @@ DEFUN (bgp_network_backdoor,
{
int idx_ipv4_prefixlen = 1;
return bgp_static_set (vty, argv[idx_ipv4_prefixlen]->arg, AFI_IP, SAFI_UNICAST,
- NULL, 1);
+ NULL, 1, BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask,
@@ -4798,7 +4899,7 @@ DEFUN (bgp_network_mask,
}
return bgp_static_set (vty, prefix_str,
- AFI_IP, bgp_node_safi (vty), NULL, 0);
+ AFI_IP, bgp_node_safi (vty), NULL, 0, BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask_route_map,
@@ -4825,7 +4926,7 @@ DEFUN (bgp_network_mask_route_map,
}
return bgp_static_set (vty, prefix_str,
- AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0);
+ AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0, BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask_backdoor,
@@ -4850,7 +4951,8 @@ DEFUN (bgp_network_mask_backdoor,
}
return bgp_static_set (vty, prefix_str, AFI_IP, SAFI_UNICAST,
- NULL, 1);
+ NULL, 1,
+ BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask_natural,
@@ -4871,7 +4973,8 @@ DEFUN (bgp_network_mask_natural,
}
return bgp_static_set (vty, prefix_str,
- AFI_IP, bgp_node_safi (vty), NULL, 0);
+ AFI_IP, bgp_node_safi (vty), NULL, 0,
+ BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask_natural_route_map,
@@ -4895,7 +4998,8 @@ DEFUN (bgp_network_mask_natural_route_map,
}
return bgp_static_set (vty, prefix_str,
- AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0);
+ AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0,
+ BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask_natural_backdoor,
@@ -4917,7 +5021,39 @@ DEFUN (bgp_network_mask_natural_backdoor,
}
return bgp_static_set (vty, prefix_str, AFI_IP, SAFI_UNICAST,
- NULL, 1);
+ NULL, 1, BGP_INVALID_LABEL_INDEX);
+}
+
+DEFUN (bgp_network_label_index,
+ bgp_network_label_index_cmd,
+ "network A.B.C.D/M label-index (0-4294967294)",
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Label index to associate with the prefix\n"
+ "Label index value\n")
+{
+ u_int32_t label_index;
+
+ VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg);
+ return bgp_static_set (vty, argv[1]->arg,
+ AFI_IP, bgp_node_safi (vty), NULL, 0, label_index);
+}
+
+DEFUN (bgp_network_label_index_route_map,
+ bgp_network_label_index_route_map_cmd,
+ "network A.B.C.D/M label-index (0-4294967294) route-map WORD",
+ "Specify a network to announce via BGP\n"
+ "IP prefix\n"
+ "Label index to associate with the prefix\n"
+ "Label index value\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+{
+ u_int32_t label_index;
+
+ VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg);
+ return bgp_static_set (vty, argv[1]->arg,
+ AFI_IP, bgp_node_safi (vty), argv[5]->arg, 0, label_index);
}
DEFUN (no_bgp_network,
@@ -4988,6 +5124,26 @@ DEFUN (no_bgp_network_mask_natural,
bgp_node_safi (vty));
}
+ALIAS (no_bgp_network,
+ no_bgp_network_label_index_cmd,
+ "no network A.B.C.D/M label-index (0-4294967294)",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Label index to associate with the prefix\n"
+ "Label index value\n")
+
+ALIAS (no_bgp_network,
+ no_bgp_network_label_index_route_map_cmd,
+ "no network A.B.C.D/M label-index (0-4294967294) route-map WORD",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "IP prefix\n"
+ "Label index to associate with the prefix\n"
+ "Label index value\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+
DEFUN (ipv6_bgp_network,
ipv6_bgp_network_cmd,
"network X:X::X:X/M",
@@ -4996,7 +5152,8 @@ DEFUN (ipv6_bgp_network,
{
int idx_ipv6_prefixlen = 1;
return bgp_static_set (vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6, bgp_node_safi(vty),
- NULL, 0);
+ NULL, 0,
+ BGP_INVALID_LABEL_INDEX);
}
DEFUN (ipv6_bgp_network_route_map,
@@ -5010,7 +5167,40 @@ DEFUN (ipv6_bgp_network_route_map,
int idx_ipv6_prefixlen = 1;
int idx_word = 3;
return bgp_static_set (vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6,
- bgp_node_safi (vty), argv[idx_word]->arg, 0);
+ bgp_node_safi (vty), argv[idx_word]->arg, 0,
+ BGP_INVALID_LABEL_INDEX);
+}
+
+DEFUN (ipv6_bgp_network_label_index,
+ ipv6_bgp_network_label_index_cmd,
+ "network X:X::X:X/M label-index (0-4294967294)",
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix <network>/<length>\n"
+ "Label index to associate with the prefix\n"
+ "Label index value\n")
+{
+ u_int32_t label_index;
+
+ VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg);
+ return bgp_static_set (vty, argv[1]->arg,
+ AFI_IP6, bgp_node_safi (vty), NULL, 0, label_index);
+}
+
+DEFUN (ipv6_bgp_network_label_index_route_map,
+ ipv6_bgp_network_label_index_route_map_cmd,
+ "network X:X::X:X/M label-index (0-4294967294) route-map WORD",
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix\n"
+ "Label index to associate with the prefix\n"
+ "Label index value\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+{
+ u_int32_t label_index;
+
+ VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg);
+ return bgp_static_set (vty, argv[1]->arg,
+ AFI_IP6, bgp_node_safi (vty), argv[5]->arg, 0, label_index);
}
DEFUN (no_ipv6_bgp_network,
@@ -5026,6 +5216,26 @@ DEFUN (no_ipv6_bgp_network,
return bgp_static_unset (vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6, bgp_node_safi(vty));
}
+ALIAS (no_ipv6_bgp_network,
+ no_ipv6_bgp_network_label_index_cmd,
+ "no network X:X::X:X/M label-index (0-4294967294)",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix <network>/<length>\n"
+ "Label index to associate with the prefix\n"
+ "Label index value\n")
+
+ALIAS (no_ipv6_bgp_network,
+ no_ipv6_bgp_network_label_index_route_map_cmd,
+ "no network X:X::X:X/M label-index (0-4294967294) route-map WORD",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "IPv6 prefix\n"
+ "Label index to associate with the prefix\n"
+ "Label index value\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
+
/* Aggreagete address:
advertise-map Set condition to advertise attribute
@@ -5557,6 +5767,8 @@ bgp_aggregate_unset (struct vty *vty, const char *prefix_str,
aggregate = rn->info;
if (aggregate->safi & SAFI_UNICAST)
bgp_aggregate_delete (bgp, &p, afi, SAFI_UNICAST, aggregate);
+ if (aggregate->safi & SAFI_LABELED_UNICAST)
+ bgp_aggregate_delete (bgp, &p, afi, SAFI_LABELED_UNICAST, aggregate);
if (aggregate->safi & SAFI_MULTICAST)
bgp_aggregate_delete (bgp, &p, afi, SAFI_MULTICAST, aggregate);
@@ -5615,6 +5827,8 @@ bgp_aggregate_set (struct vty *vty, const char *prefix_str,
/* Aggregate address insert into BGP routing table. */
if (safi & SAFI_UNICAST)
bgp_aggregate_add (bgp, &p, afi, SAFI_UNICAST, aggregate);
+ if (safi & SAFI_LABELED_UNICAST)
+ bgp_aggregate_add (bgp, &p, afi, SAFI_LABELED_UNICAST, aggregate);
if (safi & SAFI_MULTICAST)
bgp_aggregate_add (bgp, &p, afi, SAFI_MULTICAST, aggregate);
@@ -7439,6 +7653,28 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (binfo->extra && binfo->extra->damp_info)
bgp_damp_info_vty (vty, binfo, json_path);
+ /* Label information */
+ if ((bgp_labeled_safi(safi) && binfo->extra) ||
+ (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))))
+ {
+ if (bgp_labeled_safi(safi) && binfo->extra)
+ {
+ uint32_t label = label_pton(binfo->extra->tag);
+ if (json_paths)
+ json_object_int_add(json_path, "remoteLabel", label);
+ else
+ vty_out(vty, " Remote label: %d%s", label, VTY_NEWLINE);
+ }
+
+ if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)))
+ {
+ if (json_paths)
+ json_object_int_add(json_path, "labelIndex", attr->extra->label_index);
+ else
+ vty_out(vty, " Label Index: %d%s", attr->extra->label_index, VTY_NEWLINE);
+ }
+ }
+
/* Line 8 display Addpath IDs */
if (binfo->addpath_rx_id || binfo->addpath_tx_id)
{
@@ -7932,6 +8168,18 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) ? ":" : "",
buf2,
p->prefixlen, VTY_NEWLINE);
+
+ if (bgp_labeled_safi(safi))
+ {
+ vty_out(vty, "Local label: ");
+ if (!bgp_is_valid_label(rn->local_label))
+ vty_out(vty, "not allocated%s", VTY_NEWLINE);
+ else
+ {
+ uint32_t label = label_pton(rn->local_label);
+ vty_out(vty, "%d%s", label, VTY_NEWLINE);
+ }
+ }
}
for (ri = rn->info; ri; ri = ri->next)
@@ -8213,7 +8461,7 @@ bgp_show_lcommunity_list (struct vty *vty, struct bgp *bgp, const char *lcom,
DEFUN (show_ip_bgp_large_community_list,
show_ip_bgp_large_community_list_cmd,
- "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] large-community-list <(1-500)|WORD> [json]",
+ "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap|labeled-unicast>]] large-community-list <(1-500)|WORD> [json]",
SHOW_STR
IP_STR
BGP_STR
@@ -8224,6 +8472,7 @@ DEFUN (show_ip_bgp_large_community_list,
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n"
+ "Address Family modifier\n"
"Display routes matching the large-community-list\n"
"large-community-list number\n"
"large-community-list name\n"
@@ -8259,7 +8508,7 @@ DEFUN (show_ip_bgp_large_community_list,
}
DEFUN (show_ip_bgp_large_community,
show_ip_bgp_large_community_cmd,
- "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] large-community [AA:BB:CC] [json]",
+ "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap|labeled-unicast>]] large-community [AA:BB:CC] [json]",
SHOW_STR
IP_STR
BGP_STR
@@ -8270,6 +8519,7 @@ DEFUN (show_ip_bgp_large_community,
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n"
+ "Address Family modifier\n"
"Display routes matching the large-communities\n"
"List of large-community numbers\n"
JSON_STR)
@@ -9210,7 +9460,7 @@ bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, u_c
DEFUN (show_ip_bgp_instance_neighbor_prefix_counts,
show_ip_bgp_instance_neighbor_prefix_counts_cmd,
- "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] "
+ "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap|labeled-unicast>]] "
"neighbors <A.B.C.D|X:X::X:X|WORD> prefix-counts [json]",
SHOW_STR
IP_STR
@@ -9222,6 +9472,7 @@ DEFUN (show_ip_bgp_instance_neighbor_prefix_counts,
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n"
+ "Address Family modifier\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
@@ -10528,6 +10779,9 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp,
p->prefixlen);
}
+ if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX)
+ vty_out (vty, " label-index %u", bgp_static->label_index);
+
if (bgp_static->rmap.name)
vty_out (vty, " route-map %s", bgp_static->rmap.name);
else
@@ -10654,6 +10908,8 @@ bgp_route_init (void)
install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd);
install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd);
install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd);
+ install_element (BGP_IPV4L_NODE, &no_bgp_network_label_index_cmd);
+ install_element (BGP_IPV4L_NODE, &no_bgp_network_label_index_route_map_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_table_map_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_network_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd);
@@ -10681,6 +10937,21 @@ bgp_route_init (void)
install_element (BGP_IPV4M_NODE, &no_aggregate_address_cmd);
install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd);
+ /* IPv4 labeled-unicast configuration. */
+ install_element (BGP_IPV4L_NODE, &bgp_table_map_cmd);
+ install_element (BGP_IPV4L_NODE, &bgp_network_cmd);
+ install_element (BGP_IPV4L_NODE, &bgp_network_mask_cmd);
+ install_element (BGP_IPV4L_NODE, &bgp_network_mask_natural_cmd);
+ install_element (BGP_IPV4L_NODE, &bgp_network_route_map_cmd);
+ install_element (BGP_IPV4L_NODE, &bgp_network_mask_route_map_cmd);
+ install_element (BGP_IPV4L_NODE, &bgp_network_mask_natural_route_map_cmd);
+ install_element (BGP_IPV4L_NODE, &bgp_network_label_index_cmd);
+ install_element (BGP_IPV4L_NODE, &bgp_network_label_index_route_map_cmd);
+ install_element (BGP_IPV4L_NODE, &no_bgp_table_map_cmd);
+ install_element (BGP_IPV4L_NODE, &no_bgp_network_cmd);
+ install_element (BGP_IPV4L_NODE, &no_bgp_network_mask_cmd);
+ install_element (BGP_IPV4L_NODE, &no_bgp_network_mask_natural_cmd);
+
install_element (VIEW_NODE, &show_ip_bgp_instance_all_cmd);
install_element (VIEW_NODE, &show_ip_bgp_cmd);
install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
@@ -10714,6 +10985,10 @@ bgp_route_init (void)
install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd);
install_element (BGP_IPV6_NODE, &no_bgp_table_map_cmd);
install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd);
+ install_element (BGP_IPV6_NODE, &ipv6_bgp_network_label_index_cmd);
+ install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_label_index_cmd);
+ install_element (BGP_IPV6_NODE, &ipv6_bgp_network_label_index_route_map_cmd);
+ install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_label_index_route_map_cmd);
install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd);
install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd);
@@ -10721,6 +10996,12 @@ bgp_route_init (void)
install_element (BGP_IPV6M_NODE, &ipv6_bgp_network_cmd);
install_element (BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd);
+ install_element (BGP_IPV6L_NODE, &bgp_table_map_cmd);
+ install_element (BGP_IPV6L_NODE, &ipv6_bgp_network_cmd);
+ install_element (BGP_IPV6L_NODE, &ipv6_bgp_network_route_map_cmd);
+ install_element (BGP_IPV6L_NODE, &no_bgp_table_map_cmd);
+ install_element (BGP_IPV6L_NODE, &no_ipv6_bgp_network_cmd);
+
install_element (BGP_NODE, &bgp_distance_cmd);
install_element (BGP_NODE, &no_bgp_distance_cmd);
install_element (BGP_NODE, &bgp_distance_source_cmd);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index e75978d00..35994d4f7 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -150,6 +150,7 @@ struct bgp_info
#define BGP_INFO_COUNTED (1 << 10)
#define BGP_INFO_MULTIPATH (1 << 11)
#define BGP_INFO_MULTIPATH_CHG (1 << 12)
+#define BGP_INFO_RIB_ATTR_CHG (1 << 13)
/* BGP route type. This can be static, RIP, OSPF, BGP etc. */
u_char type;
@@ -179,6 +180,10 @@ struct bgp_static
/* Backdoor configuration. */
int backdoor;
+ /* Label index configuration; applies to LU prefixes. */
+ u_int32_t label_index;
+#define BGP_INVALID_LABEL_INDEX 0xFFFFFFFF
+
/* Import check status. */
u_char valid;
@@ -273,6 +278,16 @@ bgp_bump_version (struct bgp_node *node)
node->version = bgp_table_next_version(bgp_node_table(node));
}
+static inline int
+bgp_fibupd_safi (safi_t safi)
+{
+ if (safi == SAFI_UNICAST ||
+ safi == SAFI_MULTICAST ||
+ safi == SAFI_LABELED_UNICAST)
+ return 1;
+ return 0;
+}
+
/* Prototypes. */
extern void bgp_process_queue_init (void);
extern void bgp_route_init (void);
@@ -370,7 +385,7 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp,
struct bgp_node *rn,
u_int32_t addpath_tx_id);
-extern int subgroup_announce_check(struct bgp_info *ri,
+extern int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri,
struct update_subgroup *subgrp,
struct prefix *p, struct attr *attr);
diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
index 3c96dac61..a6b99a53d 100644
--- a/bgpd/bgp_table.h
+++ b/bgpd/bgp_table.h
@@ -56,10 +56,14 @@ struct bgp_node
struct bgp_node *prn;
+ u_char local_label[3];
+
uint64_t version;
u_char flags;
#define BGP_NODE_PROCESS_SCHEDULED (1 << 0)
#define BGP_NODE_USER_CLEAR (1 << 1)
+#define BGP_NODE_LABEL_CHANGED (1 << 2)
+#define BGP_NODE_REGISTERED_FOR_LABEL (1 << 3)
};
/*
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index efb2046e1..ac5f77474 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -618,7 +618,7 @@ subgroup_announce_table (struct update_subgroup *subgrp,
if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) ||
(addpath_capable && bgp_addpath_tx_path(peer, afi, safi, ri)))
{
- if (subgroup_announce_check (ri, subgrp, &rn->p, &attr))
+ if (subgroup_announce_check (rn, ri, subgrp, &rn->p, &attr))
bgp_adj_out_set_subgroup (rn, subgrp, &attr, ri);
else
bgp_adj_out_unset_subgroup (rn, subgrp, 1, ri->addpath_tx_id);
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index 8839de391..9be1a50db 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -43,6 +43,7 @@
#include "workqueue.h"
#include "hash.h"
#include "queue.h"
+#include "mpls.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_debug.h"
@@ -54,6 +55,7 @@
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_label.h"
/********************
* PRIVATE FUNCTIONS
@@ -653,6 +655,7 @@ subgroup_update_packet (struct update_subgroup *subgrp)
int addpath_encode = 0;
u_int32_t addpath_tx_id = 0;
struct prefix_rd *prd = NULL;
+ char label_buf[20];
if (!subgrp)
return NULL;
@@ -660,7 +663,6 @@ subgroup_update_packet (struct update_subgroup *subgrp)
if (bpacket_queue_is_full (SUBGRP_INST (subgrp), SUBGRP_PKTQ (subgrp)))
return NULL;
-
peer = SUBGRP_PEER (subgrp);
afi = SUBGRP_AFI (subgrp);
safi = SUBGRP_SAFI (subgrp);
@@ -668,6 +670,7 @@ subgroup_update_packet (struct update_subgroup *subgrp)
stream_reset (s);
snlri = subgrp->scratch;
stream_reset (snlri);
+ label_buf[0] = '\0';
bpacket_attr_vec_arr_reset (&vecarr);
@@ -760,8 +763,9 @@ subgroup_update_packet (struct update_subgroup *subgrp)
if (rn->prn)
prd = (struct prefix_rd *) &rn->prn->p;
- if (binfo && binfo->extra)
- tag = binfo->extra->tag;
+ tag = bgp_adv_label(rn, binfo, peer, afi, safi);
+ if (bgp_labeled_safi(safi))
+ sprintf (label_buf, "label %u", label_pton(tag));
if (stream_empty (snlri))
mpattrlen_pos = bgp_packet_mpattr_start (snlri, afi, safi,
@@ -783,14 +787,26 @@ subgroup_update_packet (struct update_subgroup *subgrp)
{
zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE w/ attr: %s",
subgrp->update_group->id, subgrp->id, send_attr_str);
+ if (!stream_empty (snlri))
+ {
+ iana_afi_t pkt_afi;
+ safi_t pkt_safi;
+
+ pkt_afi = afi_int2iana (afi);
+ pkt_safi = safi_int2iana (safi);
+ zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send MP_REACH for afi/safi %d/%d",
+ subgrp->update_group->id, subgrp->id, pkt_afi, pkt_safi);
+ }
+
send_attr_printed = 1;
}
- zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s",
+ zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s %s",
subgrp->update_group->id, subgrp->id,
bgp_debug_rdpfxpath2str (prd, &rn->p, addpath_encode,
addpath_tx_id,
- pfx_buf, sizeof (pfx_buf)));
+ pfx_buf, sizeof (pfx_buf)),
+ label_buf);
}
/* Synchnorize attribute. */
@@ -824,7 +840,7 @@ subgroup_update_packet (struct update_subgroup *subgrp)
packet = stream_dup (s);
bgp_packet_set_size (packet);
if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
- zlog_debug ("u%" PRIu64 ":s%" PRIu64 " UPDATE len %zd numpfx %d",
+ zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE len %zd numpfx %d",
subgrp->update_group->id, subgrp->id,
(stream_get_endp(packet) - stream_get_getp(packet)), num_pfx);
pkt = bpacket_queue_add (SUBGRP_PKTQ (subgrp), packet, &vecarr);
@@ -917,11 +933,20 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
/* If first time, format the MP_UNREACH header */
if (first_time)
{
+ iana_afi_t pkt_afi;
+ safi_t pkt_safi;
+
+ pkt_afi = afi_int2iana (afi);
+ pkt_safi = safi_int2iana (safi);
+
attrlen_pos = stream_get_endp (s);
/* total attr length = 0 for now. reevaluate later */
stream_putw (s, 0);
mp_start = stream_get_endp (s);
mplen_pos = bgp_packet_mpunreach_start (s, afi, safi);
+ if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
+ zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send MP_UNREACH for afi/safi %d/%d",
+ subgrp->update_group->id, subgrp->id, pkt_afi, pkt_safi);
}
bgp_packet_mpunreach_prefix (s, &rn->p, afi, safi, prd, NULL,
@@ -968,7 +993,7 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
}
bgp_packet_set_size (s);
if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
- zlog_debug ("u%" PRIu64 ":s%" PRIu64 " UPDATE (withdraw) len %zd numpfx %d",
+ zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE (withdraw) len %zd numpfx %d",
subgrp->update_group->id, subgrp->id,
(stream_get_endp(s) - stream_get_getp(s)), num_pfx);
pkt = bpacket_queue_add (SUBGRP_PKTQ (subgrp), stream_dup (s), NULL);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index e94de682d..44389b99c 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -60,6 +60,73 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
static struct peer_group *
listen_range_exists (struct bgp *bgp, struct prefix *range, int exact);
+#if 0
+#define INSTALL_CMD_ON_AF_NODES(cmd) \
+ install_element(BGP_IPV4_NODE, cmd); \
+ install_element(BGP_IPV4M_NODE, cmd); \
+ install_element(BGP_IPV4L_NODE, cmd); \
+ install_element(BGP_IPV6_NODE, cmd); \
+ install_element(BGP_IPV6M_NODE, cmd); \
+ install_element(BGP_IPV6L_NODE, cmd); \
+ install_element(BGP_VPNV4_NODE, cmd);
+#endif
+static enum node_type
+bgp_node_type (afi_t afi, safi_t safi)
+{
+ switch (afi)
+ {
+ case AFI_IP:
+ switch (safi)
+ {
+ case SAFI_UNICAST:
+ return BGP_IPV4_NODE;
+ break;
+ case SAFI_MULTICAST:
+ return BGP_IPV4M_NODE;
+ break;
+ case SAFI_LABELED_UNICAST:
+ return BGP_IPV4L_NODE;
+ break;
+ case SAFI_MPLS_VPN:
+ return BGP_VPNV4_NODE;
+ break;
+ case SAFI_ENCAP:
+ return BGP_ENCAP_NODE;
+ break;
+ }
+ break;
+ case AFI_IP6:
+ switch (safi)
+ {
+ case SAFI_UNICAST:
+ return BGP_IPV6_NODE;
+ break;
+ case SAFI_MULTICAST:
+ return BGP_IPV6M_NODE;
+ break;
+ case SAFI_LABELED_UNICAST:
+ return BGP_IPV6L_NODE;
+ break;
+ case SAFI_MPLS_VPN:
+ return BGP_VPNV6_NODE;
+ break;
+ case SAFI_ENCAP:
+ return BGP_ENCAP_NODE;
+ break;
+ }
+ break;
+ case AFI_L2VPN:
+ return BGP_EVPN_NODE;
+ break;
+ case AFI_MAX:
+ // We should never be here but to clarify the switch statement..
+ return BGP_IPV4_NODE;
+ break;
+ }
+
+ // Impossible to happen
+ return BGP_IPV4_NODE;
+}
/* Utility function to get address family from current node. */
afi_t
@@ -70,6 +137,7 @@ bgp_node_afi (struct vty *vty)
{
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
+ case BGP_IPV6L_NODE:
case BGP_VPNV6_NODE:
case BGP_ENCAPV6_NODE:
afi = AFI_IP6;
@@ -107,6 +175,10 @@ bgp_node_safi (struct vty *vty)
case BGP_EVPN_NODE:
safi = SAFI_EVPN;
break;
+ case BGP_IPV4L_NODE:
+ case BGP_IPV6L_NODE:
+ safi = SAFI_LABELED_UNICAST;
+ break;
default:
safi = SAFI_UNICAST;
break;
@@ -160,7 +232,7 @@ argv_find_and_parse_afi(struct cmd_token **argv, int argc, int *index, afi_t *af
return ret;
}
-/* supports <unicast|multicast|vpn|encap> */
+/* supports <unicast|multicast|vpn|encap|labeled-unicast> */
safi_t
bgp_vty_safi_from_arg(const char *safi_str)
{
@@ -173,6 +245,8 @@ bgp_vty_safi_from_arg(const char *safi_str)
safi = SAFI_ENCAP;
else if (strncmp (safi_str, "v", 1) == 0)
safi = SAFI_MPLS_VPN;
+ else if (strncmp (safi_str, "l", 1) == 0)
+ safi = SAFI_LABELED_UNICAST;
return safi;
}
@@ -192,6 +266,12 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t
if (safi)
*safi = SAFI_MULTICAST;
}
+ else if (argv_find (argv, argc, "labeled-unicast", index))
+ {
+ ret = 1;
+ if (safi)
+ *safi = SAFI_LABELED_UNICAST;
+ }
else if (argv_find (argv, argc, "vpn", index))
{
ret = 1;
@@ -223,12 +303,12 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t
* that is being parsed.
*
* The show commands are generally of the form:
- * "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] ..."
+ * "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap|labeled-unicast>]] ..."
*
* Since we use argv_find if the show command in particular doesn't have:
* [ip]
* [<view|vrf> WORD]
- * [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]]
+ * [<ipv4|ipv6> [<unicast|multicast|vpn|encap|labeled-unicast>]]
* The command parsing should still be ok.
*
* vty -> The vty for the command so we can output some useful data in
@@ -5649,30 +5729,16 @@ DEFUN (no_neighbor_addpath_tx_bestpath_per_as,
DEFUN_NOSH (address_family_ipv4_safi,
address_family_ipv4_safi_cmd,
- "address-family ipv4 [<unicast|multicast|vpn|encap>]",
+ "address-family ipv4 [<unicast|multicast|vpn|encap|labeled-unicast>]",
"Enter Address Family command mode\n"
"Address Family\n"
BGP_SAFI_HELP_STR)
{
- int idx_safi = 2;
- if (argc == (idx_safi + 1))
+
+ if (argc == 3)
{
- switch (bgp_vty_safi_from_arg(argv[idx_safi]->arg))
- {
- case SAFI_MULTICAST:
- vty->node = BGP_IPV4M_NODE;
- break;
- case SAFI_ENCAP:
- vty->node = BGP_ENCAP_NODE;
- break;
- case SAFI_MPLS_VPN:
- vty->node = BGP_VPNV4_NODE;
- break;
- case SAFI_UNICAST:
- default:
- vty->node = BGP_IPV4_NODE;
- break;
- }
+ safi_t safi = bgp_vty_safi_from_arg(argv[2]->arg);
+ vty->node = bgp_node_type(AFI_IP, safi);
}
else
vty->node = BGP_IPV4_NODE;
@@ -5682,30 +5748,15 @@ DEFUN_NOSH (address_family_ipv4_safi,
DEFUN_NOSH (address_family_ipv6_safi,
address_family_ipv6_safi_cmd,
- "address-family ipv6 [<unicast|multicast|vpn|encap>]",
+ "address-family ipv6 [<unicast|multicast|vpn|encap|labeled-unicast>]",
"Enter Address Family command mode\n"
"Address Family\n"
BGP_SAFI_HELP_STR)
{
- int idx_safi = 2;
- if (argc == (idx_safi + 1))
+ if (argc == 3)
{
- switch (bgp_vty_safi_from_arg(argv[idx_safi]->arg))
- {
- case SAFI_MULTICAST:
- vty->node = BGP_IPV6M_NODE;
- break;
- case SAFI_ENCAP:
- vty->node = BGP_ENCAPV6_NODE;
- break;
- case SAFI_MPLS_VPN:
- vty->node = BGP_VPNV6_NODE;
- break;
- case SAFI_UNICAST:
- default:
- vty->node = BGP_IPV6_NODE;
- break;
- }
+ safi_t safi = bgp_vty_safi_from_arg(argv[2]->arg);
+ vty->node = bgp_node_type(AFI_IP6, safi);
}
else
vty->node = BGP_IPV6_NODE;
@@ -5778,9 +5829,11 @@ DEFUN_NOSH (exit_address_family,
{
if (vty->node == BGP_IPV4_NODE
|| vty->node == BGP_IPV4M_NODE
+ || vty->node == BGP_IPV4L_NODE
|| vty->node == BGP_VPNV4_NODE
|| vty->node == BGP_IPV6_NODE
|| vty->node == BGP_IPV6M_NODE
+ || vty->node == BGP_IPV6L_NODE
|| vty->node == BGP_VPNV6_NODE
|| vty->node == BGP_ENCAP_NODE
|| vty->node == BGP_ENCAPV6_NODE
@@ -6871,6 +6924,8 @@ afi_safi_print (afi_t afi, safi_t safi)
return "IPv4 Unicast";
else if (afi == AFI_IP && safi == SAFI_MULTICAST)
return "IPv4 Multicast";
+ else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
+ return "IPv4 labeled-unicast";
else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
return "IPv4 VPN";
else if (afi == AFI_IP && safi == SAFI_ENCAP)
@@ -6879,6 +6934,8 @@ afi_safi_print (afi_t afi, safi_t safi)
return "IPv6 Unicast";
else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
return "IPv6 Multicast";
+ else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
+ return "IPv6 labeled-unicast";
else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
return "IPv6 VPN";
else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
@@ -6896,6 +6953,8 @@ afi_safi_json (afi_t afi, safi_t safi)
return "IPv4Unicast";
else if (afi == AFI_IP && safi == SAFI_MULTICAST)
return "IPv4Multicast";
+ else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
+ return "IPv4LabeledUnicast";
else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
return "IPv4VPN";
else if (afi == AFI_IP && safi == SAFI_ENCAP)
@@ -6904,6 +6963,8 @@ afi_safi_json (afi_t afi, safi_t safi)
return "IPv6Unicast";
else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
return "IPv6Multicast";
+ else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
+ return "IPv6LabeledUnicast";
else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
return "IPv6VPN";
else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
@@ -10033,6 +10094,13 @@ static struct cmd_node bgp_ipv4_multicast_node =
1,
};
+static struct cmd_node bgp_ipv4_labeled_unicast_node =
+{
+ BGP_IPV4L_NODE,
+ "%s(config-router-af)# ",
+ 1,
+};
+
static struct cmd_node bgp_ipv6_unicast_node =
{
BGP_IPV6_NODE,
@@ -10047,6 +10115,13 @@ static struct cmd_node bgp_ipv6_multicast_node =
1,
};
+static struct cmd_node bgp_ipv6_labeled_unicast_node =
+{
+ BGP_IPV6L_NODE,
+ "%s(config-router-af)# ",
+ 1,
+};
+
static struct cmd_node bgp_vpnv4_node =
{
BGP_VPNV4_NODE,
@@ -10091,8 +10166,10 @@ bgp_vty_init (void)
install_node (&bgp_node, bgp_config_write);
install_node (&bgp_ipv4_unicast_node, NULL);
install_node (&bgp_ipv4_multicast_node, NULL);
+ install_node (&bgp_ipv4_labeled_unicast_node, NULL);
install_node (&bgp_ipv6_unicast_node, NULL);
install_node (&bgp_ipv6_multicast_node, NULL);
+ install_node (&bgp_ipv6_labeled_unicast_node, NULL);
install_node (&bgp_vpnv4_node, NULL);
install_node (&bgp_vpnv6_node, NULL);
install_node (&bgp_encap_node, NULL);
@@ -10103,8 +10180,10 @@ bgp_vty_init (void)
install_default (BGP_NODE);
install_default (BGP_IPV4_NODE);
install_default (BGP_IPV4M_NODE);
+ install_default (BGP_IPV4L_NODE);
install_default (BGP_IPV6_NODE);
install_default (BGP_IPV6M_NODE);
+ install_default (BGP_IPV6L_NODE);
install_default (BGP_VPNV4_NODE);
install_default (BGP_VPNV6_NODE);
install_default (BGP_ENCAP_NODE);
@@ -10180,15 +10259,27 @@ bgp_vty_init (void)
install_element (BGP_IPV6_NODE, &bgp_maxpaths_cmd);
install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_cmd);
install_element (BGP_NODE, &bgp_maxpaths_ibgp_cmd);
- install_element(BGP_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
+ install_element (BGP_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_cmd);
install_element (BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cmd);
- install_element(BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
+ install_element (BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_cmd);
install_element (BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cmd);
- install_element(BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
+ install_element (BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_ibgp_cmd);
+ install_element (BGP_IPV4L_NODE, &bgp_maxpaths_cmd);
+ install_element (BGP_IPV4L_NODE, &no_bgp_maxpaths_cmd);
+ install_element (BGP_IPV6L_NODE, &bgp_maxpaths_cmd);
+ install_element (BGP_IPV6L_NODE, &no_bgp_maxpaths_cmd);
+
+ install_element (BGP_IPV4L_NODE, &bgp_maxpaths_ibgp_cmd);
+ install_element (BGP_IPV4L_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
+ install_element (BGP_IPV4L_NODE, &no_bgp_maxpaths_ibgp_cmd);
+ install_element (BGP_IPV6L_NODE, &bgp_maxpaths_ibgp_cmd);
+ install_element (BGP_IPV6L_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
+ install_element (BGP_IPV6L_NODE, &no_bgp_maxpaths_ibgp_cmd);
+
/* "timers bgp" commands. */
install_element (BGP_NODE, &bgp_timers_cmd);
install_element (BGP_NODE, &no_bgp_timers_cmd);
@@ -10317,8 +10408,10 @@ bgp_vty_init (void)
install_element (BGP_NODE, &neighbor_activate_cmd);
install_element (BGP_IPV4_NODE, &neighbor_activate_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_activate_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_activate_cmd);
install_element (BGP_IPV6_NODE, &neighbor_activate_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_activate_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_activate_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_activate_cmd);
install_element (BGP_ENCAP_NODE, &neighbor_activate_cmd);
@@ -10329,8 +10422,10 @@ bgp_vty_init (void)
install_element (BGP_NODE, &no_neighbor_activate_cmd);
install_element (BGP_IPV4_NODE, &no_neighbor_activate_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_activate_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_activate_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_activate_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_activate_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_activate_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd);
install_element (BGP_VPNV6_NODE, &no_neighbor_activate_cmd);
install_element (BGP_ENCAP_NODE, &no_neighbor_activate_cmd);
@@ -10346,8 +10441,10 @@ bgp_vty_init (void)
install_element (BGP_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_IPV4_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_set_peer_group_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_set_peer_group_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_ENCAP_NODE, &neighbor_set_peer_group_cmd);
@@ -10357,8 +10454,10 @@ bgp_vty_init (void)
install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_IPV4_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_set_peer_group_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_set_peer_group_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_VPNV6_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_ENCAP_NODE, &no_neighbor_set_peer_group_cmd);
@@ -10369,12 +10468,16 @@ bgp_vty_init (void)
install_element (BGP_NODE, &no_neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV4_NODE, &neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV4_NODE, &no_neighbor_soft_reconfiguration_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_soft_reconfiguration_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV6_NODE, &neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_soft_reconfiguration_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_soft_reconfiguration_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_soft_reconfiguration_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_soft_reconfiguration_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_soft_reconfiguration_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_soft_reconfiguration_cmd);
@@ -10391,10 +10494,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_attr_unchanged_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_attr_unchanged_cmd);
install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_attr_unchanged_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_attr_unchanged_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged_cmd);
@@ -10420,10 +10527,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_nexthop_self_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_nexthop_self_cmd);
install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_nexthop_self_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_nexthop_self_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_nexthop_self_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_nexthop_self_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_nexthop_self_cmd);
@@ -10440,10 +10551,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_force_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_nexthop_self_force_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_nexthop_self_force_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_nexthop_self_force_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_nexthop_self_force_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_force_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_force_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_nexthop_self_force_cmd);
@@ -10456,10 +10571,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_as_override_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_as_override_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_as_override_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_as_override_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_as_override_cmd);
install_element (BGP_IPV6_NODE, &neighbor_as_override_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_as_override_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_as_override_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_as_override_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_as_override_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_as_override_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_as_override_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_as_override_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_as_override_cmd);
@@ -10490,6 +10609,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_all_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_all_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_replace_as_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_remove_private_as_cmd);
install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_all_cmd);
@@ -10506,6 +10633,14 @@ bgp_vty_init (void)
install_element (BGP_IPV6M_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_all_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_all_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_replace_as_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_all_cmd);
@@ -10540,6 +10675,10 @@ bgp_vty_init (void)
install_element (BGP_IPV4M_NODE, &neighbor_send_community_type_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_type_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_send_community_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_send_community_type_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_send_community_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_send_community_type_cmd);
install_element (BGP_IPV6_NODE, &neighbor_send_community_cmd);
install_element (BGP_IPV6_NODE, &neighbor_send_community_type_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_send_community_cmd);
@@ -10548,6 +10687,10 @@ bgp_vty_init (void)
install_element (BGP_IPV6M_NODE, &neighbor_send_community_type_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_send_community_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_send_community_type_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_send_community_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_send_community_type_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_send_community_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_send_community_type_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_send_community_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_send_community_type_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_cmd);
@@ -10572,10 +10715,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_route_reflector_client_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_route_reflector_client_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_route_reflector_client_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_route_reflector_client_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_route_reflector_client_cmd);
install_element (BGP_IPV6_NODE, &neighbor_route_reflector_client_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_route_reflector_client_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_route_reflector_client_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_route_reflector_client_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_route_reflector_client_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_route_reflector_client_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_route_reflector_client_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_route_reflector_client_cmd);
@@ -10592,10 +10739,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_route_server_client_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_route_server_client_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_route_server_client_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_route_server_client_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_route_server_client_cmd);
install_element (BGP_IPV6_NODE, &neighbor_route_server_client_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_route_server_client_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_route_server_client_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_route_server_client_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_route_server_client_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_route_server_client_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_route_server_client_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_route_server_client_cmd);
@@ -10612,10 +10763,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_addpath_tx_all_paths_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV6_NODE, &neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_addpath_tx_all_paths_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_addpath_tx_all_paths_cmd);
@@ -10628,10 +10783,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV6_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
@@ -10659,10 +10818,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_capability_orf_prefix_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_capability_orf_prefix_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV6_NODE, &neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_capability_orf_prefix_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_capability_orf_prefix_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_capability_orf_prefix_cmd);
/* "neighbor capability dynamic" commands.*/
install_element (BGP_NODE, &neighbor_capability_dynamic_cmd);
@@ -10699,12 +10862,18 @@ bgp_vty_init (void)
install_element (BGP_IPV4M_NODE, &neighbor_default_originate_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_default_originate_rmap_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_default_originate_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_default_originate_rmap_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_default_originate_cmd);
install_element (BGP_IPV6_NODE, &neighbor_default_originate_cmd);
install_element (BGP_IPV6_NODE, &neighbor_default_originate_rmap_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_default_originate_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_default_originate_rmap_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_default_originate_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_default_originate_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_default_originate_rmap_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_default_originate_cmd);
/* "neighbor port" commands. */
install_element (BGP_NODE, &neighbor_port_cmd);
@@ -10718,10 +10887,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_weight_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_weight_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_weight_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_weight_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_weight_cmd);
install_element (BGP_IPV6_NODE, &neighbor_weight_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_weight_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_weight_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_weight_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_weight_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_weight_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_weight_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_weight_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_weight_cmd);
@@ -10762,10 +10935,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_distribute_list_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_distribute_list_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_distribute_list_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_distribute_list_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_distribute_list_cmd);
install_element (BGP_IPV6_NODE, &neighbor_distribute_list_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_distribute_list_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_distribute_list_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_distribute_list_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_distribute_list_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_distribute_list_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_distribute_list_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_distribute_list_cmd);
@@ -10782,10 +10959,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_prefix_list_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_prefix_list_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_prefix_list_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_prefix_list_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_prefix_list_cmd);
install_element (BGP_IPV6_NODE, &neighbor_prefix_list_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_prefix_list_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_prefix_list_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_prefix_list_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_prefix_list_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_prefix_list_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_prefix_list_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_prefix_list_cmd);
@@ -10802,10 +10983,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_filter_list_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_filter_list_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_filter_list_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_filter_list_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_filter_list_cmd);
install_element (BGP_IPV6_NODE, &neighbor_filter_list_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_filter_list_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_filter_list_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_filter_list_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_filter_list_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_filter_list_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_filter_list_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_filter_list_cmd);
@@ -10822,10 +11007,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_route_map_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_route_map_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_route_map_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_route_map_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_route_map_cmd);
install_element (BGP_IPV6_NODE, &neighbor_route_map_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_route_map_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_route_map_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_route_map_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_route_map_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_route_map_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_route_map_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_route_map_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_route_map_cmd);
@@ -10842,10 +11031,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_unsuppress_map_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_unsuppress_map_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_unsuppress_map_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_IPV6_NODE, &neighbor_unsuppress_map_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_unsuppress_map_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_unsuppress_map_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_unsuppress_map_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_unsuppress_map_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd);
@@ -10877,6 +11070,13 @@ bgp_vty_init (void)
install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_restart_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_threshold_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_warning_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_threshold_warning_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_restart_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_threshold_restart_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_maximum_prefix_cmd);
install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_cmd);
install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_cmd);
install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_warning_cmd);
@@ -10891,6 +11091,13 @@ bgp_vty_init (void)
install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_restart_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_threshold_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_warning_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_threshold_warning_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_restart_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_threshold_restart_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_maximum_prefix_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_warning_cmd);
@@ -10929,10 +11136,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_allowas_in_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_allowas_in_cmd);
+ install_element (BGP_IPV4L_NODE, &neighbor_allowas_in_cmd);
+ install_element (BGP_IPV4L_NODE, &no_neighbor_allowas_in_cmd);
install_element (BGP_IPV6_NODE, &neighbor_allowas_in_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_allowas_in_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_allowas_in_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_allowas_in_cmd);
+ install_element (BGP_IPV6L_NODE, &neighbor_allowas_in_cmd);
+ install_element (BGP_IPV6L_NODE, &no_neighbor_allowas_in_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_allowas_in_cmd);
@@ -10958,8 +11169,10 @@ bgp_vty_init (void)
/* "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_IPV4L_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_IPV6L_NODE, &exit_address_family_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);
diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h
index 33d24d530..a0aabcbd2 100644
--- a/bgpd/bgp_vty.h
+++ b/bgpd/bgp_vty.h
@@ -28,11 +28,13 @@ struct bgp;
#define BGP_AFI_CMD_STR "<ipv4|ipv6>"
#define BGP_AFI_HELP_STR "Address Family\nAddress Family\n"
-#define BGP_SAFI_CMD_STR "<unicast|multicast|vpn|encap>"
+#define BGP_SAFI_CMD_STR "<unicast|multicast|vpn|encap|labeled-unicast>"
#define BGP_SAFI_HELP_STR \
"Address Family modifier\n" \
"Address Family modifier\n" \
"Address Family modifier\n" \
+ "Address Family modifier\n" \
+ "Address Family modifier\n" \
"Address Family modifier\n"
#define BGP_AFI_SAFI_CMD_STR BGP_AFI_CMD_STR" "BGP_SAFI_CMD_STR
#define BGP_AFI_SAFI_HELP_STR BGP_AFI_HELP_STR BGP_SAFI_HELP_STR
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 72bd081a7..d76eb951d 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -34,6 +34,7 @@ Boston, MA 02111-1307, USA. */
#include "lib/json.h"
#include "lib/bfd.h"
#include "filter.h"
+#include "mpls.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_route.h"
@@ -46,6 +47,7 @@ Boston, MA 02111-1307, USA. */
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_bfd.h"
+#include "bgpd/bgp_label.h"
#if ENABLE_BGP_VNC
# include "bgpd/rfapi/rfapi_backend.h"
# include "bgpd/rfapi/vnc_export_bgp.h"
@@ -57,6 +59,7 @@ struct zclient *zclient = NULL;
/* Growable buffer for nexthops sent to zebra */
struct stream *bgp_nexthop_buf = NULL;
struct stream *bgp_ifindices_buf = NULL;
+struct stream *bgp_label_buf = NULL;
/* These array buffers are used in making a copy of the attributes for
route-map apply. Arrays are being used here to minimize mallocs and
@@ -178,6 +181,14 @@ bgp_update_interface_nbrs (struct bgp *bgp, struct interface *ifp,
}
}
+static int
+bgp_read_fec_update (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ bgp_parse_fec_update();
+ return 0;
+}
+
static void
bgp_start_interface_nbrs (struct bgp *bgp, struct interface *ifp)
{
@@ -1204,8 +1215,8 @@ bgp_table_map_apply (struct route_map *map, struct prefix *p,
}
void
-bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
- afi_t afi, safi_t safi)
+bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info,
+ struct bgp *bgp, afi_t afi, safi_t safi)
{
u_int32_t flags;
u_char distance;
@@ -1216,6 +1227,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
struct bgp_info local_info;
struct bgp_info *info_cp = &local_info;
route_tag_t tag;
+ u_int32_t label;
/* Don't try to install if we're not connected to Zebra or Zebra doesn't
* know of this instance.
@@ -1271,7 +1283,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
(sizeof (struct in_addr *) * nhcount))
{
- newsize = (sizeof (struct in_addr *) * nhcount);
+ newsize = sizeof (struct in_addr *) * nhcount;
newsize = stream_resize (bgp_nexthop_buf, newsize);
if (newsize == oldsize)
{
@@ -1282,6 +1294,25 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
stream_reset (bgp_nexthop_buf);
nexthop = NULL;
+ /* For labeled unicast, each nexthop has a label too. Resize label
+ * buffer, if required.
+ */
+ if (safi == SAFI_LABELED_UNICAST)
+ {
+ if ((oldsize = stream_get_size (bgp_label_buf)) <
+ (sizeof (unsigned int) * nhcount))
+ {
+ newsize = (sizeof (unsigned int) * nhcount);
+ newsize = stream_resize (bgp_label_buf, newsize);
+ if (newsize == oldsize)
+ {
+ zlog_err ("can't resize label buffer");
+ return;
+ }
+ }
+ stream_reset (bgp_label_buf);
+ }
+
/* Metric is currently based on the best-path only. */
metric = info->attr->med;
@@ -1311,6 +1342,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
{
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
valid_nh_count++;
+ if (safi == SAFI_LABELED_UNICAST)
+ {
+ label = label_pton(info->extra->tag);
+ stream_put (bgp_label_buf, &label, sizeof (u_int32_t));
+ }
}
for (mpinfo = bgp_info_mpath_first (info); mpinfo;
@@ -1336,6 +1372,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
continue;
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
+ if (safi == SAFI_LABELED_UNICAST)
+ {
+ label = label_pton(mpinfo->extra->tag);
+ stream_put (bgp_label_buf, &label, sizeof (u_int32_t));
+ }
valid_nh_count++;
}
@@ -1344,8 +1385,10 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
api.type = ZEBRA_ROUTE_BGP;
api.instance = 0;
api.message = 0;
- api.safi = safi;
+ api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+ if (safi == SAFI_LABELED_UNICAST)
+ SET_FLAG (api.message, ZAPI_MESSAGE_LABEL);
/* Note that this currently only applies to Null0 routes for aggregates.
* ZEBRA_FLAG_BLACKHOLE signals zapi_ipv4_route to encode a special
@@ -1358,6 +1401,16 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
api.nexthop_num = valid_nh_count;
api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf);
+ if (safi == SAFI_LABELED_UNICAST)
+ {
+ api.label_num = valid_nh_count;
+ api.label = (unsigned int *)STREAM_DATA (bgp_label_buf);
+ }
+ else
+ {
+ api.label_num = 0;
+ api.label = NULL;
+ }
api.ifindex_num = 0;
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = metric;
@@ -1379,14 +1432,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
if (bgp_debug_zebra(p))
{
int i;
+ char label_buf[20];
zlog_debug("Tx IPv4 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI
" count %d", (valid_nh_count ? "add":"delete"),
bgp->vrf_id,
inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
p->prefixlen, api.metric, api.tag, api.nexthop_num);
for (i = 0; i < api.nexthop_num; i++)
- zlog_debug(" IPv4 [nexthop %d] %s", i+1,
- inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1])));
+ {
+ label_buf[0] = '\0';
+ if (safi == SAFI_LABELED_UNICAST)
+ sprintf(label_buf, "label %u", api.label[i]);
+ zlog_debug(" nhop [%d]: %s %s",
+ i+1,
+ inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1])),
+ label_buf);
+ }
}
zapi_ipv4_route (valid_nh_count ? ZEBRA_IPV4_ROUTE_ADD: ZEBRA_IPV4_ROUTE_DELETE,
@@ -1431,6 +1492,25 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
}
stream_reset (bgp_ifindices_buf);
+ /* For labeled unicast, each nexthop has a label too. Resize label
+ * buffer, if required.
+ */
+ if (safi == SAFI_LABELED_UNICAST)
+ {
+ if ((oldsize = stream_get_size (bgp_label_buf)) <
+ (sizeof (unsigned int) * nhcount))
+ {
+ newsize = (sizeof (unsigned int) * nhcount);
+ newsize = stream_resize (bgp_label_buf, newsize);
+ if (newsize == oldsize)
+ {
+ zlog_err ("can't resize label buffer");
+ return;
+ }
+ }
+ stream_reset (bgp_label_buf);
+ }
+
ifindex = 0;
nexthop = NULL;
@@ -1476,6 +1556,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
}
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
+ if (safi == SAFI_LABELED_UNICAST)
+ {
+ label = label_pton(info->extra->tag);
+ stream_put (bgp_label_buf, &label, sizeof (u_int32_t));
+ }
valid_nh_count++;
}
@@ -1518,6 +1603,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
+ if (safi == SAFI_LABELED_UNICAST)
+ {
+ label = label_pton(mpinfo->extra->tag);
+ stream_put (bgp_label_buf, &label, sizeof (u_int32_t));
+ }
valid_nh_count++;
}
@@ -1527,8 +1617,10 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
api.type = ZEBRA_ROUTE_BGP;
api.instance = 0;
api.message = 0;
- api.safi = safi;
+ api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+ if (safi == SAFI_LABELED_UNICAST)
+ SET_FLAG (api.message, ZAPI_MESSAGE_LABEL);
/* Note that this currently only applies to Null0 routes for aggregates.
* ZEBRA_FLAG_BLACKHOLE signals zapi_ipv6_route to encode a special
@@ -1544,6 +1636,16 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
api.ifindex_num = valid_nh_count;
api.ifindex = (ifindex_t *)STREAM_DATA (bgp_ifindices_buf);
+ if (safi == SAFI_LABELED_UNICAST)
+ {
+ api.label_num = valid_nh_count;
+ api.label = (unsigned int *)STREAM_DATA (bgp_label_buf);
+ }
+ else
+ {
+ api.label_num = 0;
+ api.label = NULL;
+ }
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = metric;
api.tag = 0;
@@ -1566,13 +1668,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
if (bgp_debug_zebra(p))
{
int i;
+ char label_buf[20];
zlog_debug("Tx IPv4 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI,
valid_nh_count ? "add" : "delete", bgp->vrf_id,
inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
p->prefixlen, api.metric, api.tag);
for (i = 0; i < api.nexthop_num; i++)
- zlog_debug(" IPv6 [nexthop %d] %s", i+1,
- inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])));
+ {
+ label_buf[0] = '\0';
+ if (safi == SAFI_LABELED_UNICAST)
+ sprintf(label_buf, "label %u", api.label[i]);
+ zlog_debug(" nhop [%d]: %s if %s %s",
+ i+1,
+ inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])),
+ ifindex2ifname (api.ifindex[i], bgp->vrf_id),
+ label_buf);
+ }
}
if (valid_nh_count)
@@ -1588,13 +1699,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
if (bgp_debug_zebra(p))
{
int i;
+ char label_buf[20];
zlog_debug("Tx IPv6 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI,
valid_nh_count ? "add" : "delete", bgp->vrf_id,
inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
p->prefixlen, api.metric, api.tag);
for (i = 0; i < api.nexthop_num; i++)
- zlog_debug(" IPv6 [nexthop %d] %s", i+1,
- inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])));
+ {
+ label_buf[0] = '\0';
+ if (safi == SAFI_LABELED_UNICAST)
+ sprintf(label_buf, "label %u", api.label[i]);
+ zlog_debug(" nhop [%d]: %s if %s %s",
+ i+1,
+ inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])),
+ ifindex2ifname (api.ifindex[i], bgp->vrf_id),
+ label_buf);
+ }
}
zapi_ipv6_route (valid_nh_count ?
@@ -1626,7 +1746,7 @@ bgp_zebra_announce_table (struct bgp *bgp, afi_t afi, safi_t safi)
if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
&& ri->type == ZEBRA_ROUTE_BGP
&& ri->sub_type == BGP_ROUTE_NORMAL)
- bgp_zebra_announce (&rn->p, ri, bgp, afi, safi);
+ bgp_zebra_announce (rn, &rn->p, ri, bgp, afi, safi);
}
void
@@ -1673,10 +1793,14 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
api.type = ZEBRA_ROUTE_BGP;
api.instance = 0;
api.message = 0;
- api.safi = safi;
+ api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+ if (safi == SAFI_LABELED_UNICAST)
+ SET_FLAG (api.message, ZAPI_MESSAGE_LABEL);
api.nexthop_num = 0;
api.nexthop = NULL;
+ api.label_num = 0;
+ api.label = NULL;
api.ifindex_num = 0;
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
@@ -1712,11 +1836,14 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
api.type = ZEBRA_ROUTE_BGP;
api.instance = 0;
api.message = 0;
- api.safi = safi;
+ api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+ if (safi == SAFI_LABELED_UNICAST)
+ SET_FLAG (api.message, ZAPI_MESSAGE_LABEL);
api.nexthop_num = 0;
api.nexthop = NULL;
api.ifindex_num = 0;
+ api.label_num = 0;
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
api.tag = 0;
@@ -2141,9 +2268,11 @@ bgp_zebra_init (struct thread_master *master)
zclient->redistribute_route_ipv6_del = zebra_read_ipv6;
zclient->nexthop_update = bgp_read_nexthop_update;
zclient->import_check_update = bgp_read_import_check_update;
+ zclient->fec_update = bgp_read_fec_update;
bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE);
bgp_ifindices_buf = stream_new(BGP_IFINDICES_BUF_SIZE);
+ bgp_label_buf = stream_new(BGP_LABEL_BUF_SIZE);
}
void
diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h
index d22a00e8f..bc4e36352 100644
--- a/bgpd/bgp_zebra.h
+++ b/bgpd/bgp_zebra.h
@@ -23,9 +23,11 @@ Boston, MA 02111-1307, USA. */
#define BGP_NEXTHOP_BUF_SIZE (8 * sizeof (struct in_addr *))
#define BGP_IFINDICES_BUF_SIZE (8 * sizeof (unsigned int))
+#define BGP_LABEL_BUF_SIZE (8 * sizeof (unsigned int))
extern struct stream *bgp_nexthop_buf;
extern struct stream *bgp_ifindices_buf;
+extern struct stream *bgp_label_buf;
extern void bgp_zebra_init (struct thread_master *master);
extern void bgp_zebra_destroy (void);
@@ -34,8 +36,8 @@ extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t,
safi_t, int *);
extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t,
int *);
-extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *,
- afi_t, safi_t);
+extern void bgp_zebra_announce (struct bgp_node *, struct prefix *,
+ struct bgp_info *, struct bgp *, afi_t, safi_t);
extern void bgp_zebra_announce_table (struct bgp *, afi_t, safi_t);
extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, safi_t);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 3f81c1c50..1c73fb940 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1636,6 +1636,8 @@ peer_as_change (struct peer *peer, as_t as, int as_specified)
PEER_FLAG_REFLECTOR_CLIENT);
UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST],
PEER_FLAG_REFLECTOR_CLIENT);
+ UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_LABELED_UNICAST],
+ PEER_FLAG_REFLECTOR_CLIENT);
UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MPLS_VPN],
PEER_FLAG_REFLECTOR_CLIENT);
UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_ENCAP],
@@ -1644,6 +1646,8 @@ peer_as_change (struct peer *peer, as_t as, int as_specified)
PEER_FLAG_REFLECTOR_CLIENT);
UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST],
PEER_FLAG_REFLECTOR_CLIENT);
+ UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_LABELED_UNICAST],
+ PEER_FLAG_REFLECTOR_CLIENT);
UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MPLS_VPN],
PEER_FLAG_REFLECTOR_CLIENT);
UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_ENCAP],
@@ -3608,10 +3612,12 @@ peer_active (struct peer *peer)
return 0;
if (peer->afc[AFI_IP][SAFI_UNICAST]
|| peer->afc[AFI_IP][SAFI_MULTICAST]
+ || peer->afc[AFI_IP][SAFI_LABELED_UNICAST]
|| peer->afc[AFI_IP][SAFI_MPLS_VPN]
|| peer->afc[AFI_IP][SAFI_ENCAP]
|| peer->afc[AFI_IP6][SAFI_UNICAST]
|| peer->afc[AFI_IP6][SAFI_MULTICAST]
+ || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST]
|| peer->afc[AFI_IP6][SAFI_MPLS_VPN]
|| peer->afc[AFI_IP6][SAFI_ENCAP])
return 1;
@@ -3624,10 +3630,12 @@ peer_active_nego (struct peer *peer)
{
if (peer->afc_nego[AFI_IP][SAFI_UNICAST]
|| peer->afc_nego[AFI_IP][SAFI_MULTICAST]
+ || peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST]
|| peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
|| peer->afc_nego[AFI_IP][SAFI_ENCAP]
|| peer->afc_nego[AFI_IP6][SAFI_UNICAST]
|| peer->afc_nego[AFI_IP6][SAFI_MULTICAST]
+ || peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST]
|| peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]
|| peer->afc_nego[AFI_IP6][SAFI_ENCAP])
return 1;
@@ -7262,6 +7270,8 @@ bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi,
{
if (safi == SAFI_UNICAST)
vty_out (vty, "ipv4 unicast");
+ else if (safi == SAFI_LABELED_UNICAST)
+ vty_out (vty, "ipv4 labeled-unicast");
else if (safi == SAFI_MULTICAST)
vty_out (vty, "ipv4 multicast");
else if (safi == SAFI_MPLS_VPN)
@@ -7273,6 +7283,8 @@ bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi,
{
if (safi == SAFI_UNICAST)
vty_out (vty, "ipv6 unicast");
+ else if (safi == SAFI_LABELED_UNICAST)
+ vty_out (vty, "ipv6 labeled-unicast");
else if (safi == SAFI_MULTICAST)
vty_out (vty, "ipv6 multicast");
else if (safi == SAFI_MPLS_VPN)
@@ -7579,6 +7591,9 @@ bgp_config_write (struct vty *vty)
/* IPv4 multicast configuration. */
write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MULTICAST);
+ /* IPv4 labeled-unicast configuration. */
+ write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_LABELED_UNICAST);
+
/* IPv4 VPN configuration. */
write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MPLS_VPN);
@@ -7591,6 +7606,9 @@ bgp_config_write (struct vty *vty)
/* IPv6 multicast configuration. */
write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MULTICAST);
+ /* IPv6 labeled-unicast configuration. */
+ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_LABELED_UNICAST);
+
/* IPv6 VPN configuration. */
write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MPLS_VPN);
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index a72974bc1..1b97a2503 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -76,6 +76,8 @@ enum bgp_af_index
BGP_AF_IPV4_ENCAP,
BGP_AF_IPV6_ENCAP,
BGP_AF_L2VPN_EVPN,
+ BGP_AF_IPV4_LBL_UNICAST,
+ BGP_AF_IPV6_LBL_UNICAST,
BGP_AF_MAX
};
@@ -971,6 +973,7 @@ struct bgp_nlri
#define BGP_ATTR_AS_PATHLIMIT 21
#define BGP_ATTR_ENCAP 23
#define BGP_ATTR_LARGE_COMMUNITIES 32
+#define BGP_ATTR_LABEL_INDEX 40
#if ENABLE_BGP_VNC
#define BGP_ATTR_VNC 255
#endif
@@ -1394,6 +1397,9 @@ afindex (afi_t afi, safi_t safi)
case SAFI_MULTICAST:
return BGP_AF_IPV4_MULTICAST;
break;
+ case SAFI_LABELED_UNICAST:
+ return BGP_AF_IPV4_LBL_UNICAST;
+ break;
case SAFI_MPLS_VPN:
return BGP_AF_IPV4_VPN;
break;
@@ -1414,7 +1420,10 @@ afindex (afi_t afi, safi_t safi)
case SAFI_MULTICAST:
return BGP_AF_IPV6_MULTICAST;
break;
- case SAFI_MPLS_VPN:
+ case SAFI_LABELED_UNICAST:
+ return BGP_AF_IPV6_LBL_UNICAST;
+ break;
+ case SAFI_MPLS_VPN:
return BGP_AF_IPV6_VPN;
break;
case SAFI_ENCAP:
@@ -1456,6 +1465,7 @@ peer_afi_active_nego (const struct peer *peer, afi_t afi)
{
if (peer->afc_nego[afi][SAFI_UNICAST]
|| peer->afc_nego[afi][SAFI_MULTICAST]
+ || peer->afc_nego[afi][SAFI_LABELED_UNICAST]
|| peer->afc_nego[afi][SAFI_MPLS_VPN]
|| peer->afc_nego[afi][SAFI_ENCAP])
return 1;
@@ -1470,10 +1480,12 @@ peer_group_af_configured (struct peer_group *group)
if (peer->afc[AFI_IP][SAFI_UNICAST]
|| peer->afc[AFI_IP][SAFI_MULTICAST]
+ || peer->afc[AFI_IP][SAFI_LABELED_UNICAST]
|| peer->afc[AFI_IP][SAFI_MPLS_VPN]
|| peer->afc[AFI_IP][SAFI_ENCAP]
|| peer->afc[AFI_IP6][SAFI_UNICAST]
|| peer->afc[AFI_IP6][SAFI_MULTICAST]
+ || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST]
|| peer->afc[AFI_IP6][SAFI_MPLS_VPN]
|| peer->afc[AFI_IP6][SAFI_ENCAP])
return 1;
diff --git a/configure.ac b/configure.ac
index 4f0dcdf85..9b8b4e109 100755
--- a/configure.ac
+++ b/configure.ac
@@ -369,11 +369,11 @@ dnl ----------
AC_MSG_CHECKING(whether this OS has MPLS stack)
case "$host" in
*-linux*)
- MPLS_METHOD="zebra_mpls_netlink.o"
+ MPLS_METHOD="zebra_mpls_netlink.o zebra_mpls.o"
AC_MSG_RESULT(Linux MPLS)
;;
*-openbsd*)
- MPLS_METHOD="zebra_mpls_openbsd.o"
+ MPLS_METHOD="zebra_mpls_openbsd.o zebra_mpls.o"
AC_MSG_RESULT(OpenBSD MPLS)
;;
*)
diff --git a/debian/frr.dirs b/debian/frr.dirs
index 58290080d..56699b2da 100644
--- a/debian/frr.dirs
+++ b/debian/frr.dirs
@@ -1,5 +1,6 @@
etc/logrotate.d/
etc/frr/
+etc/iproute2/rt_protos.d/
usr/share/doc/frr/
usr/share/doc/frr/examples/
usr/share/lintian/overrides/
diff --git a/debian/frr.install b/debian/frr.install
index 45b3b973b..e81ebbc5b 100644
--- a/debian/frr.install
+++ b/debian/frr.install
@@ -18,5 +18,6 @@ usr/share/man/man8/isisd.8
usr/share/man/man8/watchfrr.8
usr/share/snmp/mibs/
cumulus/etc/* etc/
+tools/etc/* etc/
tools/*.service lib/systemd/system
debian/frr.conf usr/lib/tmpfiles.d
diff --git a/doc/Building_FRR_on_Ubuntu1604.md b/doc/Building_FRR_on_Ubuntu1604.md
index 70a8159cc..327b7d68a 100644
--- a/doc/Building_FRR_on_Ubuntu1604.md
+++ b/doc/Building_FRR_on_Ubuntu1604.md
@@ -38,6 +38,7 @@ an example.)
cd frr
./bootstrap.sh
./configure \
+ --prefix=/usr \
--enable-exampledir=/usr/share/doc/frr/examples/ \
--localstatedir=/var/run/frr \
--sbindir=/usr/lib/frr \
@@ -110,3 +111,38 @@ Add the following lines to `/etc/modules-load.d/modules.conf`:
mpls-iptunnel
**Reboot** or use `sysctl -p` to apply the same config to the running system
+
+
+### Install the systemd service
+
+ sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
+ sudo install -m 644 cumulus/etc/default/frr /etc/default/frr
+ sudo install -m 644 cumulus/etc/frr/daemons /etc/frr/daemons
+ sudo install -m 644 cumulus/etc/frr/debian.conf /etc/frr/debian.conf
+ sudo install -m 644 cumulus/etc/frr/Frr.conf /etc/frr/Frr.conf
+ sudo install -m 644 -o frr -g frr cumulus/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+
+### Enable daemons
+
+Edit `/etc/frr/daemons` and change the value from "no" to "yes" for those daemons you want to start by systemd.
+For example.
+
+ zebra=yes
+ bgpd=yes
+ ospfd=yes
+ ospf6d=yes
+ ripd=yes
+ ripngd=yes
+ isisd=yes
+
+### Enable the systemd serivce
+Edit `/etc/systemd/system/frr.service` and remove the line **OnFailure=heartbeat-failed@%n.service**
+For example.
+
+ [Unit]
+ Description=Cumulus Linux FRR
+ After=syslog.target networking.service
+    
+### Start the systemd service
+- systemctl start frr
+- use `systemctl status frr` to check its status.
diff --git a/isisd/Makefile.am b/isisd/Makefile.am
index c97385f87..2973820ee 100644
--- a/isisd/Makefile.am
+++ b/isisd/Makefile.am
@@ -16,7 +16,7 @@ libisis_a_SOURCES = \
isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \
isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \
isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c \
- isis_vty.c
+ isis_vty.c isis_mt.c
noinst_HEADERS = \
@@ -25,7 +25,7 @@ noinst_HEADERS = \
isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \
isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \
iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \
- isis_route.h isis_routemap.h isis_te.h
+ isis_route.h isis_routemap.h isis_te.h isis_mt.h
isisd_SOURCES = \
isis_main.c $(libisis_a_SOURCES) \
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index f55092487..fea99ec90 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -47,6 +47,7 @@
#include "isisd/isis_lsp.h"
#include "isisd/isis_spf.h"
#include "isisd/isis_events.h"
+#include "isisd/isis_mt.h"
extern struct isis *isis;
@@ -148,6 +149,8 @@ isis_delete_adj (void *arg)
if (adj->ipv6_addrs)
list_delete (adj->ipv6_addrs);
+ adj_mt_finish(adj);
+
XFREE (MTYPE_ISIS_ADJACENCY, adj);
return;
}
@@ -521,3 +524,20 @@ isis_adj_build_up_list (struct list *adjdb, struct list *list)
return;
}
+
+int
+isis_adj_usage2levels(enum isis_adj_usage usage)
+{
+ switch (usage)
+ {
+ case ISIS_ADJ_LEVEL1:
+ return IS_LEVEL_1;
+ case ISIS_ADJ_LEVEL2:
+ return IS_LEVEL_2;
+ case ISIS_ADJ_LEVEL1AND2:
+ return IS_LEVEL_1 | IS_LEVEL_2;
+ default:
+ break;
+ }
+ return 0;
+}
diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h
index 8539b03d6..4f89e3096 100644
--- a/isisd/isis_adjacency.h
+++ b/isisd/isis_adjacency.h
@@ -97,6 +97,8 @@ struct isis_adjacency
int flaps; /* number of adjacency flaps */
struct thread *t_expire; /* expire after hold_time */
struct isis_circuit *circuit; /* back pointer */
+ uint16_t *mt_set; /* Topologies this adjacency is valid for */
+ unsigned int mt_count; /* Number of entries in mt_set */
};
struct isis_adjacency *isis_adj_lookup (const u_char * sysid, struct list *adjdb);
@@ -112,5 +114,6 @@ int isis_adj_expire (struct thread *thread);
void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail);
void isis_adj_build_neigh_list (struct list *adjdb, struct list *list);
void isis_adj_build_up_list (struct list *adjdb, struct list *list);
+int isis_adj_usage2levels(enum isis_adj_usage usage);
#endif /* ISIS_ADJACENCY_H */
diff --git a/isisd/isis_bpf.c b/isisd/isis_bpf.c
index 3a5eaf558..0a1610b6f 100644
--- a/isisd/isis_bpf.c
+++ b/isisd/isis_bpf.c
@@ -212,16 +212,11 @@ isis_sock_init (struct isis_circuit *circuit)
goto end;
}
- if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ if (if_is_broadcast(circuit->interface))
{
circuit->tx = isis_send_pdu_bcast;
circuit->rx = isis_recv_pdu_bcast;
}
- else if (circuit->circ_type == CIRCUIT_T_P2P)
- {
- circuit->tx = isis_send_pdu_p2p;
- circuit->rx = isis_recv_pdu_p2p;
- }
else
{
zlog_warn ("isis_sock_init(): unknown circuit type");
@@ -284,23 +279,6 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
}
int
-isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
-{
- int bytesread;
-
- bytesread = stream_read (circuit->rcv_stream, circuit->fd,
- circuit->interface->mtu);
-
- if (bytesread < 0)
- {
- zlog_warn ("isis_recv_pdu_p2p(): read () failed: %s", safe_strerror (errno));
- return ISIS_WARNING;
- }
-
- return ISIS_OK;
-}
-
-int
isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
{
struct ether_header *eth;
@@ -327,7 +305,8 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
else
memcpy (eth->ether_dhost, ALL_L2_ISS, ETHER_ADDR_LEN);
memcpy (eth->ether_shost, circuit->u.bc.snpa, ETHER_ADDR_LEN);
- eth->ether_type = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
+ size_t frame_size = stream_get_endp(circuit->snd_stream) + LLC_LEN;
+ eth->ether_type = htons(isis_ethertype(frame_size));
/*
* Then the LLC
@@ -354,10 +333,4 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
return ISIS_OK;
}
-int
-isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
-{
- return ISIS_OK;
-}
-
#endif /* ISIS_METHOD == ISIS_METHOD_BPF */
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 6207ae189..6caf8200e 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -60,6 +60,7 @@
#include "isisd/isis_csm.h"
#include "isisd/isis_events.h"
#include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
DEFINE_QOBJ_TYPE(isis_circuit)
@@ -102,6 +103,8 @@ isis_circuit_new ()
circuit->mtc = mpls_te_circuit_new();
+ circuit_mt_init(circuit);
+
QOBJ_REG (circuit, isis_circuit);
return circuit;
@@ -117,6 +120,8 @@ isis_circuit_del (struct isis_circuit *circuit)
isis_circuit_if_unbind (circuit, circuit->interface);
+ circuit_mt_finish(circuit);
+
/* and lastly the circuit itself */
XFREE (MTYPE_ISIS_CIRCUIT, circuit);
@@ -1215,6 +1220,7 @@ isis_interface_config_write (struct vty *vty)
VTY_NEWLINE);
write++;
}
+ write += circuit_write_mt_settings(circuit, vty);
}
vty_out (vty, "!%s", VTY_NEWLINE);
}
@@ -1383,6 +1389,22 @@ isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type)
}
int
+isis_circuit_mt_enabled_set (struct isis_circuit *circuit, uint16_t mtid,
+ bool enabled)
+{
+ struct isis_circuit_mt_setting *setting;
+
+ setting = circuit_get_mt_setting(circuit, mtid);
+ if (setting->enabled != enabled)
+ {
+ setting->enabled = enabled;
+ lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
+ }
+
+ return CMD_SUCCESS;
+}
+
+int
isis_if_new_hook (struct interface *ifp)
{
return 0;
diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h
index bb0dc0f98..16dfa6304 100644
--- a/isisd/isis_circuit.h
+++ b/isisd/isis_circuit.h
@@ -123,6 +123,7 @@ struct isis_circuit
struct mpls_te_circuit *mtc; /* Support for MPLS-TE parameters - see isis_te.[c,h] */
int ip_router; /* Route IP ? */
int is_passive; /* Is Passive ? */
+ struct list *mt_settings; /* IS-IS MT Settings */
struct list *ip_addrs; /* our IP addresses */
int ipv6_router; /* Route IPv6 ? */
struct list *ipv6_link; /* our link local IPv6 addresses */
@@ -187,4 +188,6 @@ int isis_circuit_passwd_unset (struct isis_circuit *circuit);
int isis_circuit_passwd_cleartext_set (struct isis_circuit *circuit, const char *passwd);
int isis_circuit_passwd_hmac_md5_set (struct isis_circuit *circuit, const char *passwd);
+int isis_circuit_mt_enabled_set (struct isis_circuit *circuit, uint16_t mtid, bool enabled);
+
#endif /* _ZEBRA_ISIS_CIRCUIT_H */
diff --git a/isisd/isis_constants.h b/isisd/isis_constants.h
index 17616d671..ec0f6fb62 100644
--- a/isisd/isis_constants.h
+++ b/isisd/isis_constants.h
@@ -171,4 +171,14 @@
#define ETH_ALEN 6
#endif
+#define MAX_LLC_LEN 0x5ff
+#define ETHERTYPE_EXT_LLC 0x8870
+
+static inline uint16_t isis_ethertype(size_t len)
+{
+ if (len > MAX_LLC_LEN)
+ return ETHERTYPE_EXT_LLC;
+ return len;
+}
+
#endif /* ISIS_CONSTANTS_H */
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index f633a8fb7..955a73ef6 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -53,6 +53,7 @@
#include "isisd/isis_adjacency.h"
#include "isisd/isis_spf.h"
#include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
/* staticly assigned vars for printing purposes */
char lsp_bits_string[200]; /* FIXME: enough ? */
@@ -501,6 +502,7 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
expected |= TLVFLAG_TE_IPV4_REACHABILITY;
expected |= TLVFLAG_TE_ROUTER_ID;
}
+ expected |= TLVFLAG_MT_ROUTER_INFORMATION;
expected |= TLVFLAG_IPV4_ADDR;
expected |= TLVFLAG_IPV4_INT_REACHABILITY;
expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
@@ -826,6 +828,107 @@ lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost)
lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
}
+static void
+lsp_print_mt_reach(struct list *list, struct vty *vty,
+ char dynhost, uint16_t mtid)
+{
+ struct listnode *node;
+ struct te_is_neigh *neigh;
+
+ for (ALL_LIST_ELEMENTS_RO (list, node, neigh))
+ {
+ u_char lspid[255];
+
+ lspid_print(neigh->neigh_id, lspid, dynhost, 0);
+ if (mtid == ISIS_MT_IPV4_UNICAST)
+ {
+ vty_out(vty, " Metric : %-8d IS-Extended : %s%s",
+ GET_TE_METRIC(neigh), lspid, VTY_NEWLINE);
+ }
+ else
+ {
+ vty_out(vty, " Metric : %-8d MT-Reach : %s %s%s",
+ GET_TE_METRIC(neigh), lspid,
+ isis_mtid2str(mtid), VTY_NEWLINE);
+ }
+ if (IS_MPLS_TE(isisMplsTE))
+ mpls_te_print_detail(vty, neigh);
+ }
+}
+
+static void
+lsp_print_mt_ipv6_reach(struct list *list, struct vty *vty, uint16_t mtid)
+{
+ struct listnode *node;
+ struct ipv6_reachability *ipv6_reach;
+ struct in6_addr in6;
+ u_char buff[BUFSIZ];
+
+ for (ALL_LIST_ELEMENTS_RO (list, node, ipv6_reach))
+ {
+ memset (&in6, 0, sizeof (in6));
+ memcpy (in6.s6_addr, ipv6_reach->prefix,
+ PSIZE (ipv6_reach->prefix_len));
+ inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
+ if (mtid == ISIS_MT_IPV4_UNICAST)
+ {
+ if ((ipv6_reach->control_info &
+ CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
+ vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s",
+ ntohl (ipv6_reach->metric),
+ buff, ipv6_reach->prefix_len, VTY_NEWLINE);
+ else
+ vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s",
+ ntohl (ipv6_reach->metric),
+ buff, ipv6_reach->prefix_len, VTY_NEWLINE);
+ }
+ else
+ {
+ if ((ipv6_reach->control_info &
+ CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
+ vty_out (vty, " Metric : %-8d IPv6-MT-Int : %s/%d %s%s",
+ ntohl (ipv6_reach->metric),
+ buff, ipv6_reach->prefix_len,
+ isis_mtid2str(mtid), VTY_NEWLINE);
+ else
+ vty_out (vty, " Metric : %-8d IPv6-MT-Ext : %s/%d %s%s",
+ ntohl (ipv6_reach->metric),
+ buff, ipv6_reach->prefix_len,
+ isis_mtid2str(mtid), VTY_NEWLINE);
+ }
+ }
+}
+
+static void
+lsp_print_mt_ipv4_reach(struct list *list, struct vty *vty, uint16_t mtid)
+{
+ struct listnode *node;
+ struct te_ipv4_reachability *te_ipv4_reach;
+
+ for (ALL_LIST_ELEMENTS_RO (list, node, te_ipv4_reach))
+ {
+ if (mtid == ISIS_MT_IPV4_UNICAST)
+ {
+ /* FIXME: There should be better way to output this stuff. */
+ vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s",
+ ntohl (te_ipv4_reach->te_metric),
+ inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
+ te_ipv4_reach->control)),
+ te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
+ }
+ else
+ {
+ /* FIXME: There should be better way to output this stuff. */
+ vty_out (vty, " Metric : %-8d IPv4-MT : %s/%d %s%s",
+ ntohl (te_ipv4_reach->te_metric),
+ inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
+ te_ipv4_reach->control)),
+ te_ipv4_reach->control & 0x3F,
+ isis_mtid2str(mtid), VTY_NEWLINE);
+ }
+ }
+}
+
void
lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
{
@@ -833,13 +936,12 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
int i;
struct listnode *lnode;
struct is_neigh *is_neigh;
- struct te_is_neigh *te_is_neigh;
struct ipv4_reachability *ipv4_reach;
struct in_addr *ipv4_addr;
- struct te_ipv4_reachability *te_ipv4_reach;
- struct ipv6_reachability *ipv6_reach;
- struct in6_addr in6;
- u_char buff[BUFSIZ];
+ struct mt_router_info *mt_router_info;
+ struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
+ struct tlv_mt_neighbors *mt_is_neigh;
+ struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
u_char LSPid[255];
u_char hostname[255];
u_char ipv4_reach_prefix[20];
@@ -877,6 +979,14 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
}
}
+ for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_router_info, lnode, mt_router_info))
+ {
+ vty_out (vty, " MT : %s%s%s",
+ isis_mtid2str(mt_router_info->mtid),
+ mt_router_info->overload ? " (overload)" : "",
+ VTY_NEWLINE);
+ }
+
/* for the hostname tlv */
if (lsp->tlv_data.hostname)
{
@@ -946,49 +1056,31 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
ipv4_reach_mask, VTY_NEWLINE);
}
-
+
/* IPv6 tlv */
- if (lsp->tlv_data.ipv6_reachs)
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, lnode, ipv6_reach))
- {
- memset (&in6, 0, sizeof (in6));
- memcpy (in6.s6_addr, ipv6_reach->prefix,
- PSIZE (ipv6_reach->prefix_len));
- inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
- if ((ipv6_reach->control_info &
- CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
- vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s",
- ntohl (ipv6_reach->metric),
- buff, ipv6_reach->prefix_len, VTY_NEWLINE);
- else
- vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s",
- ntohl (ipv6_reach->metric),
- buff, ipv6_reach->prefix_len, VTY_NEWLINE);
- }
+ lsp_print_mt_ipv6_reach(lsp->tlv_data.ipv6_reachs, vty,
+ ISIS_MT_IPV4_UNICAST);
+
+ /* MT IPv6 reachability tlv */
+ for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.mt_ipv6_reachs, lnode, mt_ipv6_reachs))
+ lsp_print_mt_ipv6_reach(mt_ipv6_reachs->list, vty, mt_ipv6_reachs->mtid);
/* TE IS neighbor tlv */
- if (lsp->tlv_data.te_is_neighs)
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))
- {
- lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
- vty_out (vty, " Metric : %-8d IS-Extended : %s%s",
- GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE);
- if (IS_MPLS_TE(isisMplsTE))
- mpls_te_print_detail(vty, te_is_neigh);
- }
+ lsp_print_mt_reach(lsp->tlv_data.te_is_neighs, vty,
+ dynhost, ISIS_MT_IPV4_UNICAST);
+
+ /* MT IS neighbor tlv */
+ for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.mt_is_neighs, lnode, mt_is_neigh))
+ lsp_print_mt_reach(mt_is_neigh->list, vty, dynhost, mt_is_neigh->mtid);
/* TE IPv4 tlv */
- if (lsp->tlv_data.te_ipv4_reachs)
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, lnode,
- te_ipv4_reach))
- {
- /* FIXME: There should be better way to output this stuff. */
- vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s",
- ntohl (te_ipv4_reach->te_metric),
- inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
- te_ipv4_reach->control)),
- te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
- }
+ lsp_print_mt_ipv4_reach(lsp->tlv_data.te_ipv4_reachs, vty,
+ ISIS_MT_IPV4_UNICAST);
+
+ /* MT IPv4 reachability tlv */
+ for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.mt_ipv4_reachs, lnode, mt_ipv4_reachs))
+ lsp_print_mt_ipv4_reach(mt_ipv4_reachs->list, vty, mt_ipv4_reachs->mtid);
+
vty_out (vty, "%s", VTY_NEWLINE);
return;
@@ -1028,6 +1120,42 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)
return lsp_count;
}
+static void
+_lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
+ int frag_thold,
+ unsigned int tlv_build_func (struct list *, struct stream *,
+ void *arg),
+ void *arg)
+{
+ while (*from && listcount(*from))
+ {
+ unsigned int count;
+
+ count = tlv_build_func(*from, lsp->pdu, arg);
+
+ if (listcount(*to) != 0 || count != listcount(*from))
+ {
+ struct listnode *node, *nnode;
+ void *elem;
+
+ for (ALL_LIST_ELEMENTS(*from, node, nnode, elem))
+ {
+ if (!count)
+ break;
+ listnode_add (*to, elem);
+ list_delete_node (*from, node);
+ --count;
+ }
+ }
+ else
+ {
+ list_free (*to);
+ *to = *from;
+ *from = NULL;
+ }
+ }
+}
+
#define FRAG_THOLD(S,T) \
((STREAM_SIZE(S)*T)/100)
@@ -1085,64 +1213,6 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
return;
}
-/* Process IS_NEIGHBOURS TLV with TE subTLVs */
-void
-lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, int frag_thold)
-{
- int count, size = 0;
- struct listnode *node, *nextnode;
- struct te_is_neigh *elem;
-
- /* Start computing real size of TLVs */
- for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
- size = size + elem->sub_tlvs_length + IS_NEIGHBOURS_LEN;
-
- /* can we fit all ? */
- if (!FRAG_NEEDED (lsp->pdu, frag_thold, size))
- {
- tlv_add_te_is_neighs (*from, lsp->pdu);
- if (listcount (*to) != 0)
- {
- for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
- {
- listnode_add (*to, elem);
- list_delete_node (*from, node);
- }
- }
- else
- {
- list_free (*to);
- *to = *from;
- *from = NULL;
- }
- }
- else
- {
- /* fit all we can */
- /* Compute remaining place in LSP PDU */
- count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
- (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
- /* Determine size of TE SubTLVs */
- elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from));
- count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN;
- if (count > 0)
- {
- while (count > 0)
- {
- listnode_add (*to, listgetdata ((struct listnode *)listhead (*from)));
- listnode_delete (*from, listgetdata ((struct listnode *)listhead (*from)));
-
- elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from));
- count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN;
- }
-
- tlv_add_te_is_neighs (*to, lsp->pdu);
- }
- }
- lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
- return;
-}
-
static u_int16_t
lsp_rem_lifetime (struct isis_area *area, int level)
{
@@ -1278,6 +1348,24 @@ lsp_build_ext_reach_ipv4(struct isis_lsp *lsp, struct isis_area *area,
}
}
+static struct list *
+tlv_get_ipv6_reach_list(struct isis_area *area, struct tlvs *tlv_data)
+{
+ uint16_t mtid = isis_area_ipv6_topology(area);
+ if (mtid == ISIS_MT_IPV4_UNICAST)
+ {
+ if (!tlv_data->ipv6_reachs)
+ {
+ tlv_data->ipv6_reachs = list_new();
+ tlv_data->ipv6_reachs->del = free_tlv;
+ }
+ return tlv_data->ipv6_reachs;
+ }
+
+ struct tlv_mt_ipv6_reachs *reachs = tlvs_get_mt_ipv6_reachs(tlv_data, mtid);
+ return reachs->list;
+}
+
static void
lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
struct tlvs *tlv_data)
@@ -1287,6 +1375,7 @@ lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
struct prefix_ipv6 *ipv6;
struct isis_ext_info *info;
struct ipv6_reachability *ip6reach;
+ struct list *reach_list = NULL;
er_table = get_ext_reach(area, AF_INET6, lsp->level);
if (!er_table)
@@ -1300,11 +1389,9 @@ lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
ipv6 = (struct prefix_ipv6*)&rn->p;
info = rn->info;
- if (tlv_data->ipv6_reachs == NULL)
- {
- tlv_data->ipv6_reachs = list_new();
- tlv_data->ipv6_reachs->del = free_tlv;
- }
+ if (!reach_list)
+ reach_list = tlv_get_ipv6_reach_list(area, tlv_data);
+
ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach));
if (info->metric > MAX_WIDE_PATH_METRIC)
ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC);
@@ -1313,7 +1400,7 @@ lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
ip6reach->control_info = DISTRIBUTION_EXTERNAL;
ip6reach->prefix_len = ipv6->prefixlen;
memcpy(ip6reach->prefix, ipv6->prefix.s6_addr, sizeof(ip6reach->prefix));
- listnode_add(tlv_data->ipv6_reachs, ip6reach);
+ listnode_add(reach_list, ip6reach);
}
}
@@ -1342,6 +1429,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
struct te_ipv4_reachability *te_ipreach;
struct isis_adjacency *nei;
struct prefix_ipv6 *ipv6, ip6prefix;
+ struct list *ipv6_reachs = NULL;
struct ipv6_reachability *ip6reach;
struct tlvs tlv_data;
struct isis_lsp *lsp0 = lsp;
@@ -1402,6 +1490,32 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
}
+ if (area_is_mt(area))
+ {
+ lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag);
+ lsp->tlv_data.mt_router_info = list_new();
+ lsp->tlv_data.mt_router_info->del = free_tlv;
+
+ struct isis_area_mt_setting **mt_settings;
+ unsigned int mt_count;
+
+ mt_settings = area_mt_settings(area, &mt_count);
+ for (unsigned int i = 0; i < mt_count; i++)
+ {
+ struct mt_router_info *info;
+
+ info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
+ info->mtid = mt_settings[i]->mtid;
+ info->overload = mt_settings[i]->overload;
+ listnode_add(lsp->tlv_data.mt_router_info, info);
+ lsp_debug("ISIS (%s): MT %s", area->area_tag, isis_mtid2str(info->mtid));
+ }
+ tlv_add_mt_router_info (lsp->tlv_data.mt_router_info, lsp->pdu);
+ }
+ else
+ {
+ lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)", area->area_tag);
+ }
/* Dynamic Hostname */
if (area->dynhostname)
{
@@ -1551,12 +1665,9 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
if (circuit->ipv6_router && circuit->ipv6_non_link &&
circuit->ipv6_non_link->count > 0)
{
+ if (!ipv6_reachs)
+ ipv6_reachs = tlv_get_ipv6_reach_list(area, &tlv_data);
- if (tlv_data.ipv6_reachs == NULL)
- {
- tlv_data.ipv6_reachs = list_new ();
- tlv_data.ipv6_reachs->del = free_tlv;
- }
for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
{
ip6reach =
@@ -1579,7 +1690,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
memcpy (ip6reach->prefix, ip6prefix.prefix.s6_addr,
sizeof (ip6reach->prefix));
- listnode_add (tlv_data.ipv6_reachs, ip6reach);
+ listnode_add (ipv6_reachs, ip6reach);
}
}
@@ -1658,10 +1769,8 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
/* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
te_is_neigh->sub_tlvs_length = 0;
- listnode_add (tlv_data.te_is_neighs, te_is_neigh);
- lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor",
- area->area_tag, sysid_print(te_is_neigh->neigh_id),
- LSP_PSEUDO_ID(te_is_neigh->neigh_id));
+ tlvs_add_mt_bcast(&tlv_data, circuit, level, te_is_neigh);
+ XFREE(MTYPE_ISIS_TLV, te_is_neigh);
}
}
}
@@ -1718,9 +1827,9 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
else
/* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
te_is_neigh->sub_tlvs_length = 0;
- listnode_add (tlv_data.te_is_neighs, te_is_neigh);
- lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag,
- sysid_print(te_is_neigh->neigh_id));
+
+ tlvs_add_mt_p2p(&tlv_data, circuit, te_is_neigh);
+ XFREE(MTYPE_ISIS_TLV, te_is_neigh);
}
}
else
@@ -1766,35 +1875,62 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
lsp0, area, level);
}
- /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
- * for now. lsp_tlv_fit() needs to be fixed to deal with variable length
- * TLVs (sub TLVs!). */
while (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
{
if (lsp->tlv_data.te_ipv4_reachs == NULL)
lsp->tlv_data.te_ipv4_reachs = list_new ();
- lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs,
- &lsp->tlv_data.te_ipv4_reachs,
- TE_IPV4_REACH_LEN, area->lsp_frag_threshold,
- tlv_add_te_ipv4_reachs);
+ _lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs, &lsp->tlv_data.te_ipv4_reachs,
+ area->lsp_frag_threshold, tlv_add_te_ipv4_reachs, NULL);
if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
lsp0, area, level);
}
+ struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
+ for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv4_reachs, node, mt_ipv4_reachs))
+ {
+ while (mt_ipv4_reachs->list && listcount(mt_ipv4_reachs->list))
+ {
+ struct tlv_mt_ipv4_reachs *frag_mt_ipv4_reachs;
+
+ frag_mt_ipv4_reachs = tlvs_get_mt_ipv4_reachs(&lsp->tlv_data, mt_ipv4_reachs->mtid);
+ _lsp_tlv_fit (lsp, &mt_ipv4_reachs->list, &frag_mt_ipv4_reachs->list,
+ area->lsp_frag_threshold, tlv_add_te_ipv4_reachs,
+ &mt_ipv4_reachs->mtid);
+ if (mt_ipv4_reachs->list && listcount(mt_ipv4_reachs->list))
+ lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
+ lsp0, area, level);
+ }
+ }
+
while (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
{
if (lsp->tlv_data.ipv6_reachs == NULL)
lsp->tlv_data.ipv6_reachs = list_new ();
- lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs,
- &lsp->tlv_data.ipv6_reachs,
- IPV6_REACH_LEN, area->lsp_frag_threshold,
- tlv_add_ipv6_reachs);
+ _lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs, &lsp->tlv_data.ipv6_reachs,
+ area->lsp_frag_threshold, tlv_add_ipv6_reachs, NULL);
if (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
lsp0, area, level);
}
+ struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
+ for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv6_reachs, node, mt_ipv6_reachs))
+ {
+ while (mt_ipv6_reachs->list && listcount(mt_ipv6_reachs->list))
+ {
+ struct tlv_mt_ipv6_reachs *frag_mt_ipv6_reachs;
+
+ frag_mt_ipv6_reachs = tlvs_get_mt_ipv6_reachs(&lsp->tlv_data, mt_ipv6_reachs->mtid);
+ _lsp_tlv_fit (lsp, &mt_ipv6_reachs->list, &frag_mt_ipv6_reachs->list,
+ area->lsp_frag_threshold, tlv_add_ipv6_reachs,
+ &mt_ipv6_reachs->mtid);
+ if (mt_ipv6_reachs->list && listcount(mt_ipv6_reachs->list))
+ lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
+ lsp0, area, level);
+ }
+ }
+
while (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
{
if (lsp->tlv_data.is_neighs == NULL)
@@ -1812,13 +1948,31 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
{
if (lsp->tlv_data.te_is_neighs == NULL)
lsp->tlv_data.te_is_neighs = list_new ();
- lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
- IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
- tlv_add_te_is_neighs);
+ _lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
+ area->lsp_frag_threshold, tlv_add_te_is_neighs, NULL);
if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
lsp0, area, level);
}
+
+ struct tlv_mt_neighbors *mt_neighs;
+ for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_is_neighs, node, mt_neighs))
+ {
+ while (mt_neighs->list && listcount(mt_neighs->list))
+ {
+ struct tlv_mt_neighbors *frag_mt_neighs;
+
+ frag_mt_neighs = tlvs_get_mt_neighbors(&lsp->tlv_data, mt_neighs->mtid);
+ _lsp_tlv_fit (lsp, &mt_neighs->list, &frag_mt_neighs->list,
+ area->lsp_frag_threshold, tlv_add_te_is_neighs,
+ &mt_neighs->mtid);
+ if (mt_neighs->list && listcount(mt_neighs->list))
+ lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
+ lsp0, area, level);
+ }
+ }
+
+
lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
free_tlvs (&tlv_data);
@@ -2255,7 +2409,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);
if (lsp->tlv_data.te_is_neighs && listcount (lsp->tlv_data.te_is_neighs) > 0)
- tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu);
+ tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu, NULL);
if (lsp->tlv_data.es_neighs && listcount (lsp->tlv_data.es_neighs) > 0)
tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h
index 24fae57a7..6f697df62 100644
--- a/isisd/isis_lsp.h
+++ b/isisd/isis_lsp.h
@@ -108,8 +108,6 @@ void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost);
int lsp_print_all (struct vty *vty, dict_t * lspdb, char detail,
char dynhost);
const char *lsp_bits2string (u_char *);
-void lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from,
- struct list **to, int frag_thold);
/* sets SRMflags for all active circuits of an lsp */
void lsp_set_all_srmflags (struct isis_lsp *lsp);
diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c
new file mode 100644
index 000000000..552365ad1
--- /dev/null
+++ b/isisd/isis_mt.c
@@ -0,0 +1,724 @@
+/*
+ * IS-IS Rout(e)ing protocol - Multi Topology Support
+ *
+ * Copyright (C) 2017 Christian Franke
+ *
+ * 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 "isisd/isisd.h"
+#include "isisd/isis_memory.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_tlv.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_mt.h"
+
+DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")
+DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting")
+DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")
+DEFINE_MTYPE_STATIC(ISISD, MT_NEIGHBORS, "ISIS MT Neighbors for TLV")
+DEFINE_MTYPE_STATIC(ISISD, MT_IPV4_REACHS, "ISIS MT IPv4 Reachabilities for TLV")
+DEFINE_MTYPE_STATIC(ISISD, MT_IPV6_REACHS, "ISIS MT IPv6 Reachabilities for TLV")
+
+uint16_t isis_area_ipv6_topology(struct isis_area *area)
+{
+ struct isis_area_mt_setting *area_mt_setting;
+ area_mt_setting = area_lookup_mt_setting(area, ISIS_MT_IPV6_UNICAST);
+
+ if (area_mt_setting && area_mt_setting->enabled)
+ return ISIS_MT_IPV6_UNICAST;
+ return ISIS_MT_IPV4_UNICAST;
+}
+
+/* MT naming api */
+const char *isis_mtid2str(uint16_t mtid)
+{
+ static char buf[sizeof("65535")];
+
+ switch(mtid)
+ {
+ case ISIS_MT_IPV4_UNICAST:
+ return "ipv4-unicast";
+ case ISIS_MT_IPV4_MGMT:
+ return "ipv4-mgmt";
+ case ISIS_MT_IPV6_UNICAST:
+ return "ipv6-unicast";
+ case ISIS_MT_IPV4_MULTICAST:
+ return "ipv4-multicast";
+ case ISIS_MT_IPV6_MULTICAST:
+ return "ipv6-multicast";
+ case ISIS_MT_IPV6_MGMT:
+ return "ipv6-mgmt";
+ default:
+ snprintf(buf, sizeof(buf), "%" PRIu16, mtid);
+ return buf;
+ }
+}
+
+uint16_t isis_str2mtid(const char *name)
+{
+ if (!strcmp(name,"ipv4-unicast"))
+ return ISIS_MT_IPV4_UNICAST;
+ if (!strcmp(name,"ipv4-mgmt"))
+ return ISIS_MT_IPV4_MGMT;
+ if (!strcmp(name,"ipv6-unicast"))
+ return ISIS_MT_IPV6_UNICAST;
+ if (!strcmp(name,"ipv4-multicast"))
+ return ISIS_MT_IPV4_MULTICAST;
+ if (!strcmp(name,"ipv6-multicast"))
+ return ISIS_MT_IPV6_MULTICAST;
+ if (!strcmp(name,"ipv6-mgmt"))
+ return ISIS_MT_IPV6_MGMT;
+ return -1;
+}
+
+/* General MT settings api */
+
+struct mt_setting {
+ ISIS_MT_INFO_FIELDS;
+};
+
+static void *
+lookup_mt_setting(struct list *mt_list, uint16_t mtid)
+{
+ struct listnode *node;
+ struct mt_setting *setting;
+
+ for (ALL_LIST_ELEMENTS_RO(mt_list, node, setting))
+ {
+ if (setting->mtid == mtid)
+ return setting;
+ }
+ return NULL;
+}
+
+static void
+add_mt_setting(struct list **mt_list, void *setting)
+{
+ if (!*mt_list)
+ *mt_list = list_new();
+ listnode_add(*mt_list, setting);
+}
+
+/* Area specific MT settings api */
+
+struct isis_area_mt_setting*
+area_lookup_mt_setting(struct isis_area *area, uint16_t mtid)
+{
+ return lookup_mt_setting(area->mt_settings, mtid);
+}
+
+struct isis_area_mt_setting*
+area_new_mt_setting(struct isis_area *area, uint16_t mtid)
+{
+ struct isis_area_mt_setting *setting;
+
+ setting = XCALLOC(MTYPE_MT_AREA_SETTING, sizeof(*setting));
+ setting->mtid = mtid;
+ return setting;
+}
+
+static void
+area_free_mt_setting(void *setting)
+{
+ XFREE(MTYPE_MT_AREA_SETTING, setting);
+}
+
+void
+area_add_mt_setting(struct isis_area *area, struct isis_area_mt_setting *setting)
+{
+ add_mt_setting(&area->mt_settings, setting);
+}
+
+void
+area_mt_init(struct isis_area *area)
+{
+ struct isis_area_mt_setting *v4_unicast_setting;
+
+ /* MTID 0 is always enabled */
+ v4_unicast_setting = area_new_mt_setting(area, ISIS_MT_IPV4_UNICAST);
+ v4_unicast_setting->enabled = true;
+ add_mt_setting(&area->mt_settings, v4_unicast_setting);
+ area->mt_settings->del = area_free_mt_setting;
+}
+
+void
+area_mt_finish(struct isis_area *area)
+{
+ list_delete(area->mt_settings);
+ area->mt_settings = NULL;
+}
+
+struct isis_area_mt_setting *
+area_get_mt_setting(struct isis_area *area, uint16_t mtid)
+{
+ struct isis_area_mt_setting *setting;
+
+ setting = area_lookup_mt_setting(area, mtid);
+ if (!setting)
+ {
+ setting = area_new_mt_setting(area, mtid);
+ area_add_mt_setting(area, setting);
+ }
+ return setting;
+}
+
+int
+area_write_mt_settings(struct isis_area *area, struct vty *vty)
+{
+ int written = 0;
+ struct listnode *node;
+ struct isis_area_mt_setting *setting;
+
+ for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
+ {
+ const char *name = isis_mtid2str(setting->mtid);
+ if (name && setting->enabled)
+ {
+ if (setting->mtid == ISIS_MT_IPV4_UNICAST)
+ continue; /* always enabled, no need to write out config */
+ vty_out (vty, " topology %s%s%s", name,
+ setting->overload ? " overload" : "",
+ VTY_NEWLINE);
+ written++;
+ }
+ }
+ return written;
+}
+
+bool area_is_mt(struct isis_area *area)
+{
+ struct listnode *node, *node2;
+ struct isis_area_mt_setting *setting;
+ struct isis_circuit *circuit;
+ struct isis_circuit_mt_setting *csetting;
+
+ for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
+ {
+ if (setting->enabled && setting->mtid != ISIS_MT_IPV4_UNICAST)
+ return true;
+ }
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
+ {
+ for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node2, csetting))
+ {
+ if (!csetting->enabled && csetting->mtid == ISIS_MT_IPV4_UNICAST)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+struct isis_area_mt_setting**
+area_mt_settings(struct isis_area *area, unsigned int *mt_count)
+{
+ static unsigned int size = 0;
+ static struct isis_area_mt_setting **rv = NULL;
+
+ unsigned int count = 0;
+ struct listnode *node;
+ struct isis_area_mt_setting *setting;
+
+ for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
+ {
+ if (!setting->enabled)
+ continue;
+
+ count++;
+ if (count > size)
+ {
+ rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
+ size = count;
+ }
+ rv[count-1] = setting;
+ }
+
+ *mt_count = count;
+ return rv;
+}
+
+/* Circuit specific MT settings api */
+
+struct isis_circuit_mt_setting*
+circuit_lookup_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
+{
+ return lookup_mt_setting(circuit->mt_settings, mtid);
+}
+
+struct isis_circuit_mt_setting*
+circuit_new_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
+{
+ struct isis_circuit_mt_setting *setting;
+
+ setting = XCALLOC(MTYPE_MT_CIRCUIT_SETTING, sizeof(*setting));
+ setting->mtid = mtid;
+ setting->enabled = true; /* Enabled is default for circuit */
+ return setting;
+}
+
+static void
+circuit_free_mt_setting(void *setting)
+{
+ XFREE(MTYPE_MT_CIRCUIT_SETTING, setting);
+}
+
+void
+circuit_add_mt_setting(struct isis_circuit *circuit,
+ struct isis_circuit_mt_setting *setting)
+{
+ add_mt_setting(&circuit->mt_settings, setting);
+}
+
+void
+circuit_mt_init(struct isis_circuit *circuit)
+{
+ circuit->mt_settings = list_new();
+ circuit->mt_settings->del = circuit_free_mt_setting;
+}
+
+void
+circuit_mt_finish(struct isis_circuit *circuit)
+{
+ list_delete(circuit->mt_settings);
+ circuit->mt_settings = NULL;
+}
+
+struct isis_circuit_mt_setting*
+circuit_get_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
+{
+ struct isis_circuit_mt_setting *setting;
+
+ setting = circuit_lookup_mt_setting(circuit, mtid);
+ if (!setting)
+ {
+ setting = circuit_new_mt_setting(circuit, mtid);
+ circuit_add_mt_setting(circuit, setting);
+ }
+ return setting;
+}
+
+int
+circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty)
+{
+ int written = 0;
+ struct listnode *node;
+ struct isis_circuit_mt_setting *setting;
+
+ for (ALL_LIST_ELEMENTS_RO (circuit->mt_settings, node, setting))
+ {
+ const char *name = isis_mtid2str(setting->mtid);
+ if (name && !setting->enabled)
+ {
+ vty_out (vty, " no isis topology %s%s", name, VTY_NEWLINE);
+ written++;
+ }
+ }
+ return written;
+}
+
+struct isis_circuit_mt_setting**
+circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count)
+{
+ static unsigned int size = 0;
+ static struct isis_circuit_mt_setting **rv = NULL;
+
+ struct isis_area_mt_setting **area_settings;
+ unsigned int area_count;
+
+ unsigned int count = 0;
+
+ struct listnode *node;
+ struct isis_circuit_mt_setting *setting;
+
+ area_settings = area_mt_settings(circuit->area, &area_count);
+
+ for (unsigned int i = 0; i < area_count; i++)
+ {
+ for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node, setting))
+ {
+ if (setting->mtid != area_settings[i]->mtid)
+ continue;
+ break;
+ }
+ if (!setting)
+ setting = circuit_get_mt_setting(circuit, area_settings[i]->mtid);
+
+ if (!setting->enabled)
+ continue;
+
+ count++;
+ if (count > size)
+ {
+ rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
+ size = count;
+ }
+ rv[count-1] = setting;
+ }
+
+ *mt_count = count;
+ return rv;
+}
+
+/* ADJ specific MT API */
+static void adj_mt_set(struct isis_adjacency *adj, unsigned int index,
+ uint16_t mtid)
+{
+ if (adj->mt_count < index + 1)
+ {
+ adj->mt_set = XREALLOC(MTYPE_MT_ADJ_INFO, adj->mt_set,
+ (index + 1) * sizeof(*adj->mt_set));
+ adj->mt_count = index + 1;
+ }
+ adj->mt_set[index] = mtid;
+}
+
+bool
+tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
+ struct isis_adjacency *adj)
+{
+ struct isis_circuit_mt_setting **mt_settings;
+ unsigned int circuit_mt_count;
+
+ unsigned int intersect_count = 0;
+
+ uint16_t *old_mt_set = NULL;
+ unsigned int old_mt_count;
+
+ old_mt_count = adj->mt_count;
+ if (old_mt_count)
+ {
+ old_mt_set = XCALLOC(MTYPE_TMP, old_mt_count * sizeof(*old_mt_set));
+ memcpy(old_mt_set, adj->mt_set, old_mt_count * sizeof(*old_mt_set));
+ }
+
+ mt_settings = circuit_mt_settings(adj->circuit, &circuit_mt_count);
+ for (unsigned int i = 0; i < circuit_mt_count; i++)
+ {
+ if (!tlvs->mt_router_info)
+ {
+ /* Other end does not have MT enabled */
+ if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST)
+ adj_mt_set(adj, intersect_count++, ISIS_MT_IPV4_UNICAST);
+ }
+ else
+ {
+ struct listnode *node;
+ struct mt_router_info *info;
+ for (ALL_LIST_ELEMENTS_RO(tlvs->mt_router_info, node, info))
+ {
+ if (mt_settings[i]->mtid == info->mtid)
+ adj_mt_set(adj, intersect_count++, info->mtid);
+ }
+ }
+ }
+ adj->mt_count = intersect_count;
+
+ bool changed = false;
+
+ if (adj->mt_count != old_mt_count)
+ changed = true;
+
+ if (!changed && old_mt_count
+ && memcmp(adj->mt_set, old_mt_set,
+ old_mt_count * sizeof(*old_mt_set)))
+ changed = true;
+
+ if (old_mt_count)
+ XFREE(MTYPE_TMP, old_mt_set);
+
+ return changed;
+}
+
+bool
+adj_has_mt(struct isis_adjacency *adj, uint16_t mtid)
+{
+ for (unsigned int i = 0; i < adj->mt_count; i++)
+ if (adj->mt_set[i] == mtid)
+ return true;
+ return false;
+}
+
+void
+adj_mt_finish(struct isis_adjacency *adj)
+{
+ XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set);
+ adj->mt_count = 0;
+}
+
+/* TLV Router info api */
+struct mt_router_info*
+tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid)
+{
+ return lookup_mt_setting(tlvs->mt_router_info, mtid);
+}
+
+/* TLV MT Neighbors api */
+struct tlv_mt_neighbors*
+tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
+{
+ return lookup_mt_setting(tlvs->mt_is_neighs, mtid);
+}
+
+static struct tlv_mt_neighbors*
+tlvs_new_mt_neighbors(uint16_t mtid)
+{
+ struct tlv_mt_neighbors *rv;
+
+ rv = XCALLOC(MTYPE_MT_NEIGHBORS, sizeof(*rv));
+ rv->mtid = mtid;
+ rv->list = list_new();
+
+ return rv;
+};
+
+static void
+tlvs_free_mt_neighbors(void *arg)
+{
+ struct tlv_mt_neighbors *neighbors = arg;
+
+ if (neighbors && neighbors->list)
+ list_delete(neighbors->list);
+ XFREE(MTYPE_MT_NEIGHBORS, neighbors);
+}
+
+static void
+tlvs_add_mt_neighbors(struct tlvs *tlvs, struct tlv_mt_neighbors *neighbors)
+{
+ add_mt_setting(&tlvs->mt_is_neighs, neighbors);
+ tlvs->mt_is_neighs->del = tlvs_free_mt_neighbors;
+}
+
+struct tlv_mt_neighbors*
+tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
+{
+ struct tlv_mt_neighbors *neighbors;
+
+ neighbors = tlvs_lookup_mt_neighbors(tlvs, mtid);
+ if (!neighbors)
+ {
+ neighbors = tlvs_new_mt_neighbors(mtid);
+ tlvs_add_mt_neighbors(tlvs, neighbors);
+ }
+ return neighbors;
+}
+
+/* TLV MT IPv4 reach api */
+struct tlv_mt_ipv4_reachs*
+tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
+{
+ return lookup_mt_setting(tlvs->mt_ipv4_reachs, mtid);
+}
+
+static struct tlv_mt_ipv4_reachs*
+tlvs_new_mt_ipv4_reachs(uint16_t mtid)
+{
+ struct tlv_mt_ipv4_reachs *rv;
+
+ rv = XCALLOC(MTYPE_MT_IPV4_REACHS, sizeof(*rv));
+ rv->mtid = mtid;
+ rv->list = list_new();
+
+ return rv;
+};
+
+static void
+tlvs_free_mt_ipv4_reachs(void *arg)
+{
+ struct tlv_mt_ipv4_reachs *reachs = arg;
+
+ if (reachs && reachs->list)
+ list_delete(reachs->list);
+ XFREE(MTYPE_MT_IPV4_REACHS, reachs);
+}
+
+static void
+tlvs_add_mt_ipv4_reachs(struct tlvs *tlvs, struct tlv_mt_ipv4_reachs *reachs)
+{
+ add_mt_setting(&tlvs->mt_ipv4_reachs, reachs);
+ tlvs->mt_ipv4_reachs->del = tlvs_free_mt_ipv4_reachs;
+}
+
+struct tlv_mt_ipv4_reachs*
+tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
+{
+ struct tlv_mt_ipv4_reachs *reachs;
+
+ reachs = tlvs_lookup_mt_ipv4_reachs(tlvs, mtid);
+ if (!reachs)
+ {
+ reachs = tlvs_new_mt_ipv4_reachs(mtid);
+ tlvs_add_mt_ipv4_reachs(tlvs, reachs);
+ }
+ return reachs;
+}
+
+/* TLV MT IPv6 reach api */
+struct tlv_mt_ipv6_reachs*
+tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
+{
+ return lookup_mt_setting(tlvs->mt_ipv6_reachs, mtid);
+}
+
+static struct tlv_mt_ipv6_reachs*
+tlvs_new_mt_ipv6_reachs(uint16_t mtid)
+{
+ struct tlv_mt_ipv6_reachs *rv;
+
+ rv = XCALLOC(MTYPE_MT_IPV6_REACHS, sizeof(*rv));
+ rv->mtid = mtid;
+ rv->list = list_new();
+
+ return rv;
+};
+
+static void
+tlvs_free_mt_ipv6_reachs(void *arg)
+{
+ struct tlv_mt_ipv6_reachs *reachs = arg;
+
+ if (reachs && reachs->list)
+ list_delete(reachs->list);
+ XFREE(MTYPE_MT_IPV6_REACHS, reachs);
+}
+
+static void
+tlvs_add_mt_ipv6_reachs(struct tlvs *tlvs, struct tlv_mt_ipv6_reachs *reachs)
+{
+ add_mt_setting(&tlvs->mt_ipv6_reachs, reachs);
+ tlvs->mt_ipv6_reachs->del = tlvs_free_mt_ipv6_reachs;
+}
+
+struct tlv_mt_ipv6_reachs*
+tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
+{
+ struct tlv_mt_ipv6_reachs *reachs;
+
+ reachs = tlvs_lookup_mt_ipv6_reachs(tlvs, mtid);
+ if (!reachs)
+ {
+ reachs = tlvs_new_mt_ipv6_reachs(mtid);
+ tlvs_add_mt_ipv6_reachs(tlvs, reachs);
+ }
+ return reachs;
+}
+
+static void
+mt_set_add(uint16_t **mt_set, unsigned int *size,
+ unsigned int *index, uint16_t mtid)
+{
+ for (unsigned int i = 0; i < *index; i++)
+ {
+ if ((*mt_set)[i] == mtid)
+ return;
+ }
+
+ if (*index >= *size)
+ {
+ *mt_set = XREALLOC(MTYPE_TMP, *mt_set, sizeof(**mt_set) * ((*index) + 1));
+ *size = (*index) + 1;
+ }
+
+ (*mt_set)[*index] = mtid;
+ *index = (*index) + 1;
+}
+
+static uint16_t *
+circuit_bcast_mt_set(struct isis_circuit *circuit, int level,
+ unsigned int *mt_count)
+{
+ static uint16_t *rv;
+ static unsigned int size;
+ struct listnode *node;
+ struct isis_adjacency *adj;
+
+ unsigned int count = 0;
+
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST)
+ {
+ *mt_count = 0;
+ return NULL;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(circuit->u.bc.adjdb[level - 1], node, adj))
+ {
+ if (adj->adj_state != ISIS_ADJ_UP)
+ continue;
+ for (unsigned int i = 0; i < adj->mt_count; i++)
+ mt_set_add(&rv, &size, &count, adj->mt_set[i]);
+ }
+
+ *mt_count = count;
+ return rv;
+}
+
+static void
+tlvs_add_mt_set(struct isis_area *area,
+ struct tlvs *tlvs, unsigned int mt_count,
+ uint16_t *mt_set, struct te_is_neigh *neigh)
+{
+ for (unsigned int i = 0; i < mt_count; i++)
+ {
+ uint16_t mtid = mt_set[i];
+ struct te_is_neigh *ne_copy;
+
+ ne_copy = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ne_copy));
+ memcpy(ne_copy, neigh, sizeof(*ne_copy));
+
+ if (mt_set[i] == ISIS_MT_IPV4_UNICAST)
+ {
+ listnode_add(tlvs->te_is_neighs, ne_copy);
+ lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor",
+ area->area_tag, sysid_print(ne_copy->neigh_id),
+ LSP_PSEUDO_ID(ne_copy->neigh_id));
+ }
+ else
+ {
+ struct tlv_mt_neighbors *neighbors;
+
+ neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
+ neighbors->list->del = free_tlv;
+ listnode_add(neighbors->list, ne_copy);
+ lsp_debug("ISIS (%s): Adding %s.%02x as mt-style neighbor for %s",
+ area->area_tag, sysid_print(ne_copy->neigh_id),
+ LSP_PSEUDO_ID(ne_copy->neigh_id), isis_mtid2str(mtid));
+ }
+ }
+}
+
+void
+tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
+ int level, struct te_is_neigh *neigh)
+{
+ unsigned int mt_count;
+ uint16_t *mt_set = circuit_bcast_mt_set(circuit, level,
+ &mt_count);
+
+ tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, neigh);
+}
+
+void
+tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
+ struct te_is_neigh *neigh)
+{
+ struct isis_adjacency *adj = circuit->u.p2p.neighbor;
+
+ tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, neigh);
+}
diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h
new file mode 100644
index 000000000..d4dc4c6f2
--- /dev/null
+++ b/isisd/isis_mt.h
@@ -0,0 +1,146 @@
+/*
+ * IS-IS Rout(e)ing protocol - Multi Topology Support
+ *
+ * Copyright (C) 2017 Christian Franke
+ *
+ * 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 ISIS_MT_H
+#define ISIS_MT_H
+
+#define ISIS_MT_MASK 0x0fff
+#define ISIS_MT_OL_MASK 0x8000
+
+#define ISIS_MT_IPV4_UNICAST 0
+#define ISIS_MT_IPV4_MGMT 1
+#define ISIS_MT_IPV6_UNICAST 2
+#define ISIS_MT_IPV4_MULTICAST 3
+#define ISIS_MT_IPV6_MULTICAST 4
+#define ISIS_MT_IPV6_MGMT 5
+
+#define ISIS_MT_NAMES \
+ "<ipv4-unicast" \
+ "|ipv4-mgmt" \
+ "|ipv6-unicast" \
+ "|ipv4-multicast" \
+ "|ipv6-multicast" \
+ "|ipv6-mgmt" \
+ ">"
+
+#define ISIS_MT_DESCRIPTIONS \
+ "IPv4 unicast topology\n" \
+ "IPv4 management topology\n" \
+ "IPv6 unicast topology\n" \
+ "IPv4 multicast topology\n" \
+ "IPv6 multicast topology\n" \
+ "IPv6 management topology\n"
+
+#define ISIS_MT_INFO_FIELDS \
+ uint16_t mtid;
+
+struct list;
+
+struct isis_area_mt_setting {
+ ISIS_MT_INFO_FIELDS
+ bool enabled;
+ bool overload;
+};
+
+struct isis_circuit_mt_setting {
+ ISIS_MT_INFO_FIELDS
+ bool enabled;
+};
+
+struct tlv_mt_neighbors {
+ ISIS_MT_INFO_FIELDS
+ struct list *list;
+};
+
+struct tlv_mt_ipv4_reachs {
+ ISIS_MT_INFO_FIELDS
+ struct list *list;
+};
+
+struct tlv_mt_ipv6_reachs {
+ ISIS_MT_INFO_FIELDS
+ struct list *list;
+};
+
+const char *isis_mtid2str(uint16_t mtid);
+uint16_t isis_str2mtid(const char *name);
+
+struct isis_adjacency;
+struct isis_area;
+struct isis_circuit;
+struct tlvs;
+struct te_is_neigh;
+
+uint16_t isis_area_ipv6_topology(struct isis_area *area);
+
+struct mt_router_info* tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid);
+
+struct tlv_mt_neighbors* tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid);
+struct tlv_mt_neighbors* tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid);
+
+struct tlv_mt_ipv4_reachs* tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid);
+struct tlv_mt_ipv4_reachs* tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid);
+
+struct tlv_mt_ipv6_reachs* tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid);
+struct tlv_mt_ipv6_reachs* tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid);
+
+struct isis_area_mt_setting* area_lookup_mt_setting(struct isis_area *area,
+ uint16_t mtid);
+struct isis_area_mt_setting* area_new_mt_setting(struct isis_area *area,
+ uint16_t mtid);
+void area_add_mt_setting(struct isis_area *area,
+ struct isis_area_mt_setting *setting);
+
+void area_mt_init(struct isis_area *area);
+void area_mt_finish(struct isis_area *area);
+struct isis_area_mt_setting* area_get_mt_setting(struct isis_area *area,
+ uint16_t mtid);
+int area_write_mt_settings(struct isis_area *area, struct vty *vty);
+bool area_is_mt(struct isis_area *area);
+struct isis_area_mt_setting** area_mt_settings(struct isis_area *area,
+ unsigned int *mt_count);
+
+struct isis_circuit_mt_setting* circuit_lookup_mt_setting(
+ struct isis_circuit *circuit,
+ uint16_t mtid);
+struct isis_circuit_mt_setting* circuit_new_mt_setting(
+ struct isis_circuit *circuit,
+ uint16_t mtid);
+void circuit_add_mt_setting(struct isis_circuit *circuit,
+ struct isis_circuit_mt_setting *setting);
+void circuit_mt_init(struct isis_circuit *circuit);
+void circuit_mt_finish(struct isis_circuit *circuit);
+struct isis_circuit_mt_setting* circuit_get_mt_setting(
+ struct isis_circuit *circuit,
+ uint16_t mtid);
+int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty);
+struct isis_circuit_mt_setting** circuit_mt_settings(struct isis_circuit *circuit,
+ unsigned int *mt_count);
+bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
+ struct isis_adjacency *adj);
+bool adj_has_mt(struct isis_adjacency *adj, uint16_t mtid);
+void adj_mt_finish(struct isis_adjacency *adj);
+void tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
+ int level, struct te_is_neigh *neigh);
+void tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
+ struct te_is_neigh *neigh);
+#endif
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index 5fbf6c194..9e90acf2e 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -53,6 +53,7 @@
#include "isisd/isis_csm.h"
#include "isisd/isis_events.h"
#include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
#define ISIS_MINIMUM_FIXED_HDR_LEN 15
#define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
@@ -471,6 +472,7 @@ process_p2p_hello (struct isis_circuit *circuit)
expected |= TLVFLAG_NLPID;
expected |= TLVFLAG_IPV4_ADDR;
expected |= TLVFLAG_IPV6_ADDR;
+ expected |= TLVFLAG_MT_ROUTER_INFORMATION;
auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
retval = parse_tlvs (circuit->area->area_tag,
@@ -633,6 +635,8 @@ process_p2p_hello (struct isis_circuit *circuit)
if (found & TLVFLAG_IPV6_ADDR)
tlvs_to_adj_ipv6_addrs (&tlvs, adj);
+ bool mt_set_changed = tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj);
+
/* lets take care of the expiry */
THREAD_TIMER_OFF (adj->t_expire);
THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
@@ -869,6 +873,13 @@ process_p2p_hello (struct isis_circuit *circuit)
/* down - area mismatch */
isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
}
+
+ if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed)
+ {
+ lsp_regenerate_schedule(adj->circuit->area,
+ isis_adj_usage2levels(adj->adj_usage), 0);
+ }
+
/* 8.2.5.2 c) if the action was up - comparing circuit IDs */
/* FIXME - Missing parts */
@@ -1021,6 +1032,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
expected |= TLVFLAG_NLPID;
expected |= TLVFLAG_IPV4_ADDR;
expected |= TLVFLAG_IPV6_ADDR;
+ expected |= TLVFLAG_MT_ROUTER_INFORMATION;
auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
retval = parse_tlvs (circuit->area->area_tag,
@@ -1223,6 +1235,8 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
adj->circuit_t = hdr.circuit_t;
+ bool mt_set_changed = tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj);
+
/* lets take care of the expiry */
THREAD_TIMER_OFF (adj->t_expire);
THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
@@ -1266,6 +1280,9 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
"no LAN Neighbours TLV found");
}
+ if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed)
+ lsp_regenerate_schedule(adj->circuit->area, level, 0);
+
out:
if (isis->debugs & DEBUG_ADJ_PACKETS)
{
@@ -2337,6 +2354,37 @@ send_hello (struct isis_circuit *circuit, int level)
if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))
return ISIS_WARNING;
+ /*
+ * MT Supported TLV
+ *
+ * TLV gets included if no topology is enabled on the interface,
+ * if one topology other than #0 is enabled, or if multiple topologies
+ * are enabled.
+ */
+ struct isis_circuit_mt_setting **mt_settings;
+ unsigned int mt_count;
+
+ mt_settings = circuit_mt_settings(circuit, &mt_count);
+ if ((mt_count == 0 && area_is_mt(circuit->area))
+ || (mt_count == 1 && mt_settings[0]->mtid != ISIS_MT_IPV4_UNICAST)
+ || (mt_count > 1))
+ {
+ struct list *mt_info = list_new();
+ mt_info->del = free_tlv;
+
+ for (unsigned int i = 0; i < mt_count; i++)
+ {
+ struct mt_router_info *info;
+
+ info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
+ info->mtid = mt_settings[i]->mtid;
+ /* overload info is not valid in IIH, so it's not included here */
+ listnode_add(mt_info, info);
+ }
+ tlv_add_mt_router_info (mt_info, circuit->snd_stream);
+ list_free(mt_info);
+ }
+
/* IPv6 Interface Address TLV */
if (circuit->ipv6_router && circuit->ipv6_link &&
listcount (circuit->ipv6_link) > 0)
diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c
index dd07a9c6f..5c434b90d 100644
--- a/isisd/isis_pfpacket.c
+++ b/isisd/isis_pfpacket.c
@@ -371,7 +371,9 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
stream_set_getp (circuit->snd_stream, 0);
memset (&sa, 0, sizeof (struct sockaddr_ll));
sa.sll_family = AF_PACKET;
- sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
+
+ size_t frame_size = stream_get_endp(circuit->snd_stream) + LLC_LEN;
+ sa.sll_protocol = htons(isis_ethertype(frame_size));
sa.sll_ifindex = circuit->interface->ifindex;
sa.sll_halen = ETH_ALEN;
/* RFC5309 section 4.1 recommends ALL_ISS */
@@ -418,7 +420,6 @@ isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
stream_set_getp (circuit->snd_stream, 0);
memset (&sa, 0, sizeof (struct sockaddr_ll));
sa.sll_family = AF_PACKET;
- sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
sa.sll_ifindex = circuit->interface->ifindex;
sa.sll_halen = ETH_ALEN;
if (level == 1)
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 554fa563a..d85f08f50 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -5,6 +5,7 @@
* Copyright (C) 2001,2002 Sampo Saaristo
* Tampere University of Technology
* Institute of Communications Engineering
+ * Copyright (C) 2017 Christian Franke <chris@opensourcerouting.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public Licenseas published by the Free
@@ -50,6 +51,14 @@
#include "isis_spf.h"
#include "isis_route.h"
#include "isis_csm.h"
+#include "isis_mt.h"
+
+DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
+
+struct isis_spf_run {
+ struct isis_area *area;
+ int level;
+};
/* 7.2.7 */
static void
@@ -142,35 +151,24 @@ vtype2string (enum vertextype vtype)
default:
return "UNKNOWN";
}
- return NULL; /* Not reached */
+ return NULL; /* Not reached */
}
static const char *
vid2string (struct isis_vertex *vertex, char * buff, int size)
{
- switch (vertex->type)
+ if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type))
{
- case VTYPE_PSEUDO_IS:
- case VTYPE_PSEUDO_TE_IS:
return print_sys_hostname (vertex->N.id);
- break;
- case VTYPE_NONPSEUDO_IS:
- case VTYPE_NONPSEUDO_TE_IS:
- case VTYPE_ES:
- return print_sys_hostname (vertex->N.id);
- break;
- case VTYPE_IPREACH_INTERNAL:
- case VTYPE_IPREACH_EXTERNAL:
- case VTYPE_IPREACH_TE:
- case VTYPE_IP6REACH_INTERNAL:
- case VTYPE_IP6REACH_EXTERNAL:
+ }
+
+ if (VTYPE_IP(vertex->type))
+ {
prefix2str ((struct prefix *) &vertex->N.prefix, buff, size);
- break;
- default:
- return "UNKNOWN";
+ return buff;
}
- return (char *) buff;
+ return "UNKNOWN";
}
static struct isis_vertex *
@@ -181,26 +179,17 @@ isis_vertex_new (void *id, enum vertextype vtype)
vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex));
vertex->type = vtype;
- switch (vtype)
+
+ if (VTYPE_IS(vtype) || VTYPE_ES(vtype))
{
- case VTYPE_ES:
- case VTYPE_NONPSEUDO_IS:
- case VTYPE_NONPSEUDO_TE_IS:
- memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN);
- break;
- case VTYPE_PSEUDO_IS:
- case VTYPE_PSEUDO_TE_IS:
memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1);
- break;
- case VTYPE_IPREACH_INTERNAL:
- case VTYPE_IPREACH_EXTERNAL:
- case VTYPE_IPREACH_TE:
- case VTYPE_IP6REACH_INTERNAL:
- case VTYPE_IP6REACH_EXTERNAL:
- memcpy (&vertex->N.prefix, (struct prefix *) id,
- sizeof (struct prefix));
- break;
- default:
+ }
+ else if (VTYPE_IP(vtype))
+ {
+ memcpy (&vertex->N.prefix, (struct prefix *) id, sizeof (struct prefix));
+ }
+ else
+ {
zlog_err ("WTF!");
}
@@ -280,7 +269,7 @@ isis_spftree_del (struct isis_spftree *spftree)
return;
}
-void
+static void
isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj)
{
struct listnode *node;
@@ -394,23 +383,24 @@ isis_root_system_lsp (struct isis_area *area, int level, u_char *sysid)
* Add this IS to the root of SPT
*/
static struct isis_vertex *
-isis_spf_add_root (struct isis_spftree *spftree, int level, u_char *sysid)
+isis_spf_add_root (struct isis_spftree *spftree, u_char *sysid)
{
struct isis_vertex *vertex;
struct isis_lsp *lsp;
#ifdef EXTREME_DEBUG
char buff[PREFIX2STR_BUFFER];
#endif /* EXTREME_DEBUG */
+ u_char id[ISIS_SYS_ID_LEN + 1];
- lsp = isis_root_system_lsp (spftree->area, level, sysid);
- if (lsp == NULL)
- zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level);
+ memcpy(id, sysid, ISIS_SYS_ID_LEN);
+ LSP_PSEUDO_ID(id) = 0;
- if (!spftree->area->oldmetric)
- vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_TE_IS);
- else
- vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_IS);
+ lsp = isis_root_system_lsp (spftree->area, spftree->level, sysid);
+ if (lsp == NULL)
+ zlog_warn ("ISIS-Spf: could not find own l%d LSP!", spftree->level);
+ vertex = isis_vertex_new (id, spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS
+ : VTYPE_NONPSEUDO_TE_IS);
listnode_add (spftree->paths, vertex);
#ifdef EXTREME_DEBUG
@@ -432,44 +422,51 @@ isis_find_vertex (struct list *list, void *id, enum vertextype vtype)
for (ALL_LIST_ELEMENTS_RO (list, node, vertex))
{
if (vertex->type != vtype)
- continue;
- switch (vtype)
- {
- case VTYPE_ES:
- case VTYPE_NONPSEUDO_IS:
- case VTYPE_NONPSEUDO_TE_IS:
- if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN) == 0)
- return vertex;
- break;
- case VTYPE_PSEUDO_IS:
- case VTYPE_PSEUDO_TE_IS:
- if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0)
- return vertex;
- break;
- case VTYPE_IPREACH_INTERNAL:
- case VTYPE_IPREACH_EXTERNAL:
- case VTYPE_IPREACH_TE:
- case VTYPE_IP6REACH_INTERNAL:
- case VTYPE_IP6REACH_EXTERNAL:
- p1 = (struct prefix *) id;
- p2 = (struct prefix *) &vertex->N.id;
- if (p1->family == p2->family && p1->prefixlen == p2->prefixlen &&
- memcmp (&p1->u.prefix, &p2->u.prefix,
- PSIZE (p1->prefixlen)) == 0)
- return vertex;
- break;
- }
+ continue;
+ if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type))
+ {
+ if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0)
+ return vertex;
+ }
+ if (VTYPE_IP(vertex->type))
+ {
+ p1 = (struct prefix *) id;
+ p2 = (struct prefix *) &vertex->N.id;
+ if (p1->family == p2->family
+ && p1->prefixlen == p2->prefixlen
+ && !memcmp(&p1->u.prefix, &p2->u.prefix, PSIZE (p1->prefixlen)))
+ {
+ return vertex;
+ }
+ }
}
return NULL;
}
/*
+ * Compares vertizes for sorting in the TENT list. Returns true
+ * if candidate should be considered before current, false otherwise.
+ */
+static bool
+tent_cmp (struct isis_vertex *current, struct isis_vertex *candidate)
+{
+ if (current->d_N > candidate->d_N)
+ return true;
+
+ if (current->d_N == candidate->d_N
+ && current->type > candidate->type)
+ return true;
+
+ return false;
+}
+
+/*
* Add a vertex to TENT sorted by cost and by vertextype on tie break situation
*/
static struct isis_vertex *
isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
- void *id, uint32_t cost, int depth, int family,
+ void *id, uint32_t cost, int depth,
struct isis_adjacency *adj, struct isis_vertex *parent)
{
struct isis_vertex *vertex, *v;
@@ -515,17 +512,11 @@ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
for (node = listhead (spftree->tents); node; node = listnextnode (node))
{
v = listgetdata (node);
- if (v->d_N > vertex->d_N)
- {
- listnode_add_before (spftree->tents, node, vertex);
- break;
- }
- else if (v->d_N == vertex->d_N && v->type > vertex->type)
- {
- /* Tie break, add according to type */
+ if (tent_cmp(v, vertex))
+ {
listnode_add_before (spftree->tents, node, vertex);
- break;
- }
+ break;
+ }
}
if (node == NULL)
@@ -537,7 +528,7 @@ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
static void
isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
void *id, struct isis_adjacency *adj, uint32_t cost,
- int family, struct isis_vertex *parent)
+ struct isis_vertex *parent)
{
struct isis_vertex *vertex;
@@ -576,13 +567,13 @@ isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
}
}
- isis_spf_add2tent (spftree, vtype, id, cost, 1, family, adj, parent);
+ isis_spf_add2tent (spftree, vtype, id, cost, 1, adj, parent);
return;
}
static void
process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
- uint32_t dist, uint16_t depth, int family,
+ uint32_t dist, uint16_t depth,
struct isis_vertex *parent)
{
struct isis_vertex *vertex;
@@ -670,7 +661,7 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
(parent ? print_sys_hostname (parent->N.id) : "null"));
#endif /* EXTREME_DEBUG */
- isis_spf_add2tent (spftree, vtype, id, dist, depth, family, NULL, parent);
+ isis_spf_add2tent (spftree, vtype, id, dist, depth, NULL, parent);
return;
}
@@ -679,9 +670,10 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
*/
static int
isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
- uint32_t cost, uint16_t depth, int family,
+ uint32_t cost, uint16_t depth,
u_char *root_sysid, struct isis_vertex *parent)
{
+ bool pseudo_lsp = LSP_PSEUDO_ID(lsp->lsp_header->lsp_id);
struct listnode *node, *fragnode = NULL;
uint32_t dist;
struct is_neigh *is_neigh;
@@ -692,8 +684,14 @@ isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
struct prefix prefix;
struct ipv6_reachability *ip6reach;
static const u_char null_sysid[ISIS_SYS_ID_LEN];
+ struct mt_router_info *mt_router_info = NULL;
+
+ if (spftree->mtid != ISIS_MT_IPV4_UNICAST)
+ mt_router_info = tlvs_lookup_mt_router_info(&lsp->tlv_data, spftree->mtid);
- if (!speaks (lsp->tlv_data.nlpids, family))
+ if (!pseudo_lsp
+ && (spftree->mtid == ISIS_MT_IPV4_UNICAST && !speaks(lsp->tlv_data.nlpids, spftree->family))
+ && !mt_router_info)
return ISIS_OK;
lspfragloop:
@@ -707,9 +705,13 @@ lspfragloop:
zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id));
#endif /* EXTREME_DEBUG */
- if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
+ /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
+ if (pseudo_lsp
+ || (spftree->mtid == ISIS_MT_IPV4_UNICAST && !ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
+ || (mt_router_info && !mt_router_info->overload))
+
{
- if (lsp->tlv_data.is_neighs)
+ if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
{
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
{
@@ -717,95 +719,126 @@ lspfragloop:
/* Two way connectivity */
if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
continue;
- if (!memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
+ if (!pseudo_lsp && !memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
continue;
dist = cost + is_neigh->metrics.metric_default;
- vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
- : VTYPE_NONPSEUDO_IS;
- process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
- depth + 1, family, parent);
+ process_N (spftree, LSP_PSEUDO_ID(is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
+ : VTYPE_NONPSEUDO_IS,
+ (void *) is_neigh->neigh_id, dist, depth + 1, parent);
}
}
- if (lsp->tlv_data.te_is_neighs)
- {
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node,
- te_is_neigh))
+
+ struct list *te_is_neighs = NULL;
+ if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
+ {
+ te_is_neighs = lsp->tlv_data.te_is_neighs;
+ }
+ else
+ {
+ struct tlv_mt_neighbors *mt_neighbors;
+ mt_neighbors = tlvs_lookup_mt_neighbors(&lsp->tlv_data, spftree->mtid);
+ if (mt_neighbors)
+ te_is_neighs = mt_neighbors->list;
+ }
+ for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
{
if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
continue;
- if (!memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
+ if (!pseudo_lsp && !memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
continue;
dist = cost + GET_TE_METRIC(te_is_neigh);
- vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
- : VTYPE_NONPSEUDO_TE_IS;
- process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
- depth + 1, family, parent);
+ process_N (spftree, LSP_PSEUDO_ID(te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
+ : VTYPE_NONPSEUDO_TE_IS,
+ (void *) te_is_neigh->neigh_id, dist, depth + 1, parent);
}
- }
}
- if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs)
- {
- prefix.family = AF_INET;
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, node, ipreach))
- {
- dist = cost + ipreach->metrics.metric_default;
- vtype = VTYPE_IPREACH_INTERNAL;
- prefix.u.prefix4 = ipreach->prefix;
- prefix.prefixlen = ip_masklen (ipreach->mask);
- apply_mask (&prefix);
- process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
- family, parent);
- }
- }
- if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs)
+ if (!pseudo_lsp
+ && spftree->family == AF_INET
+ && spftree->mtid == ISIS_MT_IPV4_UNICAST)
{
+ struct list *reachs[] = {lsp->tlv_data.ipv4_int_reachs,
+ lsp->tlv_data.ipv4_ext_reachs};
+
prefix.family = AF_INET;
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, node, ipreach))
- {
- dist = cost + ipreach->metrics.metric_default;
- vtype = VTYPE_IPREACH_EXTERNAL;
- prefix.u.prefix4 = ipreach->prefix;
- prefix.prefixlen = ip_masklen (ipreach->mask);
- apply_mask (&prefix);
- process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
- family, parent);
- }
+ for (unsigned int i = 0; i < array_size(reachs); i++)
+ {
+ vtype = (reachs[i] == lsp->tlv_data.ipv4_int_reachs) ? VTYPE_IPREACH_INTERNAL
+ : VTYPE_IPREACH_EXTERNAL;
+ for (ALL_LIST_ELEMENTS_RO (reachs[i], node, ipreach))
+ {
+ dist = cost + ipreach->metrics.metric_default;
+ prefix.u.prefix4 = ipreach->prefix;
+ prefix.prefixlen = ip_masklen (ipreach->mask);
+ apply_mask (&prefix);
+ process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
+ parent);
+ }
+ }
}
- if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs)
+
+ if (!pseudo_lsp && spftree->family == AF_INET)
{
+ struct list *ipv4reachs = NULL;
+
+ if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
+ {
+ ipv4reachs = lsp->tlv_data.te_ipv4_reachs;
+ }
+ else
+ {
+ struct tlv_mt_ipv4_reachs *mt_reachs;
+ mt_reachs = tlvs_lookup_mt_ipv4_reachs(&lsp->tlv_data, spftree->mtid);
+ if (mt_reachs)
+ ipv4reachs = mt_reachs->list;
+ }
+
prefix.family = AF_INET;
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs,
- node, te_ipv4_reach))
+ for (ALL_LIST_ELEMENTS_RO (ipv4reachs, node, te_ipv4_reach))
{
assert ((te_ipv4_reach->control & 0x3F) <= IPV4_MAX_BITLEN);
dist = cost + ntohl (te_ipv4_reach->te_metric);
- vtype = VTYPE_IPREACH_TE;
prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start,
te_ipv4_reach->control);
prefix.prefixlen = (te_ipv4_reach->control & 0x3F);
apply_mask (&prefix);
- process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
- family, parent);
+ process_N (spftree, VTYPE_IPREACH_TE, (void *) &prefix, dist, depth + 1,
+ parent);
}
}
- if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs)
+
+ if (!pseudo_lsp
+ && spftree->family == AF_INET6)
{
+ struct list *ipv6reachs = NULL;
+
+ if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
+ {
+ ipv6reachs = lsp->tlv_data.ipv6_reachs;
+ }
+ else
+ {
+ struct tlv_mt_ipv6_reachs *mt_reachs;
+ mt_reachs = tlvs_lookup_mt_ipv6_reachs(&lsp->tlv_data, spftree->mtid);
+ if (mt_reachs)
+ ipv6reachs = mt_reachs->list;
+ }
+
prefix.family = AF_INET6;
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, node, ip6reach))
+ for (ALL_LIST_ELEMENTS_RO (ipv6reachs, node, ip6reach))
{
assert (ip6reach->prefix_len <= IPV6_MAX_BITLEN);
dist = cost + ntohl(ip6reach->metric);
vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ?
- VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
+ VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
prefix.prefixlen = ip6reach->prefix_len;
memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
PSIZE (ip6reach->prefix_len));
apply_mask (&prefix);
process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
- family, parent);
+ parent);
}
}
@@ -824,76 +857,8 @@ lspfragloop:
}
static int
-isis_spf_process_pseudo_lsp (struct isis_spftree *spftree,
- struct isis_lsp *lsp, uint32_t cost,
- uint16_t depth, int family,
- u_char *root_sysid,
- struct isis_vertex *parent)
-{
- struct listnode *node, *fragnode = NULL;
- struct is_neigh *is_neigh;
- struct te_is_neigh *te_is_neigh;
- enum vertextype vtype;
- uint32_t dist;
-
-pseudofragloop:
-
- if (lsp->lsp_header->seq_num == 0)
- {
- zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num"
- " - do not process");
- return ISIS_WARNING;
- }
-
-#ifdef EXTREME_DEBUG
- zlog_debug ("ISIS-Spf: process_pseudo_lsp %s",
- print_sys_hostname(lsp->lsp_header->lsp_id));
-#endif /* EXTREME_DEBUG */
-
- /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
-
- if (lsp->tlv_data.is_neighs)
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
- {
- /* Two way connectivity */
- if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
- continue;
- dist = cost + is_neigh->metrics.metric_default;
- vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
- : VTYPE_NONPSEUDO_IS;
- process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
- depth + 1, family, parent);
- }
- if (lsp->tlv_data.te_is_neighs)
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh))
- {
- /* Two way connectivity */
- if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
- continue;
- dist = cost + GET_TE_METRIC(te_is_neigh);
- vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
- : VTYPE_NONPSEUDO_TE_IS;
- process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
- depth + 1, family, parent);
- }
-
- if (fragnode == NULL)
- fragnode = listhead (lsp->lspu.frags);
- else
- fragnode = listnextnode (fragnode);
-
- if (fragnode)
- {
- lsp = listgetdata (fragnode);
- goto pseudofragloop;
- }
-
- return ISIS_OK;
-}
-
-static int
-isis_spf_preload_tent (struct isis_spftree *spftree, int level,
- int family, u_char *root_sysid,
+isis_spf_preload_tent (struct isis_spftree *spftree,
+ u_char *root_sysid,
struct isis_vertex *parent)
{
struct isis_circuit *circuit;
@@ -908,21 +873,25 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level,
u_char lsp_id[ISIS_SYS_ID_LEN + 2];
static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2];
struct prefix_ipv6 *ipv6;
+ struct isis_circuit_mt_setting *circuit_mt;
for (ALL_LIST_ELEMENTS_RO (spftree->area->circuit_list, cnode, circuit))
{
+ circuit_mt = circuit_lookup_mt_setting(circuit, spftree->mtid);
+ if (circuit_mt && !circuit_mt->enabled)
+ continue;
if (circuit->state != C_STATE_UP)
continue;
- if (!(circuit->is_type & level))
+ if (!(circuit->is_type & spftree->level))
continue;
- if (family == AF_INET && !circuit->ip_router)
+ if (spftree->family == AF_INET && !circuit->ip_router)
continue;
- if (family == AF_INET6 && !circuit->ipv6_router)
+ if (spftree->family == AF_INET6 && !circuit->ipv6_router)
continue;
/*
* Add IP(v6) addresses of this circuit
*/
- if (family == AF_INET)
+ if (spftree->family == AF_INET)
{
prefix.family = AF_INET;
for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
@@ -931,10 +900,10 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level,
prefix.prefixlen = ipv4->prefixlen;
apply_mask (&prefix);
isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix,
- NULL, 0, family, parent);
+ NULL, 0, parent);
}
}
- if (family == AF_INET6)
+ if (spftree->family == AF_INET6)
{
prefix.family = AF_INET6;
for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
@@ -943,7 +912,7 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level,
prefix.u.prefix6 = ipv6->prefix;
apply_mask (&prefix);
isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL,
- &prefix, NULL, 0, family, parent);
+ &prefix, NULL, 0, parent);
}
}
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
@@ -952,45 +921,46 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level,
* Add the adjacencies
*/
adj_list = list_new ();
- adjdb = circuit->u.bc.adjdb[level - 1];
+ adjdb = circuit->u.bc.adjdb[spftree->level - 1];
isis_adj_build_up_list (adjdb, adj_list);
if (listcount (adj_list) == 0)
{
list_delete (adj_list);
if (isis->debugs & DEBUG_SPF_EVENTS)
zlog_debug ("ISIS-Spf: no L%d adjacencies on circuit %s",
- level, circuit->interface->name);
+ spftree->level, circuit->interface->name);
continue;
}
for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj))
{
- if (!speaks (&adj->nlpids, family))
- continue;
+ if (!adj_has_mt(adj, spftree->mtid))
+ continue;
+ if (spftree->mtid == ISIS_MT_IPV4_UNICAST && !speaks (&adj->nlpids, spftree->family))
+ continue;
switch (adj->sys_type)
{
case ISIS_SYSTYPE_ES:
isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
- circuit->te_metric[level - 1],
- family, parent);
+ circuit->te_metric[spftree->level - 1],
+ parent);
break;
case ISIS_SYSTYPE_IS:
case ISIS_SYSTYPE_L1_IS:
case ISIS_SYSTYPE_L2_IS:
- isis_spf_add_local (spftree,
- spftree->area->oldmetric ?
- VTYPE_NONPSEUDO_IS :
- VTYPE_NONPSEUDO_TE_IS,
- adj->sysid, adj,
- circuit->te_metric[level - 1],
- family, parent);
memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID (lsp_id) = 0;
LSP_FRAGMENT (lsp_id) = 0;
- lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
+ isis_spf_add_local (spftree,
+ spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS
+ : VTYPE_NONPSEUDO_TE_IS,
+ lsp_id, adj,
+ circuit->te_metric[spftree->level - 1],
+ parent);
+ lsp = lsp_search (lsp_id, spftree->area->lspdb[spftree->level - 1]);
if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency "
"L%d on %s (ID %u)",
- rawlspid_print (lsp_id), level,
+ rawlspid_print (lsp_id), spftree->level,
circuit->interface->name, circuit->circuit_id);
break;
case ISIS_SYSTYPE_UNKNOWN:
@@ -1002,7 +972,7 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level,
/*
* Add the pseudonode
*/
- if (level == 1)
+ if (spftree->level == 1)
memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
else
memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
@@ -1011,55 +981,59 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level,
{
if (isis->debugs & DEBUG_SPF_EVENTS)
zlog_debug ("ISIS-Spf: No L%d DR on %s (ID %d)",
- level, circuit->interface->name, circuit->circuit_id);
+ spftree->level, circuit->interface->name, circuit->circuit_id);
continue;
}
adj = isis_adj_lookup (lsp_id, adjdb);
/* if no adj, we are the dis or error */
- if (!adj && !circuit->u.bc.is_dr[level - 1])
+ if (!adj && !circuit->u.bc.is_dr[spftree->level - 1])
{
zlog_warn ("ISIS-Spf: No adjacency found from root "
"to L%d DR %s on %s (ID %d)",
- level, rawlspid_print (lsp_id),
+ spftree->level, rawlspid_print (lsp_id),
circuit->interface->name, circuit->circuit_id);
continue;
}
- lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
+ lsp = lsp_search (lsp_id, spftree->area->lspdb[spftree->level - 1]);
if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
{
zlog_warn ("ISIS-Spf: No lsp (%p) found from root "
"to L%d DR %s on %s (ID %d)",
- (void *)lsp, level, rawlspid_print (lsp_id),
+ (void *)lsp, spftree->level, rawlspid_print (lsp_id),
circuit->interface->name, circuit->circuit_id);
continue;
}
- isis_spf_process_pseudo_lsp (spftree, lsp,
- circuit->te_metric[level - 1], 0,
- family, root_sysid, parent);
+ isis_spf_process_lsp (spftree, lsp,
+ circuit->te_metric[spftree->level - 1], 0,
+ root_sysid, parent);
}
else if (circuit->circ_type == CIRCUIT_T_P2P)
{
adj = circuit->u.p2p.neighbor;
if (!adj)
continue;
+ if (!adj_has_mt(adj, spftree->mtid))
+ continue;
switch (adj->sys_type)
{
case ISIS_SYSTYPE_ES:
isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
- circuit->te_metric[level - 1], family,
+ circuit->te_metric[spftree->level - 1],
parent);
break;
case ISIS_SYSTYPE_IS:
case ISIS_SYSTYPE_L1_IS:
case ISIS_SYSTYPE_L2_IS:
- if (speaks (&adj->nlpids, family))
+ memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
+ LSP_PSEUDO_ID (lsp_id) = 0;
+ LSP_FRAGMENT (lsp_id) = 0;
+ if (spftree->mtid != ISIS_MT_IPV4_UNICAST || speaks (&adj->nlpids, spftree->family))
isis_spf_add_local (spftree,
- spftree->area->oldmetric ?
- VTYPE_NONPSEUDO_IS :
- VTYPE_NONPSEUDO_TE_IS,
- adj->sysid,
- adj, circuit->te_metric[level - 1],
- family, parent);
+ spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS
+ : VTYPE_NONPSEUDO_TE_IS,
+ lsp_id,
+ adj, circuit->te_metric[spftree->level - 1],
+ parent);
break;
case ISIS_SYSTYPE_UNKNOWN:
default:
@@ -1086,8 +1060,7 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level,
* now we just put the child pointer(s) in place
*/
static void
-add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
- int level)
+add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex)
{
char buff[PREFIX2STR_BUFFER];
@@ -1102,11 +1075,11 @@ add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
vertex->depth, vertex->d_N);
#endif /* EXTREME_DEBUG */
- if (vertex->type > VTYPE_ES)
+ if (VTYPE_IP(vertex->type))
{
if (listcount (vertex->Adj_N) > 0)
isis_route_create ((struct prefix *) &vertex->N.prefix, vertex->d_N,
- vertex->depth, vertex->Adj_N, spftree->area, level);
+ vertex->depth, vertex->Adj_N, spftree->area, spftree->level);
else if (isis->debugs & DEBUG_SPF_EVENTS)
zlog_debug ("ISIS-Spf: no adjacencies do not install route for "
"%s depth %d dist %d", vid2string (vertex, buff, sizeof (buff)),
@@ -1117,12 +1090,16 @@ add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
}
static void
-init_spt (struct isis_spftree *spftree)
+init_spt (struct isis_spftree *spftree, int mtid, int level, int family)
{
spftree->tents->del = spftree->paths->del = (void (*)(void *)) isis_vertex_del;
list_delete_all_node (spftree->tents);
list_delete_all_node (spftree->paths);
spftree->tents->del = spftree->paths->del = NULL;
+
+ spftree->mtid = mtid;
+ spftree->level = level;
+ spftree->family = family;
return;
}
@@ -1139,6 +1116,7 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
struct route_table *table = NULL;
struct timeval time_now;
unsigned long long start_time, end_time;
+ uint16_t mtid;
/* Get time that can't roll backwards. */
monotime(&time_now);
@@ -1160,14 +1138,20 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
isis_route_invalidate_table (area, table);
+ /* We only support ipv4-unicast and ipv6-unicast as topologies for now */
+ if (family == AF_INET6)
+ mtid = isis_area_ipv6_topology(area);
+ else
+ mtid = ISIS_MT_IPV4_UNICAST;
+
/*
* C.2.5 Step 0
*/
- init_spt (spftree);
+ init_spt (spftree, mtid, level, family);
/* a) */
- root_vertex = isis_spf_add_root (spftree, level, sysid);
+ root_vertex = isis_spf_add_root (spftree, sysid);
/* b) */
- retval = isis_spf_preload_tent (spftree, level, family, sysid, root_vertex);
+ retval = isis_spf_preload_tent (spftree, sysid, root_vertex);
if (retval != ISIS_OK)
{
zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid));
@@ -1196,37 +1180,22 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
/* Remove from tent list and add to paths list */
list_delete_node (spftree->tents, node);
- add_to_paths (spftree, vertex, level);
- switch (vertex->type)
+ add_to_paths (spftree, vertex);
+ if (VTYPE_IS(vertex->type))
{
- case VTYPE_PSEUDO_IS:
- case VTYPE_NONPSEUDO_IS:
- case VTYPE_PSEUDO_TE_IS:
- case VTYPE_NONPSEUDO_TE_IS:
memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
LSP_FRAGMENT (lsp_id) = 0;
lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
if (lsp && lsp->lsp_header->rem_lifetime != 0)
{
- if (LSP_PSEUDO_ID (lsp_id))
- {
- isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N,
- vertex->depth, family, sysid,
- vertex);
- }
- else
- {
- isis_spf_process_lsp (spftree, lsp, vertex->d_N,
- vertex->depth, family, sysid, vertex);
- }
+ isis_spf_process_lsp (spftree, lsp, vertex->d_N,
+ vertex->depth, sysid, vertex);
}
else
{
zlog_warn ("ISIS-Spf: No LSP found for %s",
rawlspid_print (lsp_id));
}
- break;
- default:;
}
}
@@ -1243,17 +1212,17 @@ out:
}
static int
-isis_run_spf_l1 (struct thread *thread)
+isis_run_spf_cb (struct thread *thread)
{
- struct isis_area *area;
+ struct isis_spf_run *run = THREAD_ARG (thread);
+ struct isis_area *area = run->area;
+ int level = run->level;
int retval = ISIS_OK;
- area = THREAD_ARG (thread);
- assert (area);
+ XFREE(MTYPE_ISIS_SPF_RUN, run);
+ area->spf_timer[level - 1] = NULL;
- area->spf_timer[0] = NULL;
-
- if (!(area->is_type & IS_LEVEL_1))
+ if (!(area->is_type & level))
{
if (isis->debugs & DEBUG_SPF_EVENTS)
zlog_warn ("ISIS-SPF (%s) area does not share level",
@@ -1262,43 +1231,26 @@ isis_run_spf_l1 (struct thread *thread)
}
if (isis->debugs & DEBUG_SPF_EVENTS)
- zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
+ zlog_debug ("ISIS-Spf (%s) L%d SPF needed, periodic SPF",
+ area->area_tag, level);
if (area->ip_circuits)
- retval = isis_run_spf (area, 1, AF_INET, isis->sysid);
+ retval = isis_run_spf (area, level, AF_INET, isis->sysid);
if (area->ipv6_circuits)
- retval = isis_run_spf (area, 1, AF_INET6, isis->sysid);
+ retval = isis_run_spf (area, level, AF_INET6, isis->sysid);
return retval;
}
-static int
-isis_run_spf_l2 (struct thread *thread)
+static struct isis_spf_run*
+isis_run_spf_arg(struct isis_area *area, int level)
{
- struct isis_area *area;
- int retval = ISIS_OK;
-
- area = THREAD_ARG (thread);
- assert (area);
+ struct isis_spf_run *run = XMALLOC(MTYPE_ISIS_SPF_RUN, sizeof(*run));
- area->spf_timer[1] = NULL;
+ run->area = area;
+ run->level = level;
- 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 (isis->debugs & DEBUG_SPF_EVENTS)
- zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
-
- 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;
+ return run;
}
int
@@ -1323,16 +1275,9 @@ isis_spf_schedule (struct isis_area *area, int level)
if (area->spf_timer[level - 1])
return ISIS_OK;
- 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);
- }
+ THREAD_TIMER_MSEC_ON(master, area->spf_timer[level-1],
+ isis_run_spf_cb, isis_run_spf_arg(area, level),
+ delay);
return ISIS_OK;
}
@@ -1352,12 +1297,9 @@ isis_spf_schedule (struct isis_area *area, int level)
return retval;
}
- if (level == 1)
- THREAD_TIMER_ON (master, area->spf_timer[0], isis_run_spf_l1, area,
- area->min_spf_interval[0] - diff);
- else
- THREAD_TIMER_ON (master, area->spf_timer[1], isis_run_spf_l2, area,
- area->min_spf_interval[1] - diff);
+ THREAD_TIMER_ON (master, area->spf_timer[level-1],
+ isis_run_spf_cb, isis_run_spf_arg(area, level),
+ area->min_spf_interval[level-1] - diff);
if (isis->debugs & DEBUG_SPF_EVENTS)
zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
@@ -1427,14 +1369,23 @@ isis_print_paths (struct vty *vty, struct list *paths, u_char *root_sysid)
DEFUN (show_isis_topology,
show_isis_topology_cmd,
- "show isis topology",
+ "show isis topology [<level-1|level-2>]",
SHOW_STR
"IS-IS information\n"
- "IS-IS paths to Intermediate Systems\n")
+ "IS-IS paths to Intermediate Systems\n"
+ "Paths to all level-1 routers in the area\n"
+ "Paths to all level-2 routers in the domain\n")
{
+ int levels;
struct listnode *node;
struct isis_area *area;
- int level;
+
+ if (argc < 4)
+ levels = ISIS_LEVEL1|ISIS_LEVEL2;
+ else if (!strcmp(argv[3]->arg, "level-1"))
+ levels = ISIS_LEVEL1;
+ else
+ levels = ISIS_LEVEL2;
if (!isis->area_list || isis->area_list->count == 0)
return CMD_SUCCESS;
@@ -1444,23 +1395,26 @@ DEFUN (show_isis_topology,
vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
VTY_NEWLINE);
- for (level = 0; level < ISIS_LEVELS; level++)
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
{
- if (area->ip_circuits > 0 && area->spftree[level]
- && area->spftree[level]->paths->count > 0)
+ if ((level & levels) == 0)
+ continue;
+
+ if (area->ip_circuits > 0 && area->spftree[level-1]
+ && area->spftree[level-1]->paths->count > 0)
{
vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s",
- level + 1, VTY_NEWLINE);
- isis_print_paths (vty, area->spftree[level]->paths, isis->sysid);
+ level, VTY_NEWLINE);
+ isis_print_paths (vty, area->spftree[level-1]->paths, isis->sysid);
vty_out (vty, "%s", VTY_NEWLINE);
}
- if (area->ipv6_circuits > 0 && area->spftree6[level]
- && area->spftree6[level]->paths->count > 0)
+ if (area->ipv6_circuits > 0 && area->spftree6[level-1]
+ && area->spftree6[level-1]->paths->count > 0)
{
vty_out (vty,
"IS-IS paths to level-%d routers that speak IPv6%s",
- level + 1, VTY_NEWLINE);
- isis_print_paths (vty, area->spftree6[level]->paths, isis->sysid);
+ level, VTY_NEWLINE);
+ isis_print_paths (vty, area->spftree6[level-1]->paths, isis->sysid);
vty_out (vty, "%s", VTY_NEWLINE);
}
}
@@ -1471,92 +1425,8 @@ DEFUN (show_isis_topology,
return CMD_SUCCESS;
}
-DEFUN (show_isis_topology_l1,
- show_isis_topology_l1_cmd,
- "show isis topology level-1",
- SHOW_STR
- "IS-IS information\n"
- "IS-IS paths to Intermediate Systems\n"
- "Paths to all level-1 routers in the area\n")
-{
- struct listnode *node;
- struct isis_area *area;
-
- if (!isis->area_list || isis->area_list->count == 0)
- return CMD_SUCCESS;
-
- 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);
-
- if (area->ip_circuits > 0 && area->spftree[0]
- && area->spftree[0]->paths->count > 0)
- {
- vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s",
- VTY_NEWLINE);
- isis_print_paths (vty, area->spftree[0]->paths, isis->sysid);
- vty_out (vty, "%s", VTY_NEWLINE);
- }
- if (area->ipv6_circuits > 0 && area->spftree6[0]
- && area->spftree6[0]->paths->count > 0)
- {
- vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s",
- VTY_NEWLINE);
- isis_print_paths (vty, area->spftree6[0]->paths, isis->sysid);
- vty_out (vty, "%s", VTY_NEWLINE);
- }
- vty_out (vty, "%s", VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN (show_isis_topology_l2,
- show_isis_topology_l2_cmd,
- "show isis topology level-2",
- SHOW_STR
- "IS-IS information\n"
- "IS-IS paths to Intermediate Systems\n"
- "Paths to all level-2 routers in the domain\n")
-{
- struct listnode *node;
- struct isis_area *area;
-
- if (!isis->area_list || isis->area_list->count == 0)
- return CMD_SUCCESS;
-
- 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);
-
- if (area->ip_circuits > 0 && area->spftree[1]
- && area->spftree[1]->paths->count > 0)
- {
- vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s",
- VTY_NEWLINE);
- isis_print_paths (vty, area->spftree[1]->paths, isis->sysid);
- vty_out (vty, "%s", VTY_NEWLINE);
- }
- if (area->ipv6_circuits > 0 && area->spftree6[1]
- && area->spftree6[1]->paths->count > 0)
- {
- vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s",
- VTY_NEWLINE);
- isis_print_paths (vty, area->spftree6[1]->paths, isis->sysid);
- vty_out (vty, "%s", VTY_NEWLINE);
- }
- vty_out (vty, "%s", VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
-}
-
void
isis_spf_cmds_init ()
{
install_element (VIEW_NODE, &show_isis_topology_cmd);
- install_element (VIEW_NODE, &show_isis_topology_l1_cmd);
- install_element (VIEW_NODE, &show_isis_topology_l2_cmd);
}
diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h
index fb534542d..9f06dbb60 100644
--- a/isisd/isis_spf.h
+++ b/isisd/isis_spf.h
@@ -38,6 +38,10 @@ enum vertextype
VTYPE_IP6REACH_EXTERNAL
};
+#define VTYPE_IS(t) ((t) >= VTYPE_PSEUDO_IS && (t) <= VTYPE_NONPSEUDO_TE_IS)
+#define VTYPE_ES(t) ((t) == VTYPE_ES)
+#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL)
+
/*
* Triple <N, d(N), {Adj(N)}>
*/
@@ -66,12 +70,14 @@ struct isis_spftree
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 */
+
+ uint16_t mtid;
+ int family;
+ int level;
};
struct isis_spftree * isis_spftree_new (struct isis_area *area);
void isis_spftree_del (struct isis_spftree *spftree);
-void isis_spftree_adj_del (struct isis_spftree *spftree,
- struct isis_adjacency *adj);
void spftree_area_init (struct isis_area *area);
void spftree_area_del (struct isis_area *area);
void spftree_area_adj_del (struct isis_area *area,
diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c
index 4192fff9a..b033e35a2 100644
--- a/isisd/isis_tlv.c
+++ b/isisd/isis_tlv.c
@@ -43,6 +43,7 @@
#include "isisd/isis_pdu.h"
#include "isisd/isis_lsp.h"
#include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
void
free_tlv (void *val)
@@ -61,10 +62,14 @@ free_tlvs (struct tlvs *tlvs)
{
if (tlvs->area_addrs)
list_delete (tlvs->area_addrs);
+ if (tlvs->mt_router_info)
+ list_delete (tlvs->mt_router_info);
if (tlvs->is_neighs)
list_delete (tlvs->is_neighs);
if (tlvs->te_is_neighs)
list_delete (tlvs->te_is_neighs);
+ if (tlvs->mt_is_neighs)
+ list_delete (tlvs->mt_is_neighs);
if (tlvs->es_neighs)
list_delete (tlvs->es_neighs);
if (tlvs->lsp_entries)
@@ -81,16 +86,293 @@ free_tlvs (struct tlvs *tlvs)
list_delete (tlvs->ipv4_ext_reachs);
if (tlvs->te_ipv4_reachs)
list_delete (tlvs->te_ipv4_reachs);
+ if (tlvs->mt_ipv4_reachs)
+ list_delete (tlvs->mt_ipv4_reachs);
if (tlvs->ipv6_addrs)
list_delete (tlvs->ipv6_addrs);
if (tlvs->ipv6_reachs)
list_delete (tlvs->ipv6_reachs);
+ if (tlvs->mt_ipv6_reachs)
+ list_delete (tlvs->mt_ipv6_reachs);
memset (tlvs, 0, sizeof (struct tlvs));
return;
}
+static int
+parse_mtid(uint16_t *mtid, bool read_mtid,
+ unsigned int *length, u_char **pnt)
+{
+ if (!read_mtid)
+ {
+ *mtid = ISIS_MT_IPV4_UNICAST;
+ return ISIS_OK;
+ }
+
+ uint16_t mtid_buf;
+
+ if (*length < sizeof(mtid_buf))
+ {
+ zlog_warn("ISIS-TLV: mt tlv too short to contain MT id");
+ return ISIS_WARNING;
+ }
+
+ memcpy(&mtid_buf, *pnt, sizeof(mtid_buf));
+ *pnt += sizeof(mtid_buf);
+ *length -= sizeof(mtid_buf);
+
+ *mtid = ntohs(mtid_buf) & ISIS_MT_MASK;
+ return ISIS_OK;
+}
+
+static int
+parse_mt_is_neighs(struct tlvs *tlvs, bool read_mtid,
+ unsigned int length, u_char *pnt)
+{
+ struct list *neigh_list;
+ uint16_t mtid;
+ int rv;
+
+ rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
+ if (rv != ISIS_OK)
+ return rv;
+
+ if (mtid == ISIS_MT_IPV4_UNICAST)
+ {
+ if (!tlvs->te_is_neighs)
+ {
+ tlvs->te_is_neighs = list_new();
+ tlvs->te_is_neighs->del = free_tlv;
+ }
+ neigh_list = tlvs->te_is_neighs;
+ }
+ else
+ {
+ struct tlv_mt_neighbors *neighbors;
+
+ neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
+ neighbors->list->del = free_tlv;
+ neigh_list = neighbors->list;
+ }
+
+ while (length >= IS_NEIGHBOURS_LEN)
+ {
+ struct te_is_neigh *neigh = XCALLOC(MTYPE_ISIS_TLV, sizeof(*neigh));
+
+ memcpy(neigh, pnt, IS_NEIGHBOURS_LEN);
+ pnt += IS_NEIGHBOURS_LEN;
+ length -= IS_NEIGHBOURS_LEN;
+
+ if (neigh->sub_tlvs_length > length)
+ {
+ zlog_warn("ISIS-TLV: neighbor subtlv length exceeds TLV size");
+ XFREE(MTYPE_ISIS_TLV, neigh);
+ return ISIS_WARNING;
+ }
+
+ memcpy(neigh->sub_tlvs, pnt, neigh->sub_tlvs_length);
+ pnt += neigh->sub_tlvs_length;
+ length -= neigh->sub_tlvs_length;
+
+ listnode_add(neigh_list, neigh);
+ }
+
+ if (length)
+ {
+ zlog_warn("ISIS-TLV: TE/MT neighor TLV has trailing data");
+ return ISIS_WARNING;
+ }
+
+ return ISIS_OK;
+}
+
+static int
+parse_mt_ipv4_reachs(struct tlvs *tlvs, bool read_mtid,
+ unsigned int length, u_char *pnt)
+{
+ struct list *reach_list;
+ uint16_t mtid;
+ int rv;
+
+ rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
+ if (rv != ISIS_OK)
+ return rv;
+
+ if (mtid == ISIS_MT_IPV4_UNICAST)
+ {
+ if (!tlvs->te_ipv4_reachs)
+ {
+ tlvs->te_ipv4_reachs = list_new();
+ tlvs->te_ipv4_reachs->del = free_tlv;
+ }
+ reach_list = tlvs->te_ipv4_reachs;
+ }
+ else
+ {
+ struct tlv_mt_ipv4_reachs *reachs;
+
+ reachs = tlvs_get_mt_ipv4_reachs(tlvs, mtid);
+ reachs->list->del = free_tlv;
+ reach_list = reachs->list;
+ }
+
+ while (length >= 5) /* Metric + Control */
+ {
+ struct te_ipv4_reachability *reach = XCALLOC(MTYPE_ISIS_TLV, TE_IPV4_REACH_LEN);
+
+ memcpy(reach, pnt, 5); /* Metric + Control */
+ pnt += 5;
+ length -= 5;
+
+ unsigned char prefixlen = reach->control & 0x3F;
+
+ if (prefixlen > IPV4_MAX_BITLEN)
+ {
+ zlog_warn("ISIS-TLV: invalid IPv4 extended reachability prefix length %d", prefixlen);
+ XFREE(MTYPE_ISIS_TLV, reach);
+ return ISIS_WARNING;
+ }
+
+ if (length < (unsigned int)PSIZE(prefixlen))
+ {
+ zlog_warn("ISIS-TLV: invalid IPv4 extended reachability prefix too long for tlv");
+ XFREE(MTYPE_ISIS_TLV, reach);
+ return ISIS_WARNING;
+ }
+
+ memcpy(&reach->prefix_start, pnt, PSIZE(prefixlen));
+ pnt += PSIZE(prefixlen);
+ length -= PSIZE(prefixlen);
+
+ if (reach->control & TE_IPV4_HAS_SUBTLV)
+ {
+ if (length < 1)
+ {
+ zlog_warn("ISIS-TLV: invalid IPv4 extended reachability SubTLV missing");
+ XFREE(MTYPE_ISIS_TLV, reach);
+ return ISIS_WARNING;
+ }
+
+ u_char subtlv_len = *pnt;
+ pnt++;
+ length--;
+
+ if (length < subtlv_len)
+ {
+ zlog_warn("ISIS-TLV: invalid IPv4 extended reachability SubTLVs have oversize");
+ XFREE(MTYPE_ISIS_TLV, reach);
+ return ISIS_WARNING;
+ }
+
+ /* Skip Sub-TLVs for now */
+ pnt += subtlv_len;
+ length -= subtlv_len;
+ }
+ listnode_add(reach_list, reach);
+ }
+
+ if (length)
+ {
+ zlog_warn("ISIS-TLV: TE/MT ipv4 reachability TLV has trailing data");
+ return ISIS_WARNING;
+ }
+
+ return ISIS_OK;
+}
+
+static int
+parse_mt_ipv6_reachs(struct tlvs *tlvs, bool read_mtid,
+ unsigned int length, u_char *pnt)
+{
+ struct list *reach_list;
+ uint16_t mtid;
+ int rv;
+
+ rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
+ if (rv != ISIS_OK)
+ return rv;
+
+ if (mtid == ISIS_MT_IPV4_UNICAST)
+ {
+ if (!tlvs->ipv6_reachs)
+ {
+ tlvs->ipv6_reachs = list_new();
+ tlvs->ipv6_reachs->del = free_tlv;
+ }
+ reach_list = tlvs->ipv6_reachs;
+ }
+ else
+ {
+ struct tlv_mt_ipv6_reachs *reachs;
+
+ reachs = tlvs_get_mt_ipv6_reachs(tlvs, mtid);
+ reachs->list->del = free_tlv;
+ reach_list = reachs->list;
+ }
+
+ while (length >= 6) /* Metric + Control + Prefixlen */
+ {
+ struct ipv6_reachability *reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*reach));
+
+ memcpy(reach, pnt, 6); /* Metric + Control + Prefixlen */
+ pnt += 6;
+ length -= 6;
+
+ if (reach->prefix_len > IPV6_MAX_BITLEN)
+ {
+ zlog_warn("ISIS-TLV: invalid IPv6 reachability prefix length %d", reach->prefix_len);
+ XFREE(MTYPE_ISIS_TLV, reach);
+ return ISIS_WARNING;
+ }
+
+ if (length < (unsigned int)PSIZE(reach->prefix_len))
+ {
+ zlog_warn("ISIS-TLV: invalid IPv6 reachability prefix too long for tlv");
+ XFREE(MTYPE_ISIS_TLV, reach);
+ return ISIS_WARNING;
+ }
+
+ memcpy(&reach->prefix, pnt, PSIZE(reach->prefix_len));
+ pnt += PSIZE(reach->prefix_len);
+ length -= PSIZE(reach->prefix_len);
+
+ if (reach->control_info & CTRL_INFO_SUBTLVS)
+ {
+ if (length < 1)
+ {
+ zlog_warn("ISIS-TLV: invalid IPv6 reachability SubTLV missing");
+ XFREE(MTYPE_ISIS_TLV, reach);
+ return ISIS_WARNING;
+ }
+
+ u_char subtlv_len = *pnt;
+ pnt++;
+ length--;
+
+ if (length < subtlv_len)
+ {
+ zlog_warn("ISIS-TLV: invalid IPv6 reachability SubTLVs have oversize");
+ XFREE(MTYPE_ISIS_TLV, reach);
+ return ISIS_WARNING;
+ }
+
+ /* Skip Sub-TLVs for now */
+ pnt += subtlv_len;
+ length -= subtlv_len;
+ }
+ listnode_add(reach_list, reach);
+ }
+
+ if (length)
+ {
+ zlog_warn("ISIS-TLV: (MT) IPv6 reachability TLV has trailing data");
+ return ISIS_WARNING;
+ }
+
+ return ISIS_OK;
+}
+
/*
* Parses the tlvs found in the variant length part of the PDU.
* Caller tells with flags in "expected" which TLV's it is interested in.
@@ -103,17 +385,13 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
struct lan_neigh *lan_nei;
struct area_addr *area_addr;
struct is_neigh *is_nei;
- struct te_is_neigh *te_is_nei;
struct es_neigh *es_nei;
struct lsp_entry *lsp_entry;
struct in_addr *ipv4_addr;
struct ipv4_reachability *ipv4_reach;
- struct te_ipv4_reachability *te_ipv4_reach;
struct in6_addr *ipv6_addr;
- struct ipv6_reachability *ipv6_reach;
- int prefix_octets;
int value_len, retval = ISIS_OK;
- u_char *start = stream, *pnt = stream, *endpnt;
+ u_char *start = stream, *pnt = stream;
*found = 0;
memset (tlvs, 0, sizeof (struct tlvs));
@@ -207,54 +485,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
break;
case TE_IS_NEIGHBOURS:
- /* +-------+-------+-------+-------+-------+-------+-------+-------+
- * | Neighbour ID | 7
- * +---------------------------------------------------------------+
- * | TE Metric | 3
- * +---------------------------------------------------------------+
- * | SubTLVs Length | 1
- * +---------------------------------------------------------------+
- * : :
- */
*found |= TLVFLAG_TE_IS_NEIGHS;
#ifdef EXTREME_TLV_DEBUG
zlog_debug ("ISIS-TLV (%s): Extended IS Neighbours length %d",
areatag, length);
#endif /* EXTREME_TLV_DEBUG */
if (TLVFLAG_TE_IS_NEIGHS & *expected)
- {
- while (length > value_len)
- {
- te_is_nei = (struct te_is_neigh *) pnt;
- value_len += IS_NEIGHBOURS_LEN;
- pnt += IS_NEIGHBOURS_LEN;
- /* FIXME - subtlvs are handled here, for now we skip */
- /* FIXME: All TE SubTLVs are not necessary present in LSP PDU. */
- /* So, it must be copied in a new te_is_neigh structure */
- /* rather than just initialize pointer to the original LSP PDU */
- /* to avoid consider the rest of lspdu as subTLVs or buffer overflow */
- if (IS_MPLS_TE(isisMplsTE))
- {
- struct te_is_neigh *new = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh));
- memcpy(new->neigh_id, te_is_nei->neigh_id, ISIS_SYS_ID_LEN + 1);
- memcpy(new->te_metric, te_is_nei->te_metric, 3);
- new->sub_tlvs_length = te_is_nei->sub_tlvs_length;
- memcpy(new->sub_tlvs, pnt, te_is_nei->sub_tlvs_length);
- te_is_nei = new;
- }
- /* Skip SUB TLVs payload */
- value_len += te_is_nei->sub_tlvs_length;
- pnt += te_is_nei->sub_tlvs_length;
-
- if (!tlvs->te_is_neighs)
- tlvs->te_is_neighs = list_new ();
- listnode_add (tlvs->te_is_neighs, te_is_nei);
- }
- }
- else
- {
- pnt += length;
- }
+ retval = parse_mt_is_neighs(tlvs, false, length, pnt);
+ pnt += length;
+ break;
+
+ case MT_IS_NEIGHBOURS:
+ *found |= TLVFLAG_TE_IS_NEIGHS;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_debug ("ISIS-TLV (%s): MT IS Neighbours length %d",
+ areatag, length);
+#endif
+ if (TLVFLAG_TE_IS_NEIGHS & *expected)
+ retval = parse_mt_is_neighs(tlvs, true, length, pnt);
+ pnt += length;
break;
case ES_NEIGHBOURS:
@@ -577,71 +826,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
break;
case TE_IPV4_REACHABILITY:
- /* +-------+-------+-------+-------+-------+-------+-------+-------+
- * | TE Metric | 4
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * | U/D | sTLV? | Prefix Mask Len | 1
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * | Prefix | 0-4
- * +---------------------------------------------------------------+
- * | sub tlvs |
- * +---------------------------------------------------------------+
- * : :
- */
*found |= TLVFLAG_TE_IPV4_REACHABILITY;
#ifdef EXTREME_TLV_DEBUG
zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d",
- areatag, length);
+ areatag, length);
#endif /* EXTREME_TLV_DEBUG */
- endpnt = pnt + length;
if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
- {
- while (length > value_len)
- {
- te_ipv4_reach = (struct te_ipv4_reachability *) pnt;
- if ((te_ipv4_reach->control & 0x3F) > IPV4_MAX_BITLEN)
- {
- zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach"
- "ability prefix length %d", areatag,
- te_ipv4_reach->control & 0x3F);
- retval = ISIS_WARNING;
- break;
- }
- if (!tlvs->te_ipv4_reachs)
- tlvs->te_ipv4_reachs = list_new ();
- listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach);
-
- /* Metric + Control-Byte + Prefix */
- unsigned int entry_len = 5 + PSIZE(te_ipv4_reach->control & 0x3F);
- value_len += entry_len;
- pnt += entry_len;
-
- if (te_ipv4_reach->control & TE_IPV4_HAS_SUBTLV)
- {
- if (length <= value_len)
- {
- zlog_warn("ISIS-TLV (%s): invalid IPv4 extended reachability SubTLV missing",
- areatag);
- retval = ISIS_WARNING;
- break;
- }
- u_char subtlv_len = *pnt;
- value_len += subtlv_len + 1;
- pnt += subtlv_len + 1;
- if (length < value_len)
- {
- zlog_warn("ISIS-TLV (%s): invalid IPv4 extended reachability SubTLVs have oversize",
- areatag);
- retval = ISIS_WARNING;
- break;
- }
- }
- }
- }
-
- pnt = endpnt;
+ retval = parse_mt_ipv4_reachs(tlvs, false, length, pnt);
+ pnt += length;
+ break;
+ case MT_IPV4_REACHABILITY:
+ *found |= TLVFLAG_TE_IPV4_REACHABILITY;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_debug ("ISIS-TLV (%s): IPv4 MT Reachability length %d",
+ areatag, length);
+#endif /* EXTREME_TLV_DEBUG */
+ if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
+ retval = parse_mt_ipv4_reachs(tlvs, true, length, pnt);
+ pnt += length;
break;
-
case IPV6_ADDR:
/* +-------+-------+-------+-------+-------+-------+-------+-------+
* + IP version 6 address + 16
@@ -672,67 +875,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
break;
case IPV6_REACHABILITY:
- /* +-------+-------+-------+-------+-------+-------+-------+-------+
- * | Default Metric | 4
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * | Control Informantion |
- * +---------------------------------------------------------------+
- * | IPv6 Prefix Length |--+
- * +---------------------------------------------------------------+ |
- * | IPv6 Prefix |<-+
- * +---------------------------------------------------------------+
- */
*found |= TLVFLAG_IPV6_REACHABILITY;
- endpnt = pnt + length;
-
+#ifdef EXTREME_TLV_DEBUG
+ zlog_debug ("ISIS-TLV (%s): IPv6 Reachability length %d",
+ areatag, length);
+#endif /* EXTREME_TLV_DEBUG */
if (*expected & TLVFLAG_IPV6_REACHABILITY)
- {
- while (length > value_len)
- {
- ipv6_reach = (struct ipv6_reachability *) pnt;
- if (ipv6_reach->prefix_len > IPV6_MAX_BITLEN)
- {
- zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach"
- "ability prefix length %d", areatag,
- ipv6_reach->prefix_len);
- retval = ISIS_WARNING;
- break;
- }
-
- prefix_octets = ((ipv6_reach->prefix_len + 7) / 8);
- value_len += prefix_octets + 6;
- pnt += prefix_octets + 6;
-
- if (ipv6_reach->control_info & CTRL_INFO_SUBTLVS)
- {
- if (length <= value_len)
- {
- zlog_warn("ISIS-TLV (%s): invalid IPv6 extended reachability SubTLV missing",
- areatag);
- retval = ISIS_WARNING;
- break;
- }
- u_char subtlv_len = *pnt;
- value_len += subtlv_len + 1;
- pnt += subtlv_len + 1;
- if (length < value_len)
- {
- zlog_warn("ISIS-TLV (%s): invalid IPv6 extended reachability SubTLVs have oversize",
- areatag);
- retval = ISIS_WARNING;
- break;
- }
- }
- /* FIXME: sub-tlvs */
- if (!tlvs->ipv6_reachs)
- tlvs->ipv6_reachs = list_new ();
- listnode_add (tlvs->ipv6_reachs, ipv6_reach);
- }
- }
-
- pnt = endpnt;
+ retval = parse_mt_ipv6_reachs(tlvs, false, length, pnt);
+ pnt += length;
+ break;
+ case MT_IPV6_REACHABILITY:
+ *found |= TLVFLAG_IPV6_REACHABILITY;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_debug ("ISIS-TLV (%s): IPv6 Reachability length %d",
+ areatag, length);
+#endif /* EXTREME_TLV_DEBUG */
+ if (*expected & TLVFLAG_IPV6_REACHABILITY)
+ retval = parse_mt_ipv6_reachs(tlvs, true, length, pnt);
+ pnt += length;
break;
-
case WAY3_HELLO:
/* +---------------------------------------------------------------+
* | Adjacency state | 1
@@ -786,6 +947,42 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
pnt += length;
break;
+ case MT_ROUTER_INFORMATION:
+ *found |= TLVFLAG_MT_ROUTER_INFORMATION;
+ if (*expected & TLVFLAG_MT_ROUTER_INFORMATION)
+ {
+ if (!tlvs->mt_router_info)
+ {
+ tlvs->mt_router_info = list_new();
+ tlvs->mt_router_info->del = free_tlv;
+ }
+ while (length > value_len)
+ {
+ uint16_t mt_info;
+ struct mt_router_info *info;
+
+ if (value_len + sizeof(mt_info) > length) {
+ zlog_warn("ISIS-TLV (%s): TLV 229 is truncated.", areatag);
+ pnt += length - value_len;
+ break;
+ }
+
+ memcpy(&mt_info, pnt, sizeof(mt_info));
+ pnt += sizeof(mt_info);
+ value_len += sizeof(mt_info);
+
+ mt_info = ntohs(mt_info);
+ info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
+ info->mtid = mt_info & ISIS_MT_MASK;
+ info->overload = mt_info & ISIS_MT_OL_MASK;
+ listnode_add(tlvs->mt_router_info, info);
+ }
+ }
+ else
+ {
+ pnt += length;
+ }
+ break;
default:
zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
areatag, type, length);
@@ -826,6 +1023,31 @@ add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
}
int
+tlv_add_mt_router_info (struct list *mt_router_info, struct stream *stream)
+{
+ struct listnode *node;
+ struct mt_router_info *info;
+
+ uint16_t value[127];
+ uint16_t *pos = value;
+
+ for (ALL_LIST_ELEMENTS_RO(mt_router_info, node, info))
+ {
+ uint16_t mt_info;
+
+ mt_info = info->mtid;
+ if (info->overload)
+ mt_info |= ISIS_MT_OL_MASK;
+
+ *pos = htons(mt_info);
+ pos++;
+ }
+
+ return add_tlv(MT_ROUTER_INFORMATION, (pos - value) * sizeof(*pos),
+ (u_char*)value, stream);
+}
+
+int
tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
{
struct listnode *node;
@@ -887,26 +1109,44 @@ tlv_add_is_neighs (struct list *is_neighs, struct stream *stream)
return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
}
-int
-tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
+static size_t
+max_tlv_size(struct stream *stream)
+{
+ size_t avail = stream_get_size (stream) - stream_get_endp(stream);
+
+ if (avail < 2)
+ return 0;
+
+ if (avail < 257)
+ return avail - 2;
+
+ return 255;
+}
+
+unsigned int
+tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream, void *arg)
{
struct listnode *node;
struct te_is_neigh *te_is_neigh;
u_char value[255];
u_char *pos = value;
- int retval;
+ uint16_t mtid = arg ? *(uint16_t*)arg : ISIS_MT_IPV4_UNICAST;
+ unsigned int consumed = 0;
+ size_t max_size = max_tlv_size(stream);
+
+ if (mtid != ISIS_MT_IPV4_UNICAST)
+ {
+ uint16_t mtid_conversion = ntohs(mtid);
+ memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
+ pos += sizeof(mtid_conversion);
+ }
for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
{
/* FIXME: Check if Total SubTLVs size doesn't exceed 255 */
- if (pos - value + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > 255)
- {
- retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
- if (retval != ISIS_OK)
- return retval;
- pos = value;
- }
-
+ if ((size_t)(pos - value) + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > max_size)
+ break;
+
memcpy (pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
pos += ISIS_SYS_ID_LEN + 1;
memcpy (pos, te_is_neigh->te_metric, 3);
@@ -920,9 +1160,17 @@ tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
memcpy (pos, te_is_neigh->sub_tlvs, te_is_neigh->sub_tlvs_length);
pos += te_is_neigh->sub_tlvs_length;
}
+ consumed++;
}
- return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
+ if (consumed)
+ {
+ int rv = add_tlv ((mtid != ISIS_MT_IPV4_UNICAST) ? MT_IS_NEIGHBOURS
+ : TE_IS_NEIGHBOURS,
+ pos - value, value, stream);
+ assert(rv == ISIS_OK);
+ }
+ return consumed;
}
int
@@ -1100,37 +1348,49 @@ tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream)
}
-int
-tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream)
+unsigned int
+tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream, void *arg)
{
struct listnode *node;
struct te_ipv4_reachability *te_reach;
u_char value[255];
u_char *pos = value;
- u_char prefix_size;
- int retval;
+ uint16_t mtid = arg ? *(uint16_t*)arg : ISIS_MT_IPV4_UNICAST;
+ unsigned int consumed = 0;
+ size_t max_size = max_tlv_size(stream);
+
+ if (mtid != ISIS_MT_IPV4_UNICAST)
+ {
+ uint16_t mtid_conversion = ntohs(mtid);
+ memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
+ pos += sizeof(mtid_conversion);
+ }
for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs, node, te_reach))
{
- prefix_size = ((((te_reach->control & 0x3F) - 1) >> 3) + 1);
+ unsigned char prefixlen = te_reach->control & 0x3F;
+
+ if ((size_t)(pos - value) + 5 + PSIZE(prefixlen) > max_size)
+ break;
- if (pos - value + (5 + prefix_size) > 255)
- {
- retval =
- add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
- if (retval != ISIS_OK)
- return retval;
- pos = value;
- }
*(u_int32_t *) pos = te_reach->te_metric;
pos += 4;
*pos = te_reach->control;
pos++;
- memcpy (pos, &te_reach->prefix_start, prefix_size);
- pos += prefix_size;
+ memcpy (pos, &te_reach->prefix_start, PSIZE(prefixlen));
+ pos += PSIZE(prefixlen);
+ consumed++;
+ }
+
+ if (consumed)
+ {
+ int rv = add_tlv ((mtid != ISIS_MT_IPV4_UNICAST) ? MT_IPV4_REACHABILITY
+ : TE_IPV4_REACHABILITY,
+ pos - value, value, stream);
+ assert(rv == ISIS_OK);
}
- return add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
+ return consumed;
}
int
@@ -1158,36 +1418,49 @@ tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream)
return add_tlv (IPV6_ADDR, pos - value, value, stream);
}
-int
-tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream)
+unsigned int
+tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream, void *arg)
{
struct listnode *node;
struct ipv6_reachability *ip6reach;
u_char value[255];
u_char *pos = value;
- int retval, prefix_octets;
+ uint16_t mtid = arg ? *(uint16_t*)arg : ISIS_MT_IPV4_UNICAST;
+ unsigned int consumed = 0;
+ size_t max_size = max_tlv_size(stream);
+
+ if (mtid != ISIS_MT_IPV4_UNICAST)
+ {
+ uint16_t mtid_conversion = ntohs(mtid);
+ memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
+ pos += sizeof(mtid_conversion);
+ }
for (ALL_LIST_ELEMENTS_RO (ipv6_reachs, node, ip6reach))
{
- if (pos - value + IPV6_MAX_BYTELEN + 6 > 255)
- {
- retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
- if (retval != ISIS_OK)
- return retval;
- pos = value;
- }
- *(uint32_t *) pos = ip6reach->metric;
+ if ((size_t)(pos - value) + 6 + PSIZE(ip6reach->prefix_len) > max_size)
+ break;
+
+ *(uint32_t *)pos = ip6reach->metric;
pos += 4;
*pos = ip6reach->control_info;
pos++;
- prefix_octets = ((ip6reach->prefix_len + 7) / 8);
*pos = ip6reach->prefix_len;
pos++;
- memcpy (pos, ip6reach->prefix, prefix_octets);
- pos += prefix_octets;
+ memcpy (pos, ip6reach->prefix, PSIZE(ip6reach->prefix_len));
+ pos += PSIZE(ip6reach->prefix_len);
+ consumed++;
+ }
+
+ if (consumed)
+ {
+ int rv = add_tlv ((mtid != ISIS_MT_IPV4_UNICAST) ? MT_IPV6_REACHABILITY
+ : IPV6_REACHABILITY,
+ pos - value, value, stream);
+ assert(rv == ISIS_OK);
}
- return add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
+ return consumed;
}
int
diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h
index f899b9e9d..2135f5071 100644
--- a/isisd/isis_tlv.h
+++ b/isisd/isis_tlv.h
@@ -24,6 +24,8 @@
#ifndef _ZEBRA_ISIS_TLV_H
#define _ZEBRA_ISIS_TLV_H
+#include "isisd/isis_mt.h"
+
/*
* The list of TLVs we (should) support.
* ____________________________________________________________________________
@@ -109,8 +111,12 @@
#define TE_IPV4_REACHABILITY 135
#define DYNAMIC_HOSTNAME 137
#define GRACEFUL_RESTART 211
+#define MT_IS_NEIGHBOURS 222
+#define MT_ROUTER_INFORMATION 229
#define IPV6_ADDR 232
+#define MT_IPV4_REACHABILITY 235
#define IPV6_REACHABILITY 236
+#define MT_IPV6_REACHABILITY 237
#define WAY3_HELLO 240
#define ROUTER_INFORMATION 242
@@ -250,6 +256,12 @@ struct ipv6_reachability
#define CTRL_INFO_SUBTLVS 0x20
+struct mt_router_info
+{
+ ISIS_MT_INFO_FIELDS
+ bool overload;
+};
+
/*
* Pointer to each tlv type, filled by parse_tlvs()
*/
@@ -260,8 +272,10 @@ struct tlvs
struct nlpids *nlpids;
struct te_router_id *router_id;
struct list *area_addrs;
+ struct list *mt_router_info;
struct list *is_neighs;
struct list *te_is_neighs;
+ struct list *mt_is_neighs;
struct list *es_neighs;
struct list *lsp_entries;
struct list *prefix_neighs;
@@ -270,8 +284,10 @@ struct tlvs
struct list *ipv4_int_reachs;
struct list *ipv4_ext_reachs;
struct list *te_ipv4_reachs;
+ struct list *mt_ipv4_reachs;
struct list *ipv6_addrs;
struct list *ipv6_reachs;
+ struct list *mt_ipv6_reachs;
struct isis_passwd auth_info;
};
@@ -301,6 +317,7 @@ struct tlvs
#define TLVFLAG_TE_ROUTER_ID (1<<19)
#define TLVFLAG_CHECKSUM (1<<20)
#define TLVFLAG_GRACEFUL_RESTART (1<<21)
+#define TLVFLAG_MT_ROUTER_INFORMATION (1<<22)
void init_tlvs (struct tlvs *tlvs, uint32_t expected);
void free_tlvs (struct tlvs *tlvs);
@@ -310,9 +327,10 @@ int parse_tlvs (char *areatag, u_char * stream, int size,
int add_tlv (u_char, u_char, u_char *, struct stream *);
void free_tlv (void *val);
+int tlv_add_mt_router_info (struct list *mt_router_info, struct stream *stream);
int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream);
int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream);
-int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream);
+unsigned int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream, void *arg);
int tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream);
int tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream);
int tlv_add_checksum (struct checksum *checksum, struct stream *stream);
@@ -325,9 +343,9 @@ int tlv_add_dynamic_hostname (struct hostname *hostname,
int tlv_add_lsp_entries (struct list *lsps, struct stream *stream);
int tlv_add_ipv4_int_reachs (struct list *ipv4_reachs, struct stream *stream);
int tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream);
-int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream);
+unsigned int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream, void *arg);
int tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream);
-int tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream);
+unsigned int tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream, void *arg);
int tlv_add_padding (struct stream *stream);
diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c
index 721959859..1658ca373 100644
--- a/isisd/isis_vty.c
+++ b/isisd/isis_vty.c
@@ -29,6 +29,7 @@
#include "isis_circuit.h"
#include "isis_csm.h"
#include "isis_misc.h"
+#include "isis_mt.h"
#include "isisd.h"
static struct isis_circuit *
@@ -1271,6 +1272,48 @@ DEFUN (no_psnp_interval_l2,
return CMD_SUCCESS;
}
+DEFUN (circuit_topology,
+ circuit_topology_cmd,
+ "isis topology " ISIS_MT_NAMES,
+ "IS-IS commands\n"
+ "Configure interface IS-IS topologies\n"
+ ISIS_MT_DESCRIPTIONS)
+{
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
+ const char *arg = argv[2]->arg;
+ uint16_t mtid = isis_str2mtid(arg);
+ if (mtid == (uint16_t)-1)
+ {
+ vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ return isis_circuit_mt_enabled_set(circuit, mtid, true);
+}
+
+DEFUN (no_circuit_topology,
+ no_circuit_topology_cmd,
+ "no isis topology " ISIS_MT_NAMES,
+ NO_STR
+ "IS-IS commands\n"
+ "Configure interface IS-IS topologies\n"
+ ISIS_MT_DESCRIPTIONS)
+{
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
+ const char *arg = argv[3]->arg;
+ uint16_t mtid = isis_str2mtid(arg);
+ if (mtid == (uint16_t)-1)
+ {
+ vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ return isis_circuit_mt_enabled_set(circuit, mtid, false);
+}
static int
validate_metric_style_narrow (struct vty *vty, struct isis_area *area)
@@ -2116,6 +2159,9 @@ isis_vty_init (void)
install_element (INTERFACE_NODE, &psnp_interval_l2_cmd);
install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd);
+ install_element (INTERFACE_NODE, &circuit_topology_cmd);
+ install_element (INTERFACE_NODE, &no_circuit_topology_cmd);
+
install_element (ISIS_NODE, &metric_style_cmd);
install_element (ISIS_NODE, &no_metric_style_cmd);
diff --git a/isisd/isisd.c b/isisd/isisd.c
index f226c4a1f..179e43098 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -56,6 +56,7 @@
#include "isisd/isis_zebra.h"
#include "isisd/isis_events.h"
#include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
struct isis *isis = NULL;
@@ -156,6 +157,8 @@ isis_area_create (const char *area_tag)
area->lsp_frag_threshold = 90;
area->lsp_mtu = DEFAULT_LSP_MTU;
+ area_mt_init(area);
+
area->area_tag = strdup (area_tag);
listnode_add (isis->area_list, area);
area->isis = isis;
@@ -296,6 +299,8 @@ isis_area_destroy (struct vty *vty, const char *area_tag)
free (area->area_tag);
+ area_mt_finish(area);
+
XFREE (MTYPE_ISIS_AREA, area);
if (listcount (isis->area_list) == 0)
@@ -307,6 +312,33 @@ isis_area_destroy (struct vty *vty, const char *area_tag)
return CMD_SUCCESS;
}
+static void
+area_set_mt_enabled(struct isis_area *area, uint16_t mtid, bool enabled)
+{
+ struct isis_area_mt_setting *setting;
+
+ setting = area_get_mt_setting(area, mtid);
+ if (setting->enabled != enabled)
+ {
+ setting->enabled = enabled;
+ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0);
+ }
+}
+
+static void
+area_set_mt_overload(struct isis_area *area, uint16_t mtid, bool overload)
+{
+ struct isis_area_mt_setting *setting;
+
+ setting = area_get_mt_setting(area, mtid);
+ if (setting->overload != overload)
+ {
+ setting->overload = overload;
+ if (setting->enabled)
+ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0);
+ }
+}
+
int
area_net_title (struct vty *vty, const char *net_title)
{
@@ -1626,6 +1658,61 @@ DEFUN (no_net,
return area_clear_net_title (vty, argv[idx_word]->arg);
}
+DEFUN (isis_topology,
+ isis_topology_cmd,
+ "topology " ISIS_MT_NAMES " [overload]",
+ "Configure IS-IS topologies\n"
+ ISIS_MT_DESCRIPTIONS
+ "Set overload bit for topology\n")
+{
+ VTY_DECLVAR_CONTEXT (isis_area, area);
+
+ const char *arg = argv[1]->arg;
+ uint16_t mtid = isis_str2mtid(arg);
+ if (mtid == (uint16_t)-1)
+ {
+ vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+ if (mtid == ISIS_MT_IPV4_UNICAST)
+ {
+ vty_out (vty, "Cannot configure IPv4 unicast topology%s", VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ area_set_mt_enabled(area, mtid, true);
+ area_set_mt_overload(area, mtid, (argc == 3));
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_topology,
+ no_isis_topology_cmd,
+ "no topology " ISIS_MT_NAMES " [overload]",
+ NO_STR
+ "Configure IS-IS topologies\n"
+ ISIS_MT_DESCRIPTIONS
+ "Set overload bit for topology\n")
+{
+ VTY_DECLVAR_CONTEXT (isis_area, area);
+
+ const char *arg = argv[2]->arg;
+ uint16_t mtid = isis_str2mtid(arg);
+ if (mtid == (uint16_t)-1)
+ {
+ vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+ if (mtid == ISIS_MT_IPV4_UNICAST)
+ {
+ vty_out (vty, "Cannot configure IPv4 unicast topology%s", VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ area_set_mt_enabled(area, mtid, false);
+ area_set_mt_overload(area, mtid, false);
+ return CMD_SUCCESS;
+}
+
void isis_area_lsp_mtu_set(struct isis_area *area, unsigned int lsp_mtu)
{
area->lsp_mtu = lsp_mtu;
@@ -2148,6 +2235,7 @@ isis_config_write (struct vty *vty)
write++;
}
+ write += area_write_mt_settings(area, vty);
}
isis_mpls_te_config_write_router(vty);
}
@@ -2254,6 +2342,9 @@ isis_init ()
install_element (ISIS_NODE, &net_cmd);
install_element (ISIS_NODE, &no_net_cmd);
+ install_element (ISIS_NODE, &isis_topology_cmd);
+ install_element (ISIS_NODE, &no_isis_topology_cmd);
+
install_element (ISIS_NODE, &log_adj_changes_cmd);
install_element (ISIS_NODE, &no_log_adj_changes_cmd);
diff --git a/isisd/isisd.h b/isisd/isisd.h
index e1d3a69f8..a8cf3673f 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -120,6 +120,8 @@ struct isis_area
int ip_circuits;
/* logging adjacency changes? */
u_char log_adj_changes;
+ /* multi topology settings */
+ struct list *mt_settings;
int ipv6_circuits;
/* Counters */
u_int32_t circuit_state_changes;
diff --git a/ldpd/lde.c b/ldpd/lde.c
index 25f7178b6..859d47431 100644
--- a/ldpd/lde.c
+++ b/ldpd/lde.c
@@ -80,10 +80,6 @@ static zebra_capabilities_t _caps_p [] =
static struct zebra_privs_t lde_privs =
{
-#if defined(FRR_USER) && defined(FRR_GROUP)
- .user = FRR_USER,
- .group = FRR_GROUP,
-#endif
#if defined(VTY_GROUP)
.vty_group = VTY_GROUP,
#endif
@@ -164,10 +160,8 @@ void
lde_init(struct ldpd_init *init)
{
/* drop privileges */
- if (init->user)
- lde_privs.user = init->user;
- if (init->group)
- lde_privs.group = init->group;
+ lde_privs.user = init->user;
+ lde_privs.group = init->group;
zprivs_init(&lde_privs);
#ifdef HAVE_PLEDGE
diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c
index 20cc9f744..017eec250 100644
--- a/ldpd/ldpe.c
+++ b/ldpd/ldpe.c
@@ -66,10 +66,6 @@ static zebra_capabilities_t _caps_p [] =
struct zebra_privs_t ldpe_privs =
{
-#if defined(FRR_USER) && defined(FRR_GROUP)
- .user = FRR_USER,
- .group = FRR_GROUP,
-#endif
#if defined(VTY_GROUP)
.vty_group = VTY_GROUP,
#endif
@@ -143,10 +139,8 @@ void
ldpe_init(struct ldpd_init *init)
{
/* drop privileges */
- if (init->user)
- ldpe_privs.user = init->user;
- if (init->group)
- ldpe_privs.group = init->group;
+ ldpe_privs.user = init->user;
+ ldpe_privs.group = init->group;
zprivs_init(&ldpe_privs);
/* listen on ldpd control socket */
diff --git a/lib/Makefile.am b/lib/Makefile.am
index c33893be6..6e3c6d680 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -35,6 +35,7 @@ libfrr_la_SOURCES = \
sha256.c \
module.c \
hook.c \
+ frr_pthread.c \
# end
BUILT_SOURCES = route_types.h gitversion.h command_parse.h command_lex.h
@@ -76,6 +77,7 @@ pkginclude_HEADERS = \
hook.h \
libfrr.h \
sha256.h \
+ frr_pthread.h \
# end
noinst_HEADERS = \
diff --git a/lib/command.c b/lib/command.c
index f0d7a64eb..ba1e0bcec 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -1055,9 +1055,11 @@ node_parent ( enum node_type node )
case BGP_VNC_L2_GROUP_NODE:
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
+ case BGP_IPV4L_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
case BGP_EVPN_NODE:
+ case BGP_IPV6L_NODE:
ret = BGP_NODE;
break;
case KEYCHAIN_KEY_NODE:
@@ -1415,6 +1417,7 @@ cmd_exit (struct vty *vty)
break;
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
+ case BGP_IPV4L_NODE:
case BGP_VPNV4_NODE:
case BGP_VPNV6_NODE:
case BGP_ENCAP_NODE:
@@ -1426,6 +1429,7 @@ cmd_exit (struct vty *vty)
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
case BGP_EVPN_NODE:
+ case BGP_IPV6L_NODE:
vty->node = BGP_NODE;
break;
case LDP_IPV4_NODE:
@@ -1493,9 +1497,11 @@ DEFUN (config_end,
case BGP_VPNV6_NODE:
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
+ case BGP_IPV4L_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
case BGP_EVPN_NODE:
+ case BGP_IPV6L_NODE:
case RMAP_NODE:
case OSPF_NODE:
case OSPF6_NODE:
diff --git a/lib/command.h b/lib/command.h
index c8172caa7..8f6abc85b 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -97,8 +97,10 @@ enum node_type
BGP_VPNV6_NODE, /* BGP MPLS-VPN PE exchange. */
BGP_IPV4_NODE, /* BGP IPv4 unicast address family. */
BGP_IPV4M_NODE, /* BGP IPv4 multicast address family. */
+ BGP_IPV4L_NODE, /* BGP IPv4 labeled unicast address family. */
BGP_IPV6_NODE, /* BGP IPv6 address family */
BGP_IPV6M_NODE, /* BGP IPv6 multicast address family. */
+ BGP_IPV6L_NODE, /* BGP IPv6 labeled unicast address family. */
BGP_ENCAP_NODE, /* BGP ENCAP SAFI */
BGP_ENCAPV6_NODE, /* BGP ENCAP SAFI */
BGP_VRF_POLICY_NODE, /* BGP VRF policy */
diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c
new file mode 100644
index 000000000..0408bca09
--- /dev/null
+++ b/lib/frr_pthread.c
@@ -0,0 +1,184 @@
+/*
+ Utilities and interfaces for managing POSIX threads
+ Copyright (C) 2017 Cumulus Networks
+
+ This program 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 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program; see the file COPYING; if not, write to the
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+#include <pthread.h>
+
+#include "frr_pthread.h"
+#include "memory.h"
+#include "hash.h"
+
+DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread");
+
+static unsigned int next_id = 0;
+
+/* Hash table of all frr_pthreads along with synchronization primitive(s) and
+ * hash table callbacks.
+ * ------------------------------------------------------------------------ */
+static struct hash *pthread_table;
+static pthread_mutex_t pthread_table_mtx = PTHREAD_MUTEX_INITIALIZER;
+
+/* pthread_table->hash_cmp */
+static int pthread_table_hash_cmp(const void *value1, const void *value2)
+{
+ const struct frr_pthread *tq1 = value1;
+ const struct frr_pthread *tq2 = value2;
+
+ return (tq1->id == tq2->id);
+}
+
+/* pthread_table->hash_key */
+static unsigned int pthread_table_hash_key(void *value)
+{
+ return ((struct frr_pthread *)value)->id;
+}
+/* ------------------------------------------------------------------------ */
+
+void frr_pthread_init()
+{
+ pthread_mutex_lock(&pthread_table_mtx);
+ {
+ pthread_table =
+ hash_create(pthread_table_hash_key, pthread_table_hash_cmp);
+ }
+ pthread_mutex_unlock(&pthread_table_mtx);
+}
+
+void frr_pthread_finish()
+{
+ pthread_mutex_lock(&pthread_table_mtx);
+ {
+ hash_clean(pthread_table, (void (*)(void *))frr_pthread_destroy);
+ hash_free(pthread_table);
+ }
+ pthread_mutex_unlock(&pthread_table_mtx);
+}
+
+struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
+ void *(*start_routine) (void *),
+ int (*stop_routine) (void **, struct frr_pthread *))
+{
+ static struct frr_pthread holder = { 0 };
+ struct frr_pthread *fpt = NULL;
+
+ pthread_mutex_lock(&pthread_table_mtx);
+ {
+ holder.id = id;
+
+ if (!hash_lookup(pthread_table, &holder)) {
+ struct frr_pthread *fpt =
+ XCALLOC(MTYPE_FRR_PTHREAD,
+ sizeof(struct frr_pthread));
+ fpt->id = id;
+ fpt->master = thread_master_create();
+ fpt->start_routine = start_routine;
+ fpt->stop_routine = stop_routine;
+ fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name);
+
+ hash_get(pthread_table, fpt, hash_alloc_intern);
+ }
+ }
+ pthread_mutex_unlock(&pthread_table_mtx);
+
+ return fpt;
+}
+
+void frr_pthread_destroy(struct frr_pthread *fpt)
+{
+ thread_master_free(fpt->master);
+ XFREE(MTYPE_FRR_PTHREAD, fpt->name);
+ XFREE(MTYPE_FRR_PTHREAD, fpt);
+}
+
+struct frr_pthread *frr_pthread_get(unsigned int id)
+{
+ static struct frr_pthread holder = { 0 };
+ struct frr_pthread *fpt;
+
+ pthread_mutex_lock(&pthread_table_mtx);
+ {
+ holder.id = id;
+ fpt = hash_lookup(pthread_table, &holder);
+ }
+ pthread_mutex_unlock(&pthread_table_mtx);
+
+ return fpt;
+}
+
+int frr_pthread_run(unsigned int id, const pthread_attr_t * attr, void *arg)
+{
+ struct frr_pthread *fpt = frr_pthread_get(id);
+ int ret;
+
+ if (!fpt)
+ return -1;
+
+ ret = pthread_create(&fpt->thread, attr, fpt->start_routine, arg);
+
+ /* Per pthread_create(3), the contents of fpt->thread are undefined if
+ * pthread_create() did not succeed. Reset this value to zero. */
+ if (ret < 0)
+ memset(&fpt->thread, 0x00, sizeof(fpt->thread));
+
+ return ret;
+}
+
+/**
+ * Calls the stop routine for the frr_pthread and resets any relevant fields.
+ *
+ * @param fpt - the frr_pthread to stop
+ * @param result - pointer to result pointer
+ * @return the return code from the stop routine
+ */
+static int frr_pthread_stop_actual(struct frr_pthread *fpt, void **result)
+{
+ int ret = (*fpt->stop_routine) (result, fpt);
+ memset(&fpt->thread, 0x00, sizeof(fpt->thread));
+ return ret;
+}
+
+int frr_pthread_stop(unsigned int id, void **result)
+{
+ struct frr_pthread *fpt = frr_pthread_get(id);
+ return frr_pthread_stop_actual(fpt, result);
+}
+
+/**
+ * Callback for hash_iterate to stop all frr_pthread's.
+ */
+static void frr_pthread_stop_all_iter(struct hash_backet *hb, void *arg)
+{
+ struct frr_pthread *fpt = hb->data;
+ frr_pthread_stop_actual(fpt, NULL);
+}
+
+void frr_pthread_stop_all()
+{
+ pthread_mutex_lock(&pthread_table_mtx);
+ {
+ hash_iterate(pthread_table, frr_pthread_stop_all_iter, NULL);
+ }
+ pthread_mutex_unlock(&pthread_table_mtx);
+}
+
+unsigned int frr_pthread_get_id()
+{
+ return next_id++;
+}
diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h
new file mode 100644
index 000000000..b4954367f
--- /dev/null
+++ b/lib/frr_pthread.h
@@ -0,0 +1,145 @@
+/*
+ Utilities and interfaces for managing POSIX threads
+ Copyright (C) 2017 Cumulus Networks
+
+ This program 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 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program; see the file COPYING; if not, write to the
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+ */
+
+#ifndef _FRR_PTHREAD_H
+#define _FRR_PTHREAD_H
+
+#include <pthread.h>
+#include "thread.h"
+
+struct frr_pthread {
+
+ /* pthread id */
+ pthread_t thread;
+
+ /* frr thread identifier */
+ unsigned int id;
+
+ /* thread master for this pthread's thread.c event loop */
+ struct thread_master *master;
+
+ /* start routine */
+ void *(*start_routine) (void *);
+
+ /* stop routine */
+ int (*stop_routine) (void **, struct frr_pthread *);
+
+ /* the (hopefully descriptive) name of this thread */
+ char *name;
+};
+
+/* Initializes this module.
+ *
+ * Must be called before using any of the other functions.
+ */
+void frr_pthread_init(void);
+
+/* Uninitializes this module.
+ *
+ * Destroys all registered frr_pthread's and internal data structures.
+ *
+ * It is safe to call frr_pthread_init() after this function to reinitialize
+ * the module.
+ */
+void frr_pthread_finish(void);
+
+/* Creates a new frr_pthread.
+ *
+ * If the provided ID is already assigned to an existing frr_pthread, the
+ * return value will be NULL.
+ *
+ * @param name - the name of the thread. Doesn't have to be unique, but it
+ * probably should be. This value is copied and may be safely free'd upon
+ * return.
+ *
+ * @param id - the integral ID of the thread. MUST be unique. The caller may
+ * use this id to retrieve the thread.
+ *
+ * @param start_routine - start routine for the pthread, will be passed to
+ * pthread_create (see those docs for details)
+ *
+ * @param stop_routine - stop routine for the pthread, called to terminate the
+ * thread. This function should gracefully stop the pthread and clean up any
+ * thread-specific resources. The passed pointer is used to return a data
+ * result.
+ *
+ * @return the created frr_pthread upon success, or NULL upon failure
+ */
+struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
+ void *(*start_routine) (void *),
+ int (*stop_routine) (void **, struct frr_pthread *));
+
+/* Destroys an frr_pthread.
+ *
+ * Assumes that the associated pthread, if any, has already terminated.
+ *
+ * @param fpt - the frr_pthread to destroy
+ */
+void frr_pthread_destroy(struct frr_pthread *fpt);
+
+/* Gets an existing frr_pthread by its id.
+ *
+ * @return frr_thread associated with the provided id, or NULL on error
+ */
+struct frr_pthread *frr_pthread_get(unsigned int id);
+
+/* Creates a new pthread and binds it to a frr_pthread.
+ *
+ * This function is a wrapper for pthread_create. The first parameter is the
+ * frr_pthread to bind the created pthread to. All subsequent arguments are
+ * passed unmodified to pthread_create().
+ *
+ * This function returns the same code as pthread_create(). If the value is
+ * zero, the provided frr_pthread is bound to a running POSIX thread. If the
+ * value is less than zero, the provided frr_pthread is guaranteed to be a
+ * clean instance that may be susbsequently passed to frr_pthread_run().
+ *
+ * @param id - frr_pthread to bind the created pthread to
+ * @param attr - see pthread_create(3)
+ * @param arg - see pthread_create(3)
+ *
+ * @return see pthread_create(3)
+ */
+int frr_pthread_run(unsigned int id, const pthread_attr_t * attr, void *arg);
+
+/* Stops an frr_pthread with a result.
+ *
+ * @param id - frr_pthread to stop
+ * @param result - where to store the thread's result, if any. May be NULL if a
+ * result is not needed.
+ */
+int frr_pthread_stop(unsigned int id, void **result);
+
+/* Stops all frr_pthread's. */
+void frr_pthread_stop_all(void);
+
+/* Returns a unique identifier for use with frr_pthread_new().
+ *
+ * Internally, this is an integer that increments after each call to this
+ * function. Because the number of pthreads created should never exceed INT_MAX
+ * during the life of the program, there is no overflow protection. If by
+ * chance this function returns an ID which is already in use,
+ * frr_pthread_new() will fail when it is provided.
+ *
+ * @return unique identifier
+ */
+unsigned int frr_pthread_get_id(void);
+
+#endif /* _FRR_PTHREAD_H */
diff --git a/lib/mpls.h b/lib/mpls.h
index 13a46e101..f4f360c95 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -85,7 +85,8 @@ enum lsp_types_t
{
ZEBRA_LSP_NONE = 0, /* No LSP. */
ZEBRA_LSP_STATIC = 1, /* Static LSP. */
- ZEBRA_LSP_LDP = 2 /* LDP LSP. */
+ ZEBRA_LSP_LDP = 2, /* LDP LSP. */
+ ZEBRA_LSP_BGP = 3 /* BGP LSP. */
};
/* Functions for basic label operations. */
@@ -122,6 +123,11 @@ mpls_lse_decode (mpls_lse_t lse, mpls_label_t *label,
*ttl = MPLS_LABEL_TTL(local_lse);
}
+/* Invalid label index value (when used with BGP Prefix-SID). Should
+ * match the BGP definition.
+ */
+#define MPLS_INVALID_LABEL_INDEX 0xFFFFFFFF
+
/* Printable string for labels (with consideration for reserved values). */
static inline char *
diff --git a/lib/nexthop.c b/lib/nexthop.c
index 7b8ac95e8..a6420fea3 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -92,6 +92,28 @@ nexthop_type_to_str (enum nexthop_types_t nh_type)
return desc[nh_type];
}
+/*
+ * Check if the labels match for the 2 nexthops specified.
+ */
+int
+nexthop_labels_match (struct nexthop *nh1, struct nexthop *nh2)
+{
+ struct nexthop_label *nhl1, *nhl2;
+
+ nhl1 = nh1->nh_label;
+ nhl2 = nh2->nh_label;
+ if ((nhl1 && !nhl2) || (!nhl1 && nhl2))
+ return 0;
+
+ if (nhl1->num_labels != nhl2->num_labels)
+ return 0;
+
+ if (memcmp (nhl1->label, nhl2->label, nhl1->num_labels))
+ return 0;
+
+ return 1;
+}
+
struct nexthop *
nexthop_new (void)
{
diff --git a/lib/nexthop.h b/lib/nexthop.h
index e66e0eee2..83c5b850b 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -117,6 +117,7 @@ void nexthop_del_labels (struct nexthop *);
extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type);
extern int nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2);
+extern int nexthop_labels_match (struct nexthop *nh1, struct nexthop *nh2);
extern const char * nexthop2str (struct nexthop *nexthop, char *str, int size);
#endif /*_LIB_NEXTHOP_H */
diff --git a/lib/prefix.h b/lib/prefix.h
index eb3ae3daf..786c2bf7e 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -244,6 +244,8 @@ union prefixconstptr
/* Count prefix size from mask length */
#define PSIZE(a) (((a) + 7) / (8))
+#define BSIZE(a) ((a) * (8))
+
/* Prefix's family member. */
#define PREFIX_FAMILY(p) ((p)->family)
diff --git a/lib/stream.c b/lib/stream.c
index 301ebc627..32dde1ca0 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -919,6 +919,31 @@ stream_put_prefix (struct stream *s, struct prefix *p)
return stream_put_prefix_addpath (s, p, 0, 0);
}
+/* Put NLRI with label */
+int
+stream_put_labeled_prefix (struct stream *s, struct prefix *p, u_char *label)
+{
+ size_t psize;
+
+ STREAM_VERIFY_SANE(s);
+
+ psize = PSIZE (p->prefixlen);
+
+ if (STREAM_WRITEABLE (s) < (psize + 3))
+ {
+ STREAM_BOUND_WARN (s, "put");
+ return 0;
+ }
+
+ stream_putc (s, (p->prefixlen + 24));
+ stream_putc(s, label[0]);
+ stream_putc(s, label[1]);
+ stream_putc(s, label[2]);
+ memcpy (s->data + s->endp, &p->u.prefix, psize);
+ s->endp += psize;
+
+ return (psize + 3);
+}
/* Read size from fd. */
int
diff --git a/lib/stream.h b/lib/stream.h
index 1e2bc89b3..b7bf31bf7 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -181,7 +181,8 @@ extern int stream_put_prefix_addpath (struct stream *, struct prefix *,
int addpath_encode,
u_int32_t addpath_tx_id);
extern int stream_put_prefix (struct stream *, struct prefix *);
-
+extern int stream_put_labeled_prefix (struct stream *, struct prefix *,
+ u_char *);
extern void stream_get (void *, struct stream *, size_t);
extern void stream_get_from (void *, struct stream *, size_t, size_t);
extern u_char stream_getc (struct stream *);
diff --git a/lib/thread.c b/lib/thread.c
index e707fc584..d4ed5d1a0 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -41,7 +41,7 @@ DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats")
#include <mach/mach_time.h>
#endif
-/* Relative time, since startup */
+static pthread_mutex_t cpu_record_mtx = PTHREAD_MUTEX_INITIALIZER;
static struct hash *cpu_record = NULL;
static unsigned long
@@ -137,9 +137,14 @@ cpu_record_print(struct vty *vty, thread_type filter)
vty_out(vty, "Active Runtime(ms) Invoked Avg uSec Max uSecs");
vty_out(vty, " Avg uSec Max uSecs");
vty_out(vty, " Type Thread%s", VTY_NEWLINE);
- hash_iterate(cpu_record,
- (void(*)(struct hash_backet*,void*))cpu_record_hash_print,
- args);
+
+ pthread_mutex_lock (&cpu_record_mtx);
+ {
+ hash_iterate(cpu_record,
+ (void(*)(struct hash_backet*,void*))cpu_record_hash_print,
+ args);
+ }
+ pthread_mutex_unlock (&cpu_record_mtx);
if (tmp.total_calls > 0)
vty_out_cpu_thread_history(vty, &tmp);
@@ -216,16 +221,25 @@ cpu_record_hash_clear (struct hash_backet *bucket,
if ( !(a->types & *filter) )
return;
- hash_release (cpu_record, bucket->data);
+ pthread_mutex_lock (&cpu_record_mtx);
+ {
+ hash_release (cpu_record, bucket->data);
+ }
+ pthread_mutex_unlock (&cpu_record_mtx);
}
static void
cpu_record_clear (thread_type filter)
{
thread_type *tmp = &filter;
- hash_iterate (cpu_record,
- (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
- tmp);
+
+ pthread_mutex_lock (&cpu_record_mtx);
+ {
+ hash_iterate (cpu_record,
+ (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
+ tmp);
+ }
+ pthread_mutex_unlock (&cpu_record_mtx);
}
DEFUN (clear_thread_cpu,
@@ -326,16 +340,20 @@ thread_master_create (void)
getrlimit(RLIMIT_NOFILE, &limit);
- if (cpu_record == NULL)
- cpu_record
- = hash_create ((unsigned int (*) (void *))cpu_record_hash_key,
- (int (*) (const void *, const void *))cpu_record_hash_cmp);
+ pthread_mutex_lock (&cpu_record_mtx);
+ {
+ if (cpu_record == NULL)
+ cpu_record = hash_create ((unsigned int (*) (void *))cpu_record_hash_key,
+ (int (*) (const void *, const void *))
+ cpu_record_hash_cmp);
+ }
+ pthread_mutex_unlock (&cpu_record_mtx);
rv = XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master));
if (rv == NULL)
- {
- return NULL;
- }
+ return NULL;
+
+ pthread_mutex_init (&rv->mtx, NULL);
rv->fd_limit = (int)limit.rlim_cur;
rv->read = XCALLOC (MTYPE_THREAD, sizeof (struct thread *) * rv->fd_limit);
@@ -358,6 +376,8 @@ thread_master_create (void)
rv->background = pqueue_create();
rv->timer->cmp = rv->background->cmp = thread_timer_cmp;
rv->timer->update = rv->background->update = thread_timer_update;
+ rv->spin = true;
+ rv->handle_signals = true;
#if defined(HAVE_POLL)
rv->handler.pfdsize = rv->fd_limit;
@@ -498,11 +518,16 @@ thread_queue_free (struct thread_master *m, struct pqueue *queue)
void
thread_master_free_unused (struct thread_master *m)
{
- struct thread *t;
- while ((t = thread_trim_head(&m->unuse)) != NULL)
- {
- XFREE(MTYPE_THREAD, t);
- }
+ pthread_mutex_lock (&m->mtx);
+ {
+ struct thread *t;
+ while ((t = thread_trim_head(&m->unuse)) != NULL)
+ {
+ pthread_mutex_destroy (&t->mtx);
+ XFREE(MTYPE_THREAD, t);
+ }
+ }
+ pthread_mutex_unlock (&m->mtx);
}
/* Stop thread scheduler. */
@@ -516,25 +541,37 @@ thread_master_free (struct thread_master *m)
thread_list_free (m, &m->ready);
thread_list_free (m, &m->unuse);
thread_queue_free (m, m->background);
+ pthread_mutex_destroy (&m->mtx);
#if defined(HAVE_POLL)
XFREE (MTYPE_THREAD_MASTER, m->handler.pfds);
#endif
XFREE (MTYPE_THREAD_MASTER, m);
- if (cpu_record)
- {
- hash_clean (cpu_record, cpu_record_hash_free);
- hash_free (cpu_record);
- cpu_record = NULL;
- }
+ pthread_mutex_lock (&cpu_record_mtx);
+ {
+ if (cpu_record)
+ {
+ hash_clean (cpu_record, cpu_record_hash_free);
+ hash_free (cpu_record);
+ cpu_record = NULL;
+ }
+ }
+ pthread_mutex_unlock (&cpu_record_mtx);
}
/* Return remain time in second. */
unsigned long
thread_timer_remain_second (struct thread *thread)
{
- int64_t remain = monotime_until(&thread->u.sands, NULL) / 1000000LL;
+ int64_t remain;
+
+ pthread_mutex_lock (&thread->mtx);
+ {
+ remain = monotime_until(&thread->u.sands, NULL) / 1000000LL;
+ }
+ pthread_mutex_unlock (&thread->mtx);
+
return remain < 0 ? 0 : remain;
}
@@ -545,7 +582,11 @@ struct timeval
thread_timer_remain(struct thread *thread)
{
struct timeval remain;
- monotime_until(&thread->u.sands, &remain);
+ pthread_mutex_lock (&thread->mtx);
+ {
+ monotime_until(&thread->u.sands, &remain);
+ }
+ pthread_mutex_unlock (&thread->mtx);
return remain;
}
@@ -560,8 +601,11 @@ thread_get (struct thread_master *m, u_char type,
if (! thread)
{
thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
+ /* mutex only needs to be initialized at struct creation. */
+ pthread_mutex_init (&thread->mtx, NULL);
m->alloc++;
}
+
thread->type = type;
thread->add_type = type;
thread->master = m;
@@ -584,8 +628,12 @@ thread_get (struct thread_master *m, u_char type,
{
tmp.func = func;
tmp.funcname = funcname;
- thread->hist = hash_get (cpu_record, &tmp,
- (void * (*) (void *))cpu_record_hash_alloc);
+ pthread_mutex_lock (&cpu_record_mtx);
+ {
+ thread->hist = hash_get (cpu_record, &tmp,
+ (void * (*) (void *))cpu_record_hash_alloc);
+ }
+ pthread_mutex_unlock (&cpu_record_mtx);
}
thread->hist->total_active++;
thread->func = func;
@@ -650,15 +698,45 @@ static int
fd_select (struct thread_master *m, int size, thread_fd_set *read, thread_fd_set *write, thread_fd_set *except, struct timeval *timer_wait)
{
int num;
+
+ /* If timer_wait is null here, that means either select() or poll() should
+ * block indefinitely, unless the thread_master has overriden it. select()
+ * and poll() differ in the timeout values they interpret as an indefinite
+ * block; select() requires a null pointer, while poll takes a millisecond
+ * value of -1.
+ *
+ * The thread_master owner has the option of overriding the default behavior
+ * by setting ->selectpoll_timeout. If the value is positive, it specifies
+ * the maximum number of milliseconds to wait. If the timeout is -1, it
+ * specifies that we should never wait and always return immediately even if
+ * no event is detected. If the value is zero, the behavior is default.
+ */
+
#if defined(HAVE_POLL)
- /* recalc timeout for poll. Attention NULL pointer is no timeout with
- select, where with poll no timeount is -1 */
int timeout = -1;
- if (timer_wait != NULL)
+
+ if (timer_wait != NULL && m->selectpoll_timeout == 0) // use the default value
timeout = (timer_wait->tv_sec*1000) + (timer_wait->tv_usec/1000);
+ else if (m->selectpoll_timeout > 0) // use the user's timeout
+ timeout = m->selectpoll_timeout;
+ else if (m->selectpoll_timeout < 0) // effect a poll (return immediately)
+ timeout = 0;
num = poll (m->handler.pfds, m->handler.pfdcount + m->handler.pfdcountsnmp, timeout);
#else
+ struct timeval timeout;
+ if (m->selectpoll_timeout > 0) // use the user's timeout
+ {
+ timeout.tv_sec = m->selectpoll_timeout / 1000;
+ timeout.tv_usec = (m->selectpoll_timeout % 1000) * 1000;
+ timer_wait = &timeout;
+ }
+ else if (m->selectpoll_timeout < 0) // effect a poll (return immediately)
+ {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ timer_wait = &timeout;
+ }
num = select (size, read, write, except, timer_wait);
#endif
@@ -703,36 +781,43 @@ funcname_thread_add_read_write (int dir, struct thread_master *m,
{
struct thread *thread = NULL;
-#if !defined(HAVE_POLL)
- thread_fd_set *fdset = NULL;
- if (dir == THREAD_READ)
- fdset = &m->handler.readfd;
- else
- fdset = &m->handler.writefd;
-#endif
-
+ pthread_mutex_lock (&m->mtx);
+ {
#if defined (HAVE_POLL)
- thread = generic_thread_add(m, func, arg, fd, dir, debugargpass);
-
- if (thread == NULL)
- return NULL;
+ thread = generic_thread_add(m, func, arg, fd, dir, debugargpass);
#else
- if (FD_ISSET (fd, fdset))
- {
- zlog_warn ("There is already %s fd [%d]",
- (dir == THREAD_READ) ? "read" : "write", fd);
- return NULL;
- }
+ thread_fd_set *fdset = NULL;
+ if (dir == THREAD_READ)
+ fdset = &m->handler.readfd;
+ else
+ fdset = &m->handler.writefd;
- FD_SET (fd, fdset);
- thread = thread_get (m, dir, func, arg, debugargpass);
+ if (FD_ISSET (fd, fdset))
+ {
+ zlog_warn ("There is already %s fd [%d]",
+ (dir == THREAD_READ) ? "read" : "write", fd);
+ }
+ else
+ {
+ FD_SET (fd, fdset);
+ thread = thread_get (m, dir, func, arg, debugargpass);
+ }
#endif
- thread->u.fd = fd;
- if (dir == THREAD_READ)
- thread_add_fd (m->read, thread);
- else
- thread_add_fd (m->write, thread);
+ if (thread)
+ {
+ pthread_mutex_lock (&thread->mtx);
+ {
+ thread->u.fd = fd;
+ if (dir == THREAD_READ)
+ thread_add_fd (m->read, thread);
+ else
+ thread_add_fd (m->write, thread);
+ }
+ pthread_mutex_unlock (&thread->mtx);
+ }
+ }
+ pthread_mutex_unlock (&m->mtx);
return thread;
}
@@ -753,13 +838,21 @@ funcname_thread_add_timer_timeval (struct thread_master *m,
assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
assert (time_relative);
- queue = ((type == THREAD_TIMER) ? m->timer : m->background);
- thread = thread_get (m, type, func, arg, debugargpass);
+ pthread_mutex_lock (&m->mtx);
+ {
+ queue = ((type == THREAD_TIMER) ? m->timer : m->background);
+ thread = thread_get (m, type, func, arg, debugargpass);
- monotime(&thread->u.sands);
- timeradd(&thread->u.sands, time_relative, &thread->u.sands);
+ pthread_mutex_lock (&thread->mtx);
+ {
+ monotime(&thread->u.sands);
+ timeradd(&thread->u.sands, time_relative, &thread->u.sands);
+ pqueue_enqueue(thread, queue);
+ }
+ pthread_mutex_unlock (&thread->mtx);
+ }
+ pthread_mutex_unlock (&m->mtx);
- pqueue_enqueue(thread, queue);
return thread;
}
@@ -847,9 +940,17 @@ funcname_thread_add_event (struct thread_master *m,
assert (m != NULL);
- thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass);
- thread->u.val = val;
- thread_list_add (&m->event, thread);
+ pthread_mutex_lock (&m->mtx);
+ {
+ thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass);
+ pthread_mutex_lock (&thread->mtx);
+ {
+ thread->u.val = val;
+ thread_list_add (&m->event, thread);
+ }
+ pthread_mutex_unlock (&thread->mtx);
+ }
+ pthread_mutex_unlock (&m->mtx);
return thread;
}
@@ -880,14 +981,22 @@ thread_cancel_read_or_write (struct thread *thread, short int state)
fd_clear_read_write (thread);
}
-/* Cancel thread from scheduler. */
+/**
+ * Cancel thread from scheduler.
+ *
+ * This function is *NOT* MT-safe. DO NOT call it from any other pthread except
+ * the one which owns thread->master.
+ */
void
thread_cancel (struct thread *thread)
{
struct thread_list *list = NULL;
struct pqueue *queue = NULL;
struct thread **thread_array = NULL;
-
+
+ pthread_mutex_lock (&thread->master->mtx);
+ pthread_mutex_lock (&thread->mtx);
+
switch (thread->type)
{
case THREAD_READ:
@@ -919,15 +1028,14 @@ thread_cancel (struct thread *thread)
queue = thread->master->background;
break;
default:
- return;
+ goto done;
break;
}
if (queue)
{
assert(thread->index >= 0);
- assert(thread == queue->array[thread->index]);
- pqueue_remove_at(thread->index, queue);
+ pqueue_remove (thread, queue);
}
else if (list)
{
@@ -943,6 +1051,10 @@ thread_cancel (struct thread *thread)
}
thread_add_unuse (thread->master, thread);
+
+done:
+ pthread_mutex_unlock (&thread->mtx);
+ pthread_mutex_unlock (&thread->master->mtx);
}
/* Delete all events which has argument value arg. */
@@ -951,39 +1063,48 @@ thread_cancel_event (struct thread_master *m, void *arg)
{
unsigned int ret = 0;
struct thread *thread;
+ struct thread *t;
- thread = m->event.head;
- while (thread)
- {
- struct thread *t;
-
- t = thread;
- thread = t->next;
-
- if (t->arg == arg)
+ pthread_mutex_lock (&m->mtx);
+ {
+ thread = m->event.head;
+ while (thread)
+ {
+ t = thread;
+ pthread_mutex_lock (&t->mtx);
{
- ret++;
- thread_list_delete (&m->event, t);
- thread_add_unuse (m, t);
+ thread = t->next;
+
+ if (t->arg == arg)
+ {
+ ret++;
+ thread_list_delete (&m->event, t);
+ thread_add_unuse (m, t);
+ }
}
- }
-
- /* thread can be on the ready list too */
- thread = m->ready.head;
- while (thread)
- {
- struct thread *t;
-
- t = thread;
- thread = t->next;
+ pthread_mutex_unlock (&t->mtx);
+ }
- if (t->arg == arg)
+ /* thread can be on the ready list too */
+ thread = m->ready.head;
+ while (thread)
+ {
+ t = thread;
+ pthread_mutex_lock (&t->mtx);
{
- ret++;
- thread_list_delete (&m->ready, t);
- thread_add_unuse (m, t);
+ thread = t->next;
+
+ if (t->arg == arg)
+ {
+ ret++;
+ thread_list_delete (&m->ready, t);
+ thread_add_unuse (m, t);
+ }
}
- }
+ pthread_mutex_unlock (&t->mtx);
+ }
+ }
+ pthread_mutex_unlock (&m->mtx);
return ret;
}
@@ -1143,18 +1264,24 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
struct timeval *timer_wait = &timer_val;
struct timeval *timer_wait_bg;
- while (1)
+ do
{
int num = 0;
/* Signals pre-empt everything */
- quagga_sigevent_process ();
+ if (m->handle_signals)
+ quagga_sigevent_process ();
+ pthread_mutex_lock (&m->mtx);
/* Drain the ready queue of already scheduled jobs, before scheduling
* more.
*/
if ((thread = thread_trim_head (&m->ready)) != NULL)
- return thread_run (m, thread, fetch);
+ {
+ fetch = thread_run (m, thread, fetch);
+ pthread_mutex_unlock (&m->mtx);
+ return fetch;
+ }
/* To be fair to all kinds of threads, and avoid starvation, we
* need to be careful to consider all thread types for scheduling
@@ -1194,8 +1321,12 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
if (num < 0)
{
if (errno == EINTR)
- continue; /* signal received - process it */
+ {
+ pthread_mutex_unlock (&m->mtx);
+ continue; /* signal received - process it */
+ }
zlog_warn ("select() error: %s", safe_strerror (errno));
+ pthread_mutex_unlock (&m->mtx);
return NULL;
}
@@ -1215,15 +1346,28 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
list at this time. If this is code is uncommented, then background
timer threads will not run unless there is nothing else to do. */
if ((thread = thread_trim_head (&m->ready)) != NULL)
- return thread_run (m, thread, fetch);
+ {
+ fetch = thread_run (m, thread, fetch);
+ pthread_mutex_unlock (&m->mtx);
+ return fetch;
+ }
#endif
/* Background timer/events, lowest priority */
thread_timer_process (m->background, &now);
if ((thread = thread_trim_head (&m->ready)) != NULL)
- return thread_run (m, thread, fetch);
- }
+ {
+ fetch = thread_run (m, thread, fetch);
+ pthread_mutex_unlock (&m->mtx);
+ return fetch;
+ }
+
+ pthread_mutex_unlock (&m->mtx);
+
+ } while (m->spin);
+
+ return NULL;
}
unsigned long
@@ -1248,13 +1392,23 @@ thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
int
thread_should_yield (struct thread *thread)
{
- return monotime_since(&thread->real, NULL) > (int64_t)thread->yield;
+ int result;
+ pthread_mutex_lock (&thread->mtx);
+ {
+ result = monotime_since(&thread->real, NULL) > (int64_t)thread->yield;
+ }
+ pthread_mutex_unlock (&thread->mtx);
+ return result;
}
void
thread_set_yield_time (struct thread *thread, unsigned long yield_time)
{
- thread->yield = yield_time;
+ pthread_mutex_lock (&thread->mtx);
+ {
+ thread->yield = yield_time;
+ }
+ pthread_mutex_unlock (&thread->mtx);
}
void
@@ -1324,6 +1478,7 @@ funcname_thread_execute (struct thread_master *m,
memset (&dummy, 0, sizeof (struct thread));
+ pthread_mutex_init (&dummy.mtx, NULL);
dummy.type = THREAD_EVENT;
dummy.add_type = THREAD_EXECUTE;
dummy.master = NULL;
@@ -1332,8 +1487,12 @@ funcname_thread_execute (struct thread_master *m,
tmp.func = dummy.func = func;
tmp.funcname = dummy.funcname = funcname;
- dummy.hist = hash_get (cpu_record, &tmp,
- (void * (*) (void *))cpu_record_hash_alloc);
+ pthread_mutex_lock (&cpu_record_mtx);
+ {
+ dummy.hist = hash_get (cpu_record, &tmp,
+ (void * (*) (void *))cpu_record_hash_alloc);
+ }
+ pthread_mutex_unlock (&cpu_record_mtx);
dummy.schedfrom = schedfrom;
dummy.schedfrom_line = fromln;
diff --git a/lib/thread.h b/lib/thread.h
index 34adcc4d0..18fd340ba 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -24,6 +24,7 @@
#include <zebra.h>
#include "monotime.h"
+#include <pthread.h>
struct rusage_t
{
@@ -84,6 +85,10 @@ struct thread_master
int fd_limit;
struct fd_handler handler;
unsigned long alloc;
+ long selectpoll_timeout;
+ bool spin;
+ bool handle_signals;
+ pthread_mutex_t mtx;
};
typedef unsigned char thread_type;
@@ -110,6 +115,7 @@ struct thread
const char *funcname;
const char *schedfrom;
int schedfrom_line;
+ pthread_mutex_t mtx;
};
struct cpu_thread_history
diff --git a/lib/vty.c b/lib/vty.c
index bd0b1c321..225a82c2d 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -746,9 +746,11 @@ vty_end_config (struct vty *vty)
case BGP_VNC_L2_GROUP_NODE:
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
+ case BGP_IPV4L_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
case BGP_EVPN_NODE:
+ case BGP_IPV6L_NODE:
case RMAP_NODE:
case OSPF_NODE:
case OSPF6_NODE:
diff --git a/lib/zclient.c b/lib/zclient.c
index d2a518631..e3eadf22a 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -733,6 +733,18 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
s = zclient->obuf;
stream_reset (s);
+ /* Some checks for labeled-unicast. The current expectation is that each
+ * nexthop is accompanied by a label in the case of labeled-unicast.
+ */
+ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) &&
+ CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+ {
+ /* We expect prefixes installed with labels and the number to match
+ * the number of nexthops.
+ */
+ assert (api->label_num == api->nexthop_num);
+ }
+
zclient_create_header (s, cmd, api->vrf_id);
/* Put type and nexthop. */
@@ -749,7 +761,7 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
/* Nexthop, ifindex, distance and metric information. */
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
- {
+ {
/* traditional 32-bit data units */
if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
{
@@ -765,6 +777,9 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
{
stream_putc (s, NEXTHOP_TYPE_IPV4);
stream_put_in_addr (s, api->nexthop[i]);
+ /* For labeled-unicast, each nexthop is followed by label. */
+ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL))
+ stream_putl (s, api->label[i]);
}
for (i = 0; i < api->ifindex_num; i++)
{
@@ -800,6 +815,18 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
s = zclient->obuf;
stream_reset (s);
+ /* Some checks for labeled-unicast. The current expectation is that each
+ * nexthop is accompanied by a label in the case of labeled-unicast.
+ */
+ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) &&
+ CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+ {
+ /* We expect prefixes installed with labels and the number to match
+ * the number of nexthops.
+ */
+ assert (api->label_num == api->nexthop_num);
+ }
+
zclient_create_header (s, cmd, api->vrf_id);
/* Put type and nexthop. */
@@ -831,6 +858,9 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
{
stream_putc (s, NEXTHOP_TYPE_IPV6);
stream_write (s, (u_char *)api->nexthop[i], 16);
+ /* For labeled-unicast, each nexthop is followed by label. */
+ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL))
+ stream_putl (s, api->label[i]);
}
for (i = 0; i < api->ifindex_num; i++)
{
@@ -869,6 +899,18 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
s = zclient->obuf;
stream_reset (s);
+ /* Some checks for labeled-unicast. The current expectation is that each
+ * nexthop is accompanied by a label in the case of labeled-unicast.
+ */
+ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) &&
+ CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+ {
+ /* We expect prefixes installed with labels and the number to match
+ * the number of nexthops.
+ */
+ assert (api->label_num == api->nexthop_num);
+ }
+
zclient_create_header (s, cmd, api->vrf_id);
/* Put type and nexthop. */
@@ -907,6 +949,9 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
{
stream_putc (s, NEXTHOP_TYPE_IPV6);
stream_write (s, (u_char *)api->nexthop[i], 16);
+ /* For labeled-unicast, each nexthop is followed by label. */
+ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL))
+ stream_putl (s, api->label[i]);
}
for (i = 0; i < api->ifindex_num; i++)
{
@@ -1879,6 +1924,12 @@ zclient_read (struct thread *thread)
if (zclient->interface_link_params)
(*zclient->interface_link_params) (command, zclient, length);
break;
+ case ZEBRA_FEC_UPDATE:
+ if (zclient_debug)
+ zlog_debug("zclient rcvd fec update\n");
+ if (zclient->fec_update)
+ (*zclient->fec_update) (command, zclient, length);
+ break;
default:
break;
}
diff --git a/lib/zclient.h b/lib/zclient.h
index d3d0a202c..a54bf420d 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -94,6 +94,9 @@ typedef enum {
ZEBRA_LABEL_MANAGER_CONNECT,
ZEBRA_GET_LABEL_CHUNK,
ZEBRA_RELEASE_LABEL_CHUNK,
+ ZEBRA_FEC_REGISTER,
+ ZEBRA_FEC_UNREGISTER,
+ ZEBRA_FEC_UPDATE,
} zebra_message_types_t;
struct redist_proto
@@ -164,6 +167,7 @@ struct zclient
int (*redistribute_route_ipv4_del) (int, struct zclient *, uint16_t, vrf_id_t);
int (*redistribute_route_ipv6_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*redistribute_route_ipv6_del) (int, struct zclient *, uint16_t, vrf_id_t);
+ int (*fec_update) (int, struct zclient *, uint16_t);
};
/* Zebra API message flag. */
@@ -174,6 +178,7 @@ struct zclient
#define ZAPI_MESSAGE_TAG 0x10
#define ZAPI_MESSAGE_MTU 0x20
#define ZAPI_MESSAGE_SRCPFX 0x40
+#define ZAPI_MESSAGE_LABEL 0x80
/* Zserv protocol message header */
struct zserv_header
@@ -206,6 +211,9 @@ struct zapi_ipv4
u_char ifindex_num;
ifindex_t *ifindex;
+ u_char label_num;
+ unsigned int *label;
+
u_char distance;
u_int32_t metric;
@@ -297,6 +305,9 @@ struct zapi_ipv6
u_char ifindex_num;
ifindex_t *ifindex;
+ u_char label_num;
+ unsigned int *label;
+
u_char distance;
u_int32_t metric;
diff --git a/lib/zebra.h b/lib/zebra.h
index 760264d75..cd72dc67f 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -393,6 +393,9 @@ extern const char *zserv_command_string (unsigned int command);
#define ZEBRA_FLAG_SCOPE_LINK 0x100
#define ZEBRA_FLAG_FIB_OVERRIDE 0x200
+/* Zebra FEC flags. */
+#define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x1
+
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */
#endif
@@ -413,11 +416,13 @@ typedef enum {
#define SAFI_ENCAP 5
#define SAFI_RESERVED_5 5
#define SAFI_EVPN 6
-#define SAFI_MAX 7
+#define SAFI_LABELED_UNICAST 7
+#define SAFI_MAX 8
#define IANA_SAFI_RESERVED 0
#define IANA_SAFI_UNICAST 1
#define IANA_SAFI_MULTICAST 2
+#define IANA_SAFI_LABELED_UNICAST 4
#define IANA_SAFI_ENCAP 7
#define IANA_SAFI_MPLS_VPN 128
@@ -512,6 +517,8 @@ static inline safi_t safi_iana2int (safi_t safi)
return SAFI_ENCAP;
if (safi == IANA_SAFI_EVPN)
return SAFI_EVPN;
+ if (safi == IANA_SAFI_LABELED_UNICAST)
+ return SAFI_LABELED_UNICAST;
return SAFI_MAX;
}
@@ -527,6 +534,8 @@ static inline safi_t safi_int2iana (safi_t safi)
return IANA_SAFI_ENCAP;
if (safi == SAFI_EVPN)
return IANA_SAFI_EVPN;
+ if (safi == SAFI_LABELED_UNICAST)
+ return IANA_SAFI_LABELED_UNICAST;
return IANA_SAFI_RESERVED;
}
diff --git a/tools/etc/iproute2/rt_protos.d/frr.conf b/tools/etc/iproute2/rt_protos.d/frr.conf
new file mode 100644
index 000000000..3f55b1126
--- /dev/null
+++ b/tools/etc/iproute2/rt_protos.d/frr.conf
@@ -0,0 +1,8 @@
+# Additional protocol strings defined by frr for each of its daemons
+
+186 bgp
+187 isis
+188 ospf
+189 rip
+190 ripng
+191 static
diff --git a/tools/frr b/tools/frr
index 8ae0b0a6e..ad3745147 100755
--- a/tools/frr
+++ b/tools/frr
@@ -532,8 +532,15 @@ case "$1" in
fi
if [ -z "$dmn" -o "$dmn" = "zebra" ]; then
- echo "Removing all routes made by zebra."
+ echo "Removing all routes made by FRR."
+ ip route flush proto bgp
+ ip route flush proto ospf
+ ip route flush proto static
+ ip route flush proto rip
+ ip route flush proto ripng
ip route flush proto zebra
+ ip route flush proto isis
+
else
[ -n "$dmn" ] && eval "${dmn/-/_}=0"
start_watchfrr
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 0af17abea..d545a73be 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -310,7 +310,8 @@ vtysh_execute_func (const char *line, int pager)
|| saved_node == BGP_ENCAP_NODE || saved_node == BGP_ENCAPV6_NODE
|| saved_node == BGP_IPV4_NODE
|| saved_node == BGP_IPV6_NODE || saved_node == BGP_IPV4M_NODE
- || saved_node == BGP_IPV6M_NODE || saved_node == BGP_EVPN_NODE)
+ || saved_node == BGP_IPV4L_NODE || saved_node == BGP_IPV6L_NODE
+ || saved_node == BGP_IPV6M_NODE || saved_node == BGP_EVPN_NODE)
&& (tried == 1))
{
vtysh_execute("exit-address-family");
@@ -948,6 +949,12 @@ static struct cmd_node bgp_ipv4m_node =
"%s(config-router-af)# "
};
+static struct cmd_node bgp_ipv4l_node =
+{
+ BGP_IPV4L_NODE,
+ "%s(config-router-af)# "
+};
+
static struct cmd_node bgp_ipv6_node =
{
BGP_IPV6_NODE,
@@ -966,6 +973,12 @@ static struct cmd_node bgp_evpn_node =
"%s(config-router-af)# "
};
+static struct cmd_node bgp_ipv6l_node =
+{
+ BGP_IPV6L_NODE,
+ "%s(config-router-af)# "
+};
+
static struct cmd_node bgp_vnc_defaults_node =
{
BGP_VNC_DEFAULTS_NODE,
@@ -1122,7 +1135,7 @@ DEFUNSH (VTYSH_BGPD,
"address-family vpnv4 [unicast]",
"Enter Address Family command mode\n"
"Address Family\n"
- "Address Family Modifier\n")
+ "Address Family modifier\n")
{
vty->node = BGP_VPNV4_NODE;
return CMD_SUCCESS;
@@ -1134,7 +1147,7 @@ DEFUNSH (VTYSH_BGPD,
"address-family vpnv6 [unicast]",
"Enter Address Family command mode\n"
"Address Family\n"
- "Address Family Modifier\n")
+ "Address Family modifier\n")
{
vty->node = BGP_VPNV6_NODE;
return CMD_SUCCESS;
@@ -1164,15 +1177,16 @@ DEFUNSH (VTYSH_BGPD,
}
DEFUNSH (VTYSH_BGPD,
- address_family_ipv4_unicast,
- address_family_ipv4_unicast_cmd,
- "address-family ipv4 [<unicast|multicast|vpn|encap>]",
- "Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family Modifier\n"
- "Address Family Modifier\n"
- "Address Family Modifier\n"
- "Address Family Modifier\n")
+ address_family_ipv4,
+ address_family_ipv4_cmd,
+ "address-family ipv4 [<unicast|multicast|vpn|encap|labeled-unicast>]",
+ "Enter Address Family command mode\n"
+ "Address Family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n")
{
int idx = 0;
@@ -1185,6 +1199,9 @@ DEFUNSH (VTYSH_BGPD,
else if (argv_find (argv, argc, "vpn", &idx))
vty->node = BGP_VPNV4_NODE;
+ else if (argv_find (argv, argc, "labeled-unicast", &idx))
+ vty->node = BGP_IPV4L_NODE;
+
else
vty->node = BGP_IPV4_NODE;
@@ -1192,15 +1209,16 @@ DEFUNSH (VTYSH_BGPD,
}
DEFUNSH (VTYSH_BGPD,
- address_family_ipv6,
- address_family_ipv6_cmd,
- "address-family ipv6 [<unicast|multicast|vpn|encap>]",
- "Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family Modifier\n"
- "Address Family Modifier\n"
- "Address Family Modifier\n"
- "Address Family Modifier\n")
+ address_family_ipv6,
+ address_family_ipv6_cmd,
+ "address-family ipv6 [<unicast|multicast|vpn|encap|labeled-unicast>]",
+ "Enter Address Family command mode\n"
+ "Address Family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n")
{
int idx = 0;
@@ -1213,6 +1231,9 @@ DEFUNSH (VTYSH_BGPD,
else if (argv_find (argv, argc, "vpn", &idx))
vty->node = BGP_VPNV6_NODE;
+ else if (argv_find (argv, argc, "labeled-unicast", &idx))
+ vty->node = BGP_IPV6L_NODE;
+
else
vty->node = BGP_IPV6_NODE;
@@ -1550,8 +1571,10 @@ vtysh_exit (struct vty *vty)
case BGP_ENCAPV6_NODE:
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
+ case BGP_IPV4L_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
+ case BGP_IPV6L_NODE:
case BGP_VRF_POLICY_NODE:
case BGP_EVPN_NODE:
case BGP_VNC_DEFAULTS_NODE:
@@ -1610,11 +1633,13 @@ DEFUNSH (VTYSH_BGPD,
{
if (vty->node == BGP_IPV4_NODE
|| vty->node == BGP_IPV4M_NODE
+ || vty->node == BGP_IPV4L_NODE
|| vty->node == BGP_VPNV4_NODE
|| vty->node == BGP_VPNV6_NODE
|| vty->node == BGP_ENCAP_NODE
|| vty->node == BGP_ENCAPV6_NODE
|| vty->node == BGP_IPV6_NODE
+ || vty->node == BGP_IPV6L_NODE
|| vty->node == BGP_IPV6M_NODE)
vty->node = BGP_NODE;
return CMD_SUCCESS;
@@ -3160,8 +3185,10 @@ vtysh_init_vty (void)
install_node (&bgp_encapv6_node, NULL);
install_node (&bgp_ipv4_node, NULL);
install_node (&bgp_ipv4m_node, NULL);
+ install_node (&bgp_ipv4l_node, NULL);
install_node (&bgp_ipv6_node, NULL);
install_node (&bgp_ipv6m_node, NULL);
+ install_node (&bgp_ipv6l_node, NULL);
install_node (&bgp_vrf_policy_node, NULL);
install_node (&bgp_evpn_node, NULL);
install_node (&bgp_vnc_defaults_node, NULL);
@@ -3199,9 +3226,11 @@ vtysh_init_vty (void)
vtysh_install_default (BGP_ENCAPV6_NODE);
vtysh_install_default (BGP_IPV4_NODE);
vtysh_install_default (BGP_IPV4M_NODE);
+ vtysh_install_default (BGP_IPV4L_NODE);
vtysh_install_default (BGP_IPV6_NODE);
vtysh_install_default (BGP_IPV6M_NODE);
vtysh_install_default (BGP_EVPN_NODE);
+ vtysh_install_default (BGP_IPV6L_NODE);
#if ENABLE_BGP_VNC
vtysh_install_default (BGP_VRF_POLICY_NODE);
vtysh_install_default (BGP_VNC_DEFAULTS_NODE);
@@ -3273,11 +3302,15 @@ vtysh_init_vty (void)
install_element (BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd);
install_element (BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_IPV4M_NODE, &vtysh_quit_bgpd_cmd);
+ install_element (BGP_IPV4L_NODE, &vtysh_exit_bgpd_cmd);
+ install_element (BGP_IPV4L_NODE, &vtysh_quit_bgpd_cmd);
install_element (BGP_IPV6_NODE, &vtysh_exit_bgpd_cmd);
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);
+ install_element (BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd);
+ install_element (BGP_IPV6L_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);
@@ -3317,12 +3350,14 @@ vtysh_init_vty (void)
install_element (BGP_NODE, &vtysh_end_all_cmd);
install_element (BGP_IPV4_NODE, &vtysh_end_all_cmd);
install_element (BGP_IPV4M_NODE, &vtysh_end_all_cmd);
+ install_element (BGP_IPV4L_NODE, &vtysh_end_all_cmd);
install_element (BGP_VPNV4_NODE, &vtysh_end_all_cmd);
install_element (BGP_VPNV6_NODE, &vtysh_end_all_cmd);
install_element (BGP_ENCAP_NODE, &vtysh_end_all_cmd);
install_element (BGP_ENCAPV6_NODE, &vtysh_end_all_cmd);
install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd);
install_element (BGP_IPV6M_NODE, &vtysh_end_all_cmd);
+ install_element (BGP_IPV6L_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);
@@ -3379,7 +3414,7 @@ vtysh_init_vty (void)
install_element (BGP_NODE, &vnc_nve_group_cmd);
install_element (BGP_NODE, &vnc_l2_group_cmd);
#endif
- install_element (BGP_NODE, &address_family_ipv4_unicast_cmd);
+ install_element (BGP_NODE, &address_family_ipv4_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);
@@ -3388,9 +3423,11 @@ vtysh_init_vty (void)
install_element (BGP_ENCAPV6_NODE, &exit_address_family_cmd);
install_element (BGP_IPV4_NODE, &exit_address_family_cmd);
install_element (BGP_IPV4M_NODE, &exit_address_family_cmd);
+ install_element (BGP_IPV4L_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_IPV6L_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);
diff --git a/zebra/Makefile.am b/zebra/Makefile.am
index 3e0de3b46..6c5e06906 100644
--- a/zebra/Makefile.am
+++ b/zebra/Makefile.am
@@ -31,7 +31,7 @@ zebra_SOURCES = \
redistribute.c debug.c rtadv.c zebra_vty.c \
irdp_main.c irdp_interface.c irdp_packet.c router-id.c \
zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \
- zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls.c zebra_mpls_vty.c \
+ zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls_vty.c \
zebra_mroute.c \
label_manager.c \
# end
@@ -40,7 +40,7 @@ testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
zebra_vty.c zebra_ptm.c zebra_routemap.c zebra_ns.c zebra_vrf.c \
kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c \
zebra_ptm_null.c rtadv_null.c if_null.c zserv_null.c zebra_static.c \
- zebra_memory.c zebra_mpls.c zebra_mpls_vty.c zebra_mpls_null.c
+ zebra_memory.c zebra_mpls_vty.c zebra_mpls_null.c
noinst_HEADERS = \
zebra_memory.h \
@@ -88,7 +88,7 @@ EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c \
rt_socket.c rtread_netlink.c rtread_sysctl.c \
rtread_getmsg.c kernel_socket.c kernel_netlink.c \
ioctl.c ioctl_solaris.c \
- zebra_mpls_netlink.c zebra_mpls_openbsd.c \
+ zebra_mpls_netlink.c zebra_mpls_openbsd.c zebra_mpls.c \
GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB
client : client_main.o ../lib/libfrr.la
diff --git a/zebra/interface.c b/zebra/interface.c
index 1d015e858..1eefe1339 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -691,6 +691,7 @@ if_delete_update (struct interface *ifp)
for setting ifindex to IFINDEX_INTERNAL after processing the
interface deletion message. */
ifp->ifindex = IFINDEX_INTERNAL;
+ ifp->node = NULL;
}
/* VRF change for an interface */
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 49394bd6f..e97420321 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -100,6 +100,11 @@ static const struct message rtproto_str[] = {
{RTPROT_BIRD, "BIRD"},
#endif /* RTPROT_BIRD */
{RTPROT_MROUTED, "mroute"},
+ {RTPROT_BGP, "BGP"},
+ {RTPROT_OSPF, "OSPF"},
+ {RTPROT_ISIS, "IS-IS"},
+ {RTPROT_RIP, "RIP"},
+ {RTPROT_RIPNG, "RIPNG"},
{0, NULL}
};
diff --git a/zebra/rib.h b/zebra/rib.h
index 5381d76b9..8f6cff0d8 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -372,7 +372,7 @@ extern void rib_init (void);
extern unsigned long rib_score_proto (u_char proto, u_short instance);
extern void rib_queue_add (struct route_node *rn);
extern void meta_queue_free (struct meta_queue *mq);
-
+extern int zebra_rib_labeled_unicast (struct rib *rib);
extern struct route_table *rib_table_ipv6;
extern void rib_unlink (struct route_node *, struct rib *);
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index a544593dd..77f03a2c6 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -103,6 +103,47 @@ struct gw_family_t
union g_addr gate;
};
+static inline int is_selfroute(int proto)
+{
+ if ((proto == RTPROT_BGP) || (proto == RTPROT_OSPF) ||
+ (proto == RTPROT_STATIC) || (proto == RTPROT_ZEBRA) ||
+ (proto == RTPROT_ISIS) || (proto == RTPROT_RIPNG)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static inline int get_rt_proto(int proto)
+{
+ switch (proto) {
+ case ZEBRA_ROUTE_BGP:
+ proto = RTPROT_BGP;
+ break;
+ case ZEBRA_ROUTE_OSPF:
+ case ZEBRA_ROUTE_OSPF6:
+ proto = RTPROT_OSPF;
+ break;
+ case ZEBRA_ROUTE_STATIC:
+ proto = RTPROT_STATIC;
+ break;
+ case ZEBRA_ROUTE_ISIS:
+ proto = RTPROT_ISIS;
+ break;
+ case ZEBRA_ROUTE_RIP:
+ proto = RTPROT_RIP;
+ break;
+ case ZEBRA_ROUTE_RIPNG:
+ proto = RTPROT_RIPNG;
+ break;
+ default:
+ proto = RTPROT_ZEBRA;
+ break;
+ }
+
+ return proto;
+}
+
/*
Pending: create an efficient table_id (in a tree/hash) based lookup)
*/
@@ -171,7 +212,7 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
return 0;
if (!startup &&
- rtm->rtm_protocol == RTPROT_ZEBRA &&
+ is_selfroute (rtm->rtm_protocol) &&
h->nlmsg_type == RTM_NEWROUTE)
return 0;
@@ -196,7 +237,7 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
}
/* Route which inserted by Zebra. */
- if (rtm->rtm_protocol == RTPROT_ZEBRA)
+ if (is_selfroute(rtm->rtm_protocol))
flags |= ZEBRA_FLAG_SELFROUTE;
if (tb[RTA_OIF])
@@ -1137,7 +1178,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct prefix *src_p,
req.r.rtm_family = family;
req.r.rtm_dst_len = p->prefixlen;
req.r.rtm_src_len = src_p ? src_p->prefixlen : 0;
- req.r.rtm_protocol = RTPROT_ZEBRA;
+ req.r.rtm_protocol = get_rt_proto(rib->type);
req.r.rtm_scope = RT_SCOPE_UNIVERSE;
if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h
index 93ee622e3..af58a0f0d 100644
--- a/zebra/rt_netlink.h
+++ b/zebra/rt_netlink.h
@@ -28,6 +28,14 @@
#define NL_DEFAULT_ROUTE_METRIC 20
+/* Additional protocol strings to push into routes */
+#define RTPROT_BGP 186
+#define RTPROT_ISIS 187
+#define RTPROT_OSPF 188
+#define RTPROT_RIP 189
+#define RTPROT_RIPNG 190
+
+
extern void
clear_nhlfe_installed (zebra_lsp_t *lsp);
extern int
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index 5a3ed7545..76263024c 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -47,6 +47,7 @@
#include "zebra/zebra_mpls.h"
DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object")
+DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object")
DEFINE_MTYPE_STATIC(ZEBRA, SLSP, "MPLS static LSP config")
DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object")
DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE, "MPLS static nexthop object")
@@ -58,6 +59,32 @@ int mpls_enabled;
extern struct zebra_t zebrad;
/* static function declarations */
+
+static void
+fec_evaluate (struct zebra_vrf *zvrf, int add);
+static u_int32_t
+fec_derive_label_from_index (struct zebra_vrf *vrf, zebra_fec_t *fec);
+static int
+lsp_install (struct zebra_vrf *zvrf, mpls_label_t label,
+ struct route_node *rn, struct rib *rib);
+static int
+lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t label);
+static int
+fec_change_update_lsp (struct zebra_vrf *zvrf, zebra_fec_t *fec, mpls_label_t old_label);
+static int
+fec_send (zebra_fec_t *fec, struct zserv *client);
+static void
+fec_update_clients (zebra_fec_t *fec);
+static void
+fec_print (zebra_fec_t *fec, struct vty *vty);
+static zebra_fec_t *
+fec_find (struct route_table *table, struct prefix *p);
+static zebra_fec_t *
+fec_add (struct route_table *table, struct prefix *p, mpls_label_t label,
+ u_int32_t flags, u_int32_t label_index);
+static int
+fec_del (zebra_fec_t *fec);
+
static unsigned int
label_hash (void *p);
static int
@@ -68,6 +95,7 @@ static int
nhlfe_nexthop_active_ipv6 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop);
static int
nhlfe_nexthop_active (zebra_nhlfe_t *nhlfe);
+
static void
lsp_select_best_nhlfe (zebra_lsp_t *lsp);
static void
@@ -84,21 +112,24 @@ static int
lsp_processq_add (zebra_lsp_t *lsp);
static void *
lsp_alloc (void *p);
+
static char *
nhlfe2str (zebra_nhlfe_t *nhlfe, char *buf, int size);
static int
nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
- union g_addr *gate, char *ifname, ifindex_t ifindex);
+ union g_addr *gate, ifindex_t ifindex);
static zebra_nhlfe_t *
nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
enum nexthop_types_t gtype, union g_addr *gate,
- char *ifname, ifindex_t ifindex);
+ ifindex_t ifindex);
static zebra_nhlfe_t *
nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
enum nexthop_types_t gtype, union g_addr *gate,
- char *ifname, ifindex_t ifindex, mpls_label_t out_label);
+ ifindex_t ifindex, mpls_label_t out_label);
static int
nhlfe_del (zebra_nhlfe_t *snhlfe);
+static void
+nhlfe_out_label_update (zebra_nhlfe_t *nhlfe, struct nexthop_label *nh_label);
static int
mpls_lsp_uninstall_all (struct hash *lsp_table, zebra_lsp_t *lsp,
enum lsp_types_t type);
@@ -112,14 +143,13 @@ static void *
slsp_alloc (void *p);
static int
snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
- union g_addr *gate, char *ifname, ifindex_t ifindex);
+ union g_addr *gate, ifindex_t ifindex);
static zebra_snhlfe_t *
snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
- union g_addr *gate, char *ifname, ifindex_t ifindex);
+ union g_addr *gate, ifindex_t ifindex);
static zebra_snhlfe_t *
snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
- union g_addr *gate, char *ifname, ifindex_t ifindex,
- mpls_label_t out_label);
+ union g_addr *gate, ifindex_t ifindex, mpls_label_t out_label);
static int
snhlfe_del (zebra_snhlfe_t *snhlfe);
static int
@@ -135,6 +165,469 @@ mpls_processq_init (struct zebra_t *zebra);
/* Static functions */
/*
+ * Install label forwarding entry based on labeled-route entry.
+ */
+static int
+lsp_install (struct zebra_vrf *zvrf, mpls_label_t label,
+ struct route_node *rn, struct rib *rib)
+{
+ struct hash *lsp_table;
+ zebra_ile_t tmp_ile;
+ zebra_lsp_t *lsp;
+ zebra_nhlfe_t *nhlfe;
+ struct nexthop *nexthop;
+ enum lsp_types_t lsp_type;
+ char buf[BUFSIZ];
+ int added, changed;
+
+ /* Lookup table. */
+ lsp_table = zvrf->lsp_table;
+ if (!lsp_table)
+ return -1;
+
+ /* See if route entry is selected; we really expect only 1 entry here. */
+ if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ return 0;
+
+ lsp_type = lsp_type_from_rib_type (rib->type);
+ added = changed = 0;
+
+ /* Locate or allocate LSP entry. */
+ tmp_ile.in_label = label;
+ lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc);
+ if (!lsp)
+ return -1;
+
+ /* For each active nexthop, create NHLFE. Note that we deliberately skip
+ * recursive nexthops right now, because intermediate hops won't understand
+ * the label advertised by the recursive nexthop (plus we don't have the
+ * logic yet to push multiple labels).
+ */
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ /* Skip inactive and recursive entries. */
+ if (!CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ continue;
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ continue;
+
+ nhlfe = nhlfe_find (lsp, lsp_type, nexthop->type, &nexthop->gate,
+ nexthop->ifindex);
+ if (nhlfe)
+ {
+ /* Clear deleted flag (in case it was set) */
+ UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
+ if (nexthop_labels_match (nhlfe->nexthop, nexthop))
+ /* No change */
+ continue;
+
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ {
+ nhlfe2str (nhlfe, buf, BUFSIZ);
+ zlog_debug ("LSP in-label %u type %d nexthop %s "
+ "out-label changed",
+ lsp->ile.in_label, lsp_type, buf);
+ }
+
+ /* Update out label, trigger processing. */
+ nhlfe_out_label_update (nhlfe, nexthop->nh_label);
+ SET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
+ changed++;
+ }
+ else
+ {
+ /* Add LSP entry to this nexthop */
+ nhlfe = nhlfe_add (lsp, lsp_type, nexthop->type,
+ &nexthop->gate, nexthop->ifindex,
+ nexthop->nh_label->label[0]);
+ if (!nhlfe)
+ return -1;
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ {
+ nhlfe2str (nhlfe, buf, BUFSIZ);
+ zlog_debug ("Add LSP in-label %u type %d nexthop %s "
+ "out-label %u",
+ lsp->ile.in_label, lsp_type, buf,
+ nexthop->nh_label->label[0]);
+ }
+
+ lsp->addr_family = NHLFE_FAMILY (nhlfe);
+
+ /* Mark NHLFE as changed. */
+ SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
+ added++;
+ }
+ }
+
+ /* Queue LSP for processing if necessary. If no NHLFE got added (special
+ * case), delete the LSP entry; this case results in somewhat ugly logging.
+ */
+ if (added || changed)
+ {
+ if (lsp_processq_add (lsp))
+ return -1;
+ }
+ else if (!lsp->nhlfe_list &&
+ !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED))
+ {
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug ("Free LSP in-label %u flags 0x%x",
+ lsp->ile.in_label, lsp->flags);
+
+ lsp = hash_release(lsp_table, &lsp->ile);
+ if (lsp)
+ XFREE(MTYPE_LSP, lsp);
+ }
+
+ return 0;
+}
+
+/*
+ * Uninstall all non-static NHLFEs of a label forwarding entry. If all
+ * NHLFEs are removed, the entire entry is deleted.
+ */
+static int
+lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t label)
+{
+ struct hash *lsp_table;
+ zebra_ile_t tmp_ile;
+ zebra_lsp_t *lsp;
+ zebra_nhlfe_t *nhlfe, *nhlfe_next;
+ char buf[BUFSIZ];
+
+ /* Lookup table. */
+ lsp_table = zvrf->lsp_table;
+ if (!lsp_table)
+ return -1;
+
+ /* If entry is not present, exit. */
+ tmp_ile.in_label = label;
+ lsp = hash_lookup (lsp_table, &tmp_ile);
+ if (!lsp || !lsp->nhlfe_list)
+ return 0;
+
+ /* Mark NHLFEs for delete or directly delete, as appropriate. */
+ for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next)
+ {
+ nhlfe_next = nhlfe->next;
+
+ /* Skip static NHLFEs */
+ if (nhlfe->type == ZEBRA_LSP_STATIC)
+ continue;
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ {
+ nhlfe2str (nhlfe, buf, BUFSIZ);
+ zlog_debug ("Del LSP in-label %u type %d nexthop %s flags 0x%x",
+ label, nhlfe->type, buf, nhlfe->flags);
+ }
+
+ if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED))
+ {
+ UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
+ SET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
+ }
+ else
+ {
+ nhlfe_del (nhlfe);
+ }
+ }
+
+ /* Queue LSP for processing, if needed, else delete. */
+ if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
+ {
+ if (lsp_processq_add (lsp))
+ return -1;
+ }
+ else if (!lsp->nhlfe_list &&
+ !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED))
+ {
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug ("Del LSP in-label %u flags 0x%x",
+ lsp->ile.in_label, lsp->flags);
+
+ lsp = hash_release(lsp_table, &lsp->ile);
+ if (lsp)
+ XFREE(MTYPE_LSP, lsp);
+ }
+
+ return 0;
+}
+
+/*
+ * This function is invoked upon change to label block configuration; it
+ * will walk all registered FECs with label-index and appropriately update
+ * their local labels and trigger client updates.
+ */
+static void
+fec_evaluate (struct zebra_vrf *zvrf, int add)
+{
+ struct route_node *rn;
+ zebra_fec_t *fec;
+ u_int32_t old_label, new_label;
+ int af;
+ char buf[BUFSIZ];
+
+ for (af = AFI_IP; af < AFI_MAX; af++)
+ {
+ if (zvrf->fec_table[af] == NULL)
+ continue;
+
+ for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
+ {
+ if ((fec = rn->info) == NULL)
+ continue;
+
+ /* Skip configured FECs and those without a label index. */
+ if (fec->flags & FEC_FLAG_CONFIGURED ||
+ fec->label_index == MPLS_INVALID_LABEL_INDEX)
+ continue;
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ prefix2str(&rn->p, buf, BUFSIZ);
+
+ /* Save old label, determine new label. */
+ old_label = fec->label;
+ if (add)
+ {
+ new_label = zvrf->mpls_srgb.start_label + fec->label_index;
+ if (new_label >= zvrf->mpls_srgb.end_label)
+ new_label = MPLS_INVALID_LABEL;
+ }
+ else
+ new_label = MPLS_INVALID_LABEL;
+
+ /* If label has changed, update FEC and clients. */
+ if (new_label == old_label)
+ continue;
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug ("Update fec %s new label %u upon label block %s",
+ buf, new_label, add ? "ADD" : "DEL");
+
+ fec->label = new_label;
+ fec_update_clients (fec);
+
+ /* Update label forwarding entries appropriately */
+ fec_change_update_lsp (zvrf, fec, old_label);
+ }
+ }
+}
+
+/*
+ * Derive (if possible) and update the local label for the FEC based on
+ * its label index. The index is "acceptable" if it falls within the
+ * globally configured label block (SRGB).
+ */
+static u_int32_t
+fec_derive_label_from_index (struct zebra_vrf *zvrf, zebra_fec_t *fec)
+{
+ u_int32_t label;
+
+ if (fec->label_index != MPLS_INVALID_LABEL_INDEX &&
+ zvrf->mpls_srgb.start_label &&
+ ((label = zvrf->mpls_srgb.start_label + fec->label_index) <
+ zvrf->mpls_srgb.end_label))
+ fec->label = label;
+ else
+ fec->label = MPLS_INVALID_LABEL;
+
+ return fec->label;
+}
+
+/*
+ * There is a change for this FEC. Install or uninstall label forwarding
+ * entries, as appropriate.
+ */
+static int
+fec_change_update_lsp (struct zebra_vrf *zvrf, zebra_fec_t *fec, mpls_label_t old_label)
+{
+ struct route_table *table;
+ struct route_node *rn;
+ struct rib *rib;
+ afi_t afi;
+
+ /* Uninstall label forwarding entry, if previously installed. */
+ if (old_label != MPLS_INVALID_LABEL &&
+ old_label != MPLS_IMP_NULL_LABEL)
+ lsp_uninstall (zvrf, old_label);
+
+ /* Install label forwarding entry corr. to new label, if needed. */
+ if (fec->label == MPLS_INVALID_LABEL ||
+ fec->label == MPLS_IMP_NULL_LABEL)
+ return 0;
+
+ afi = family2afi(PREFIX_FAMILY(&fec->rn->p));
+ table = zebra_vrf_table (afi, SAFI_UNICAST, zvrf_id (zvrf));
+ if (!table)
+ return 0;
+
+ /* See if labeled route exists. */
+ rn = route_node_lookup (table, &fec->rn->p);
+ if (!rn)
+ return 0;
+
+ RNODE_FOREACH_RIB (rn, rib)
+ {
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ break;
+ }
+
+ if (!rib || !zebra_rib_labeled_unicast (rib))
+ return 0;
+
+ if (lsp_install (zvrf, fec->label, rn, rib))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Inform about FEC to a registered client.
+ */
+static int
+fec_send (zebra_fec_t *fec, struct zserv *client)
+{
+ struct stream *s;
+ struct route_node *rn;
+
+ rn = fec->rn;
+
+ /* Get output stream. */
+ s = client->obuf;
+ stream_reset (s);
+
+ zserv_create_header (s, ZEBRA_FEC_UPDATE, VRF_DEFAULT);
+
+ stream_putw(s, rn->p.family);
+ stream_put_prefix (s, &rn->p);
+ stream_putl(s, fec->label);
+ stream_putw_at(s, 0, stream_get_endp(s));
+ return zebra_server_send_message(client);
+}
+
+/*
+ * Update all registered clients about this FEC. Caller should've updated
+ * FEC and ensure no duplicate updates.
+ */
+static void
+fec_update_clients (zebra_fec_t *fec)
+{
+ struct listnode *node;
+ struct zserv *client;
+
+ for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
+ {
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug ("Update client %s", zebra_route_string(client->proto));
+ fec_send(fec, client);
+ }
+}
+
+
+/*
+ * Print a FEC-label binding entry.
+ */
+static void
+fec_print (zebra_fec_t *fec, struct vty *vty)
+{
+ struct route_node *rn;
+ struct listnode *node;
+ struct zserv *client;
+ char buf[BUFSIZ];
+
+ rn = fec->rn;
+ prefix2str(&rn->p, buf, BUFSIZ);
+ vty_out(vty, "%s%s", buf, VTY_NEWLINE);
+ vty_out(vty, " Label: %s", label2str(fec->label, buf, BUFSIZ));
+ if (fec->label_index != MPLS_INVALID_LABEL_INDEX)
+ vty_out(vty, ", Label Index: %u", fec->label_index);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ if (!list_isempty(fec->client_list))
+ {
+ vty_out(vty, " Client list:");
+ for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
+ vty_out(vty, " %s(fd %d)",
+ zebra_route_string(client->proto), client->sock);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+}
+
+/*
+ * Locate FEC-label binding that matches with passed info.
+ */
+static zebra_fec_t *
+fec_find (struct route_table *table, struct prefix *p)
+{
+ struct route_node *rn;
+
+ apply_mask (p);
+ rn = route_node_lookup(table, p);
+ if (!rn)
+ return NULL;
+
+ route_unlock_node(rn);
+ return (rn->info);
+}
+
+/*
+ * Add a FEC. This may be upon a client registering for a binding
+ * or when a binding is configured.
+ */
+static zebra_fec_t *
+fec_add (struct route_table *table, struct prefix *p,
+ mpls_label_t label, u_int32_t flags, u_int32_t label_index)
+{
+ struct route_node *rn;
+ zebra_fec_t *fec;
+
+ apply_mask (p);
+
+ /* Lookup (or add) route node.*/
+ rn = route_node_get (table, p);
+ if (!rn)
+ return NULL;
+
+ fec = rn->info;
+
+ if (!fec)
+ {
+ fec = XCALLOC (MTYPE_FEC, sizeof(zebra_fec_t));
+ if (!fec)
+ return NULL;
+
+ rn->info = fec;
+ fec->rn = rn;
+ fec->label = label;
+ fec->client_list = list_new();
+ }
+ else
+ route_unlock_node (rn); /* for the route_node_get */
+
+ fec->label_index = label_index;
+ fec->flags = flags;
+
+ return fec;
+}
+
+/*
+ * Delete a FEC. This may be upon the last client deregistering for
+ * a FEC and no binding exists or when the binding is deleted and there
+ * are no registered clients.
+ */
+static int
+fec_del (zebra_fec_t *fec)
+{
+ list_free (fec->client_list);
+ fec->rn->info = NULL;
+ route_unlock_node (fec->rn);
+ XFREE (MTYPE_FEC, fec);
+ return 0;
+}
+
+/*
* Hash function for label.
*/
static unsigned int
@@ -602,7 +1095,7 @@ nhlfe2str (zebra_nhlfe_t *nhlfe, char *buf, int size)
*/
static int
nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
- union g_addr *gate, char *ifname, ifindex_t ifindex)
+ union g_addr *gate, ifindex_t ifindex)
{
struct nexthop *nhop;
int cmp = 1;
@@ -644,7 +1137,7 @@ nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
static zebra_nhlfe_t *
nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
enum nexthop_types_t gtype, union g_addr *gate,
- char *ifname, ifindex_t ifindex)
+ ifindex_t ifindex)
{
zebra_nhlfe_t *nhlfe;
@@ -655,7 +1148,7 @@ nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
{
if (nhlfe->type != lsp_type)
continue;
- if (!nhlfe_nhop_match (nhlfe, gtype, gate, ifname, ifindex))
+ if (!nhlfe_nhop_match (nhlfe, gtype, gate, ifindex))
break;
}
@@ -669,7 +1162,7 @@ nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
static zebra_nhlfe_t *
nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
enum nexthop_types_t gtype, union g_addr *gate,
- char *ifname, ifindex_t ifindex, mpls_label_t out_label)
+ ifindex_t ifindex, mpls_label_t out_label)
{
zebra_nhlfe_t *nhlfe;
struct nexthop *nexthop;
@@ -759,6 +1252,15 @@ nhlfe_del (zebra_nhlfe_t *nhlfe)
return 0;
}
+/*
+ * Update label for NHLFE entry.
+ */
+static void
+nhlfe_out_label_update (zebra_nhlfe_t *nhlfe, struct nexthop_label *nh_label)
+{
+ nhlfe->nexthop->nh_label->label[0] = nh_label->label[0];
+}
+
static int
mpls_lsp_uninstall_all (struct hash *lsp_table, zebra_lsp_t *lsp,
enum lsp_types_t type)
@@ -1026,7 +1528,7 @@ slsp_cmp (zebra_slsp_t *slsp1, zebra_slsp_t *slsp2)
*/
static int
snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
- union g_addr *gate, char *ifname, ifindex_t ifindex)
+ union g_addr *gate, ifindex_t ifindex)
{
int cmp = 1;
@@ -1058,7 +1560,7 @@ snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
*/
static zebra_snhlfe_t *
snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
- union g_addr *gate, char *ifname, ifindex_t ifindex)
+ union g_addr *gate, ifindex_t ifindex)
{
zebra_snhlfe_t *snhlfe;
@@ -1067,7 +1569,7 @@ snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next)
{
- if (!snhlfe_match (snhlfe, gtype, gate, ifname, ifindex))
+ if (!snhlfe_match (snhlfe, gtype, gate, ifindex))
break;
}
@@ -1081,7 +1583,7 @@ snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
*/
static zebra_snhlfe_t *
snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
- union g_addr *gate, char *ifname, ifindex_t ifindex,
+ union g_addr *gate, ifindex_t ifindex,
mpls_label_t out_label)
{
zebra_snhlfe_t *snhlfe;
@@ -1230,7 +1732,7 @@ mpls_str2label (const char *label_str, u_int8_t *num_labels,
*num_labels = 0;
for (i = 0; i < MPLS_MAX_LABELS; i++)
{
- u_int32_t label;
+ mpls_label_t label;
label = strtoul(label_str, &endp, 0);
@@ -1275,6 +1777,486 @@ mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
}
/*
+ * Install dynamic LSP entry.
+ */
+int
+zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib)
+{
+ struct route_table *table;
+ zebra_fec_t *fec;
+
+ table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
+ if (!table)
+ return -1;
+
+ /* See if there is a configured label binding for this FEC. */
+ fec = fec_find (table, &rn->p);
+ if (!fec || fec->label == MPLS_INVALID_LABEL)
+ return 0;
+
+ /* We cannot install a label forwarding entry if local label is the
+ * implicit-null label.
+ */
+ if (fec->label == MPLS_IMP_NULL_LABEL)
+ return 0;
+
+ if (lsp_install (zvrf, fec->label, rn, rib))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Uninstall dynamic LSP entry, if any.
+ */
+int
+zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib)
+{
+ struct route_table *table;
+ zebra_fec_t *fec;
+
+ table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
+ if (!table)
+ return -1;
+
+ /* See if there is a configured label binding for this FEC. */
+ fec = fec_find (table, &rn->p);
+ if (!fec || fec->label == MPLS_INVALID_LABEL)
+ return 0;
+
+ /* Uninstall always removes all dynamic NHLFEs. */
+ return lsp_uninstall (zvrf, fec->label);
+}
+
+/*
+ * Registration from a client for the label binding for a FEC. If a binding
+ * already exists, it is informed to the client.
+ * NOTE: If there is a manually configured label binding, that is used.
+ * Otherwise, if aa label index is specified, it means we have to allocate the
+ * label from a locally configured label block (SRGB), if one exists and index
+ * is acceptable.
+ */
+int
+zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
+ u_int32_t label_index, struct zserv *client)
+{
+ struct route_table *table;
+ zebra_fec_t *fec;
+ char buf[BUFSIZ];
+ int new_client;
+ int label_change = 0;
+ u_int32_t old_label;
+
+ table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+ if (!table)
+ return -1;
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ prefix2str(p, buf, BUFSIZ);
+
+ /* Locate FEC */
+ fec = fec_find (table, p);
+ if (!fec)
+ {
+ fec = fec_add (table, p, MPLS_INVALID_LABEL, 0, label_index);
+ if (!fec)
+ {
+ prefix2str(p, buf, BUFSIZ);
+ zlog_err("Failed to add FEC %s upon register, client %s",
+ buf, zebra_route_string(client->proto));
+ return -1;
+ }
+
+ old_label = MPLS_INVALID_LABEL;
+ new_client = 1;
+ }
+ else
+ {
+ /* Client may register same FEC with different label index. */
+ new_client = (listnode_lookup(fec->client_list, client) == NULL);
+ if (!new_client && fec->label_index == label_index)
+ /* Duplicate register */
+ return 0;
+
+ /* Save current label, update label index */
+ old_label = fec->label;
+ fec->label_index = label_index;
+ }
+
+ if (new_client)
+ listnode_add (fec->client_list, client);
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug("FEC %s Label Index %u %s by client %s",
+ buf, label_index, new_client ? "registered" : "updated",
+ zebra_route_string(client->proto));
+
+ /* If not a configured FEC, derive the local label (from label index)
+ * or reset it.
+ */
+ if (!(fec->flags & FEC_FLAG_CONFIGURED))
+ {
+ fec_derive_label_from_index (zvrf, fec);
+
+ /* If no label change, exit. */
+ if (fec->label == old_label)
+ return 0;
+
+ label_change = 1;
+ }
+
+ /* If new client or label change, update client and install or uninstall
+ * label forwarding entry as needed.
+ */
+ /* Inform client of label, if needed. */
+ if ((new_client && fec->label != MPLS_INVALID_LABEL) ||
+ label_change)
+ {
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug ("Update client label %u", fec->label);
+ fec_send (fec, client);
+ }
+
+ if (new_client || label_change)
+ return fec_change_update_lsp (zvrf, fec, old_label);
+
+ return 0;
+}
+
+/*
+ * Deregistration from a client for the label binding for a FEC. The FEC
+ * itself is deleted if no other registered clients exist and there is no
+ * label bound to the FEC.
+ */
+int
+zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
+ struct zserv *client)
+{
+ struct route_table *table;
+ zebra_fec_t *fec;
+ char buf[BUFSIZ];
+
+ table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+ if (!table)
+ return -1;
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ prefix2str(p, buf, BUFSIZ);
+
+ fec = fec_find (table, p);
+ if (!fec)
+ {
+ prefix2str(p, buf, BUFSIZ);
+ zlog_err("Failed to find FEC %s upon unregister, client %s",
+ buf, zebra_route_string(client->proto));
+ return -1;
+ }
+
+ listnode_delete(fec->client_list, client);
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug("FEC %s unregistered by client %s",
+ buf, zebra_route_string(client->proto));
+
+ /* If not a configured entry, delete the FEC if no other clients. Before
+ * deleting, see if any LSP needs to be uninstalled.
+ */
+ if (!(fec->flags & FEC_FLAG_CONFIGURED) &&
+ list_isempty(fec->client_list))
+ {
+ mpls_label_t old_label = fec->label;
+ fec->label = MPLS_INVALID_LABEL; /* reset */
+ fec_change_update_lsp (zvrf, fec, old_label);
+ fec_del (fec);
+ }
+
+ return 0;
+}
+
+/*
+ * Cleanup any FECs registered by this client.
+ */
+int
+zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client)
+{
+ struct route_node *rn;
+ zebra_fec_t *fec;
+ struct listnode *node;
+ struct zserv *fec_client;
+ int af;
+
+ for (af = AFI_IP; af < AFI_MAX; af++)
+ {
+ if (zvrf->fec_table[af] == NULL)
+ continue;
+
+ for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
+ {
+ fec = rn->info;
+ if (!fec || list_isempty(fec->client_list))
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, fec_client))
+ {
+ if (fec_client == client)
+ {
+ listnode_delete(fec->client_list, fec_client);
+ if (!(fec->flags & FEC_FLAG_CONFIGURED) &&
+ list_isempty(fec->client_list))
+ fec_del (fec);
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Return FEC (if any) to which this label is bound.
+ * Note: Only works for per-prefix binding and when the label is not
+ * implicit-null.
+ * TODO: Currently walks entire table, can optimize later with another
+ * hash..
+ */
+zebra_fec_t *
+zebra_mpls_fec_for_label (struct zebra_vrf *zvrf, mpls_label_t label)
+{
+ struct route_node *rn;
+ zebra_fec_t *fec;
+ int af;
+
+ for (af = AFI_IP; af < AFI_MAX; af++)
+ {
+ if (zvrf->fec_table[af] == NULL)
+ continue;
+
+ for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
+ {
+ if (!rn->info)
+ continue;
+ fec = rn->info;
+ if (fec->label == label)
+ return fec;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Inform if specified label is currently bound to a FEC or not.
+ */
+int
+zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label)
+{
+ return (zebra_mpls_fec_for_label (zvrf, label) ? 1 : 0);
+}
+
+/*
+ * Add static FEC to label binding. If there are clients registered for this
+ * FEC, notify them. If there are labeled routes for this FEC, install the
+ * label forwarding entry.
+*/
+int
+zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
+ mpls_label_t in_label)
+{
+ struct route_table *table;
+ zebra_fec_t *fec;
+ char buf[BUFSIZ];
+ mpls_label_t old_label;
+ int ret = 0;
+
+ table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+ if (!table)
+ return -1;
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ prefix2str(p, buf, BUFSIZ);
+
+ /* Update existing FEC or create a new one. */
+ fec = fec_find (table, p);
+ if (!fec)
+ {
+ fec = fec_add (table, p, in_label, FEC_FLAG_CONFIGURED,
+ MPLS_INVALID_LABEL_INDEX);
+ if (!fec)
+ {
+ prefix2str(p, buf, BUFSIZ);
+ zlog_err ("Failed to add FEC %s upon config", buf);
+ return -1;
+ }
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug ("Add fec %s label %u", buf, in_label);
+ }
+ else
+ {
+ fec->flags |= FEC_FLAG_CONFIGURED;
+ if (fec->label == in_label)
+ /* Duplicate config */
+ return 0;
+
+ /* Label change, update clients. */
+ old_label = fec->label;
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug ("Update fec %s new label %u", buf, in_label);
+
+ fec->label = in_label;
+ fec_update_clients (fec);
+
+ /* Update label forwarding entries appropriately */
+ ret = fec_change_update_lsp (zvrf, fec, old_label);
+ }
+
+ return ret;
+}
+
+/*
+ * Remove static FEC to label binding. If there are no clients registered
+ * for this FEC, delete the FEC; else notify clients
+ * Note: Upon delete of static binding, if label index exists for this FEC,
+ * client may need to be updated with derived label.
+ */
+int
+zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
+{
+ struct route_table *table;
+ zebra_fec_t *fec;
+ mpls_label_t old_label;
+ char buf[BUFSIZ];
+
+ table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+ if (!table)
+ return -1;
+
+ fec = fec_find (table, p);
+ if (!fec)
+ {
+ prefix2str(p, buf, BUFSIZ);
+ zlog_err("Failed to find FEC %s upon delete", buf);
+ return -1;
+ }
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ {
+ prefix2str(p, buf, BUFSIZ);
+ zlog_debug ("Delete fec %s label index %u",
+ buf, fec->label_index);
+ }
+
+ old_label = fec->label;
+ fec->flags &= ~FEC_FLAG_CONFIGURED;
+ fec->label = MPLS_INVALID_LABEL;
+
+ /* If no client exists, just delete the FEC. */
+ if (list_isempty(fec->client_list))
+ {
+ fec_del (fec);
+ return 0;
+ }
+
+ /* Derive the local label (from label index) or reset it. */
+ fec_derive_label_from_index (zvrf, fec);
+
+ /* If there is a label change, update clients. */
+ if (fec->label == old_label)
+ return 0;
+ fec_update_clients (fec);
+
+ /* Update label forwarding entries appropriately */
+ return fec_change_update_lsp (zvrf, fec, old_label);
+}
+
+/*
+ * Display MPLS FEC to label binding configuration (VTY command handler).
+ */
+int
+zebra_mpls_write_fec_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+ struct route_node *rn;
+ int af;
+ zebra_fec_t *fec;
+ char buf[BUFSIZ];
+ int write = 0;
+
+ for (af = AFI_IP; af < AFI_MAX; af++)
+ {
+ if (zvrf->fec_table[af] == NULL)
+ continue;
+
+ for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
+ {
+ if (!rn->info)
+ continue;
+
+ char lstr[BUFSIZ];
+ fec = rn->info;
+
+ if (!(fec->flags & FEC_FLAG_CONFIGURED))
+ continue;
+
+ write = 1;
+ prefix2str(&rn->p, buf, BUFSIZ);
+ vty_out(vty, "mpls label bind %s %s%s", buf,
+ label2str(fec->label, lstr, BUFSIZ), VTY_NEWLINE);
+ }
+ }
+
+ return write;
+}
+
+/*
+ * Display MPLS FEC to label binding (VTY command handler).
+ */
+void
+zebra_mpls_print_fec_table (struct vty *vty, struct zebra_vrf *zvrf)
+{
+ struct route_node *rn;
+ int af;
+
+ for (af = AFI_IP; af < AFI_MAX; af++)
+ {
+ if (zvrf->fec_table[af] == NULL)
+ continue;
+
+ for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
+ {
+ if (!rn->info)
+ continue;
+ fec_print (rn->info, vty);
+ }
+ }
+}
+
+/*
+ * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
+ */
+void
+zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p)
+{
+ struct route_table *table;
+ struct route_node *rn;
+
+ table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+ if (!table)
+ return;
+
+ apply_mask (p);
+ rn = route_node_lookup(table, p);
+ if (!rn)
+ return;
+
+ route_unlock_node(rn);
+ if (!rn->info)
+ return;
+
+ fec_print (rn->info, vty);
+}
+
+/*
* Install/uninstall a FEC-To-NHLFE (FTN) binding.
*/
int
@@ -1361,7 +2343,7 @@ int
mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label, mpls_label_t out_label,
enum nexthop_types_t gtype, union g_addr *gate,
- char *ifname, ifindex_t ifindex)
+ ifindex_t ifindex)
{
struct hash *lsp_table;
zebra_ile_t tmp_ile;
@@ -1379,7 +2361,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc);
if (!lsp)
return -1;
- nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex);
+ nhlfe = nhlfe_find (lsp, type, gtype, gate, ifindex);
if (nhlfe)
{
struct nexthop *nh = nhlfe->nexthop;
@@ -1408,8 +2390,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
else
{
/* Add LSP entry to this nexthop */
- nhlfe = nhlfe_add (lsp, type, gtype, gate,
- ifname, ifindex, out_label);
+ nhlfe = nhlfe_add (lsp, type, gtype, gate, ifindex, out_label);
if (!nhlfe)
return -1;
@@ -1438,7 +2419,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
int
mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label, enum nexthop_types_t gtype,
- union g_addr *gate, char *ifname, ifindex_t ifindex)
+ union g_addr *gate, ifindex_t ifindex)
{
struct hash *lsp_table;
zebra_ile_t tmp_ile;
@@ -1456,7 +2437,7 @@ mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type,
lsp = hash_lookup (lsp_table, &tmp_ile);
if (!lsp)
return 0;
- nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex);
+ nhlfe = nhlfe_find (lsp, type, gtype, gate, ifindex);
if (!nhlfe)
return 0;
@@ -1561,7 +2542,7 @@ mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi)
int
zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
mpls_label_t out_label, enum nexthop_types_t gtype,
- union g_addr *gate, char *ifname, ifindex_t ifindex)
+ union g_addr *gate, ifindex_t ifindex)
{
struct hash *slsp_table;
zebra_ile_t tmp_ile;
@@ -1579,7 +2560,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
if (!slsp)
return 1;
- snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
+ snhlfe = snhlfe_find (slsp, gtype, gate, ifindex);
if (snhlfe)
{
if (snhlfe->out_label == out_label)
@@ -1619,7 +2600,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
int
zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
mpls_label_t out_label, enum nexthop_types_t gtype,
- union g_addr *gate, char *ifname, ifindex_t ifindex)
+ union g_addr *gate, ifindex_t ifindex)
{
struct hash *slsp_table;
zebra_ile_t tmp_ile;
@@ -1637,7 +2618,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
slsp = hash_get (slsp_table, &tmp_ile, slsp_alloc);
if (!slsp)
return -1;
- snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
+ snhlfe = snhlfe_find (slsp, gtype, gate, ifindex);
if (snhlfe)
{
if (snhlfe->out_label == out_label)
@@ -1656,7 +2637,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
else
{
/* Add static LSP entry to this nexthop */
- snhlfe = snhlfe_add (slsp, gtype, gate, ifname, ifindex, out_label);
+ snhlfe = snhlfe_add (slsp, gtype, gate, ifindex, out_label);
if (!snhlfe)
return -1;
@@ -1670,7 +2651,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
/* (Re)Install LSP in the main table. */
if (mpls_lsp_install (zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype,
- gate, ifname, ifindex))
+ gate, ifindex))
return -1;
return 0;
@@ -1686,7 +2667,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
int
zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
enum nexthop_types_t gtype, union g_addr *gate,
- char *ifname, ifindex_t ifindex)
+ ifindex_t ifindex)
{
struct hash *slsp_table;
zebra_ile_t tmp_ile;
@@ -1719,7 +2700,7 @@ zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
else
{
/* Find specific NHLFE, exit if not found. */
- snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
+ snhlfe = snhlfe_find (slsp, gtype, gate, ifindex);
if (!snhlfe)
return 0;
@@ -1733,7 +2714,7 @@ zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
/* Uninstall LSP from the main table. */
mpls_lsp_uninstall (zvrf, ZEBRA_LSP_STATIC, in_label, gtype, gate,
- ifname, ifindex);
+ ifindex);
/* Delete static LSP NHLFE */
snhlfe_del (snhlfe);
@@ -1902,6 +2883,51 @@ zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf)
}
/*
+ * Add/update global label block.
+ */
+int
+zebra_mpls_label_block_add (struct zebra_vrf *zvrf, u_int32_t start_label,
+ u_int32_t end_label)
+{
+ zvrf->mpls_srgb.start_label = start_label;
+ zvrf->mpls_srgb.end_label = end_label;
+
+ /* Evaluate registered FECs to see if any get a label or not. */
+ fec_evaluate (zvrf, 1);
+ return 0;
+}
+
+/*
+ * Delete global label block.
+ */
+int
+zebra_mpls_label_block_del (struct zebra_vrf *zvrf)
+{
+ zvrf->mpls_srgb.start_label = 0;
+ zvrf->mpls_srgb.end_label = 0;
+
+ /* Process registered FECs to clear their local label, if needed. */
+ fec_evaluate (zvrf, 0);
+ return 0;
+}
+
+/*
+ * Display MPLS global label block configuration (VTY command handler).
+ */
+int
+zebra_mpls_write_label_block_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+ if (zvrf->mpls_srgb.start_label == 0)
+ return 0;
+
+ vty_out(vty, "mpls label global-block %u %u%s",
+ zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label,
+ VTY_NEWLINE);
+
+ return 1;
+}
+
+/*
* Called upon process exiting, need to delete LSP forwarding
* entries from the kernel.
* NOTE: Currently supported only for default VRF.
@@ -1927,7 +2953,11 @@ zebra_mpls_init_tables (struct zebra_vrf *zvrf)
return;
zvrf->slsp_table = hash_create(label_hash, label_cmp);
zvrf->lsp_table = hash_create(label_hash, label_cmp);
+ zvrf->fec_table[AFI_IP] = route_table_init();
+ zvrf->fec_table[AFI_IP6] = route_table_init();
zvrf->mpls_flags = 0;
+ zvrf->mpls_srgb.start_label = 0;
+ zvrf->mpls_srgb.end_label = 0;
}
/*
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h
index a871fac65..e271edd2e 100644
--- a/zebra/zebra_mpls.h
+++ b/zebra/zebra_mpls.h
@@ -52,6 +52,7 @@ typedef struct zebra_snhlfe_t_ zebra_snhlfe_t;
typedef struct zebra_slsp_t_ zebra_slsp_t;
typedef struct zebra_nhlfe_t_ zebra_nhlfe_t;
typedef struct zebra_lsp_t_ zebra_lsp_t;
+typedef struct zebra_fec_t_ zebra_fec_t;
/*
* (Outgoing) nexthop label forwarding entry configuration
@@ -147,6 +148,27 @@ struct zebra_lsp_t_
u_char addr_family;
};
+/*
+ * FEC to label binding.
+ */
+struct zebra_fec_t_
+{
+ /* FEC (prefix) */
+ struct route_node *rn;
+
+ /* In-label - either statically bound or derived from label block. */
+ mpls_label_t label;
+
+ /* Label index (into global label block), if valid */
+ u_int32_t label_index;
+
+ /* Flags. */
+ u_int32_t flags;
+#define FEC_FLAG_CONFIGURED (1 << 0)
+
+ /* Clients interested in this FEC. */
+ struct list *client_list;
+};
/* Function declarations. */
@@ -165,6 +187,116 @@ mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
char *buf, int len);
/*
+ * Add/update global label block.
+ */
+int
+zebra_mpls_label_block_add (struct zebra_vrf *zvrf, u_int32_t start_label,
+ u_int32_t end_label);
+
+/*
+ * Delete global label block.
+ */
+int
+zebra_mpls_label_block_del (struct zebra_vrf *vrf);
+
+/*
+ * Display MPLS global label block configuration (VTY command handler).
+ */
+int
+zebra_mpls_write_label_block_config (struct vty *vty, struct zebra_vrf *vrf);
+
+/*
+ * Install dynamic LSP entry.
+ */
+int
+zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib);
+
+/*
+ * Uninstall dynamic LSP entry, if any.
+ */
+int
+zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib);
+
+/*
+ * Registration from a client for the label binding for a FEC. If a binding
+ * already exists, it is informed to the client.
+ * NOTE: If there is a manually configured label binding, that is used.
+ * Otherwise, if aa label index is specified, it means we have to allocate the
+ * label from a locally configured label block (SRGB), if one exists and index
+ * is acceptable.
+ */
+int
+zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
+ u_int32_t label_index, struct zserv *client);
+
+/*
+ * Deregistration from a client for the label binding for a FEC. The FEC
+ * itself is deleted if no other registered clients exist and there is no
+ * label bound to the FEC.
+ */
+int
+zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
+ struct zserv *client);
+
+/*
+ * Cleanup any FECs registered by this client.
+ */
+int
+zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client);
+
+/*
+ * Return FEC (if any) to which this label is bound.
+ * Note: Only works for per-prefix binding and when the label is not
+ * implicit-null.
+ * TODO: Currently walks entire table, can optimize later with another
+ * hash..
+ */
+zebra_fec_t *
+zebra_mpls_fec_for_label (struct zebra_vrf *zvrf, mpls_label_t label);
+
+/*
+ * Inform if specified label is currently bound to a FEC or not.
+ */
+int
+zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label);
+
+/*
+ * Add static FEC to label binding. If there are clients registered for this
+ * FEC, notify them. If there are labeled routes for this FEC, install the
+ * label forwarding entry.
+ */
+int
+zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
+ mpls_label_t in_label);
+
+/*
+ * Remove static FEC to label binding. If there are no clients registered
+ * for this FEC, delete the FEC; else notify clients.
+ * Note: Upon delete of static binding, if label index exists for this FEC,
+ * client may need to be updated with derived label.
+ */
+int
+zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p);
+
+/*
+ * Display MPLS FEC to label binding configuration (VTY command handler).
+ */
+int
+zebra_mpls_write_fec_config (struct vty *vty, struct zebra_vrf *zvrf);
+
+/*
+ * Display MPLS FEC to label binding (VTY command handler).
+ */
+void
+zebra_mpls_print_fec_table (struct vty *vty, struct zebra_vrf *zvrf);
+
+/*
+ * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
+ */
+void
+zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p);
+
+/*
* Install/uninstall a FEC-To-NHLFE (FTN) binding.
*/
int
@@ -182,7 +314,7 @@ int
mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label, mpls_label_t out_label,
enum nexthop_types_t gtype, union g_addr *gate,
- char *ifname, ifindex_t ifindex);
+ ifindex_t ifindex);
/*
* Uninstall a particular NHLFE in the forwarding table. If this is
@@ -191,7 +323,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
int
mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label, enum nexthop_types_t gtype,
- union g_addr *gate, char *ifname, ifindex_t ifindex);
+ union g_addr *gate, ifindex_t ifindex);
/*
* Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
@@ -216,7 +348,7 @@ mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi);
int
zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
mpls_label_t out_label, enum nexthop_types_t gtype,
- union g_addr *gate, char *ifname, ifindex_t ifindex);
+ union g_addr *gate, ifindex_t ifindex);
#endif /* HAVE_CUMULUS */
/*
@@ -229,7 +361,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
int
zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
mpls_label_t out_label, enum nexthop_types_t gtype,
- union g_addr *gate, char *ifname, ifindex_t ifindex);
+ union g_addr *gate, ifindex_t ifindex);
/*
* Delete static LSP entry. This may be the delete of one particular
@@ -241,7 +373,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
int
zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
enum nexthop_types_t gtype, union g_addr *gate,
- char *ifname, ifindex_t ifindex);
+ ifindex_t ifindex);
/*
* Schedule all MPLS label forwarding entries for processing.
@@ -324,6 +456,8 @@ lsp_type_from_rib_type (int rib_type)
{
case ZEBRA_ROUTE_STATIC:
return ZEBRA_LSP_STATIC;
+ case ZEBRA_ROUTE_BGP:
+ return ZEBRA_LSP_BGP;
default:
return ZEBRA_LSP_NONE;
}
@@ -339,6 +473,8 @@ nhlfe_type2str(enum lsp_types_t lsp_type)
return "Static";
case ZEBRA_LSP_LDP:
return "LDP";
+ case ZEBRA_LSP_BGP:
+ return "BGP";
default:
return "Unknown";
}
diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c
index 23f5e7295..168c8d003 100644
--- a/zebra/zebra_mpls_null.c
+++ b/zebra/zebra_mpls_null.c
@@ -27,3 +27,209 @@ int kernel_add_lsp (zebra_lsp_t *lsp) { return 0; }
int kernel_upd_lsp (zebra_lsp_t *lsp) { return 0; }
int kernel_del_lsp (zebra_lsp_t *lsp) { return 0; }
int mpls_kernel_init (void) { return -1; };
+
+int mpls_enabled;
+
+char *
+mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
+ char *buf, int len)
+{
+ return NULL;
+}
+
+int
+mpls_str2label (const char *label_str, u_int8_t *num_labels,
+ mpls_label_t *labels)
+{
+ return 0;
+}
+
+int
+zebra_mpls_label_block_add (struct zebra_vrf *vrf, u_int32_t start_label,
+ u_int32_t end_label)
+{
+ return 0;
+}
+
+int
+zebra_mpls_label_block_del (struct zebra_vrf *zvrf)
+{
+ return 0;
+}
+
+int
+zebra_mpls_write_label_block_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+ return 0;
+}
+
+int
+zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib)
+{
+ return 0;
+}
+
+int
+zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib)
+{
+ return 0;
+}
+
+void
+zebra_mpls_init_tables (struct zebra_vrf *zvrf)
+{
+}
+
+void
+zebra_mpls_print_lsp (struct vty *vty, struct zebra_vrf *zvrf, mpls_label_t label,
+ u_char use_json)
+{
+}
+
+void
+zebra_mpls_print_lsp_table (struct vty *vty, struct zebra_vrf *zvrf,
+ u_char use_json)
+{
+}
+
+int
+zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+ return 0;
+}
+
+#ifdef HAVE_CUMULUS
+int
+zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
+ mpls_label_t out_label, enum nexthop_types_t gtype,
+ union g_addr *gate, ifindex_t ifindex)
+{
+ return 0;
+}
+#endif
+
+int
+zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
+ mpls_label_t out_label, enum nexthop_types_t gtype,
+ union g_addr *gate, ifindex_t ifindex)
+{
+ return 0;
+}
+
+int
+zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
+ enum nexthop_types_t gtype, union g_addr *gate,
+ ifindex_t ifindex)
+{
+ return 0;
+}
+
+void
+zebra_mpls_lsp_schedule (struct zebra_vrf *zvrf)
+{
+}
+
+void
+zebra_mpls_close_tables (struct zebra_vrf *zvrf)
+{
+}
+
+zebra_fec_t *
+zebra_mpls_fec_for_label (struct zebra_vrf *zvrf, mpls_label_t label)
+{
+ return NULL;
+}
+
+int
+zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label)
+{
+ return 0;
+}
+
+int
+zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
+ mpls_label_t in_label)
+{
+ return 0;
+}
+
+int
+zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
+{
+ return 0;
+}
+
+int
+zebra_mpls_write_fec_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+ return 0;
+}
+
+void
+zebra_mpls_print_fec_table (struct vty *vty, struct zebra_vrf *zvrf)
+{
+}
+
+void
+zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p)
+{
+}
+
+int
+zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
+ u_int32_t label_index, struct zserv *client)
+{
+ return 0;
+}
+
+int
+zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
+ struct zserv *client)
+{
+ return 0;
+}
+
+int
+zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client)
+{
+ return 0;
+}
+
+void mpls_ldp_lsp_uninstall_all (struct hash_backet *backet, void *ctxt)
+{
+ return;
+}
+
+void mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi)
+{
+ return;
+}
+
+void zebra_mpls_init (void)
+{
+ return;
+}
+
+int mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
+ mpls_label_t in_label, mpls_label_t out_label,
+ enum nexthop_types_t gtype, union g_addr *gate,
+ ifindex_t ifindex)
+{
+ return 0;
+}
+
+int mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type,
+ mpls_label_t in_label, enum nexthop_types_t gtype,
+ union g_addr *gate, ifindex_t ifindex)
+{
+ return 0;
+}
+
+int mpls_ftn_update (int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
+ struct prefix *prefix, enum nexthop_types_t gtype,
+ union g_addr *gate, ifindex_t ifindex, u_int8_t distance,
+ mpls_label_t out_label)
+{
+ return 0;
+}
+
diff --git a/zebra/zebra_mpls_vty.c b/zebra/zebra_mpls_vty.c
index dd381723c..7662cf416 100644
--- a/zebra/zebra_mpls_vty.c
+++ b/zebra/zebra_mpls_vty.c
@@ -133,7 +133,7 @@ zebra_mpls_transit_lsp (struct vty *vty, int add_cmd, const char *inlabel_str,
#if defined(HAVE_CUMULUS)
/* Check that label value is consistent. */
if (!zebra_mpls_lsp_label_consistent (zvrf, in_label, out_label, gtype,
- &gate, NULL, 0))
+ &gate, 0))
{
vty_out (vty, "%% Label value not consistent%s",
VTY_NEWLINE);
@@ -142,10 +142,10 @@ zebra_mpls_transit_lsp (struct vty *vty, int add_cmd, const char *inlabel_str,
#endif /* HAVE_CUMULUS */
ret = zebra_mpls_static_lsp_add (zvrf, in_label, out_label, gtype,
- &gate, NULL, 0);
+ &gate, 0);
}
else
- ret = zebra_mpls_static_lsp_del (zvrf, in_label, gtype, &gate, NULL, 0);
+ ret = zebra_mpls_static_lsp_del (zvrf, in_label, gtype, &gate, 0);
if (ret)
{
@@ -209,6 +209,109 @@ DEFUN (no_mpls_transit_lsp_all,
return zebra_mpls_transit_lsp (vty, 0, argv[3]->arg, NULL, NULL, NULL);
}
+static int
+zebra_mpls_bind (struct vty *vty, int add_cmd, const char *prefix,
+ const char *label_str)
+{
+ struct zebra_vrf *zvrf;
+ struct prefix p;
+ u_int32_t label;
+ int ret;
+
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (!zvrf)
+ {
+ vty_out (vty, "%% Default VRF does not exist%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ memset(&p, 0, sizeof(struct prefix));
+ ret = str2prefix(prefix, &p);
+ if (ret <= 0)
+ {
+ vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (add_cmd)
+ {
+ if (!label_str)
+ {
+ vty_out (vty, "%% No label binding specified%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!strcmp(label_str, "implicit-null"))
+ label = MPLS_IMP_NULL_LABEL;
+ else if (!strcmp(label_str, "explicit-null"))
+ {
+ if (p.family == AF_INET)
+ label = MPLS_V4_EXP_NULL_LABEL;
+ else
+ label = MPLS_V6_EXP_NULL_LABEL;
+ }
+ else
+ {
+ label = atoi(label_str);
+ if (!IS_MPLS_UNRESERVED_LABEL(label))
+ {
+ vty_out (vty, "%% Invalid label%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (zebra_mpls_label_already_bound (zvrf, label))
+ {
+ vty_out (vty, "%% Label already bound to a FEC%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ ret = zebra_mpls_static_fec_add (zvrf, &p, label);
+ }
+ else
+ ret = zebra_mpls_static_fec_del (zvrf, &p);
+
+ if (ret)
+ {
+ vty_out (vty, "%% FEC to label binding cannot be %s%s",
+ add_cmd ? "added" : "deleted", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (mpls_label_bind,
+ mpls_label_bind_cmd,
+ "mpls label bind <A.B.C.D/M|X:X::X:X/M> <(16-1048575)|implicit-null|explicit-null>",
+ MPLS_STR
+ "Label configuration\n"
+ "Establish FEC to label binding\n"
+ "IPv4 prefix\n"
+ "IPv6 prefix\n"
+ "MPLS Label to bind\n"
+ "Use Implicit-Null Label\n"
+ "Use Explicit-Null Label\n")
+{
+ return zebra_mpls_bind (vty, 1, argv[3]->arg, argv[4]->arg);
+}
+
+DEFUN (no_mpls_label_bind,
+ no_mpls_label_bind_cmd,
+ "no mpls label bind <A.B.C.D/M|X:X::X:X/M> [<(16-1048575)|implicit-null>]",
+ NO_STR
+ MPLS_STR
+ "Label configuration\n"
+ "Establish FEC to label binding\n"
+ "IPv4 prefix\n"
+ "IPv6 prefix\n"
+ "MPLS Label to bind\n"
+ "Use Implicit-Null Label\n")
+
+{
+ return zebra_mpls_bind (vty, 0, argv[4]->arg, NULL);
+}
+
/* Static route configuration. */
DEFUN (ip_route_label,
ip_route_label_cmd,
@@ -777,9 +880,45 @@ zebra_mpls_config (struct vty *vty)
return 0;
write += zebra_mpls_write_lsp_config(vty, zvrf);
+ write += zebra_mpls_write_fec_config(vty, zvrf);
+ write += zebra_mpls_write_label_block_config (vty, zvrf);
return write;
}
+DEFUN (show_mpls_fec,
+ show_mpls_fec_cmd,
+ "show mpls fec [<A.B.C.D/M|X:X::X:X/M>]",
+ SHOW_STR
+ MPLS_STR
+ "MPLS FEC table\n"
+ "FEC to display information about\n"
+ "FEC to display information about\n")
+{
+ struct zebra_vrf *zvrf;
+ struct prefix p;
+ int ret;
+
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (!zvrf)
+ return 0;
+
+ if (argc == 3)
+ zebra_mpls_print_fec_table(vty, zvrf);
+ else
+ {
+ memset(&p, 0, sizeof(struct prefix));
+ ret = str2prefix(argv[3]->arg, &p);
+ if (ret <= 0)
+ {
+ vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ zebra_mpls_print_fec (vty, zvrf, &p);
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFUN (show_mpls_table,
show_mpls_table_cmd,
"show mpls table [json]",
@@ -827,6 +966,85 @@ DEFUN (show_mpls_status,
return CMD_SUCCESS;
}
+static int
+zebra_mpls_global_block (struct vty *vty, int add_cmd,
+ const char *start_label_str, const char *end_label_str)
+{
+ int ret;
+ u_int32_t start_label;
+ u_int32_t end_label;
+ struct zebra_vrf *zvrf;
+
+ zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
+ if (!zvrf)
+ {
+ vty_out (vty, "%% Default VRF does not exist%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (add_cmd)
+ {
+ if (!start_label_str || !end_label_str)
+ {
+ vty_out (vty, "%% Labels not specified%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ start_label = atoi(start_label_str);
+ end_label = atoi(end_label_str);
+ if (!IS_MPLS_UNRESERVED_LABEL(start_label) ||
+ !IS_MPLS_UNRESERVED_LABEL(end_label))
+ {
+ vty_out (vty, "%% Invalid label%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (end_label < start_label)
+ {
+ vty_out (vty, "%% End label is less than Start label%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ret = zebra_mpls_label_block_add (zvrf, start_label, end_label);
+ }
+ else
+ ret = zebra_mpls_label_block_del (zvrf);
+
+ if (ret)
+ {
+ vty_out (vty, "%% Global label block could not be %s%s",
+ add_cmd ? "added" : "deleted", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (mpls_label_global_block,
+ mpls_label_global_block_cmd,
+ "mpls label global-block (16-1048575) (16-1048575)",
+ MPLS_STR
+ "Label configuration\n"
+ "Configure global label block\n"
+ "Start label\n"
+ "End label\n")
+{
+ return zebra_mpls_global_block (vty, 1, argv[3]->arg, argv[4]->arg);
+}
+
+DEFUN (no_mpls_label_global_block,
+ no_mpls_label_global_block_cmd,
+ "no mpls label global-block [(16-1048575) (16-1048575)]",
+ NO_STR
+ MPLS_STR
+ "Label configuration\n"
+ "Configure global label block\n"
+ "Start label\n"
+ "End label\n")
+{
+ return zebra_mpls_global_block (vty, 0, NULL, NULL);
+}
+
/* MPLS node for MPLS LSP. */
static struct cmd_node mpls_node = { MPLS_NODE, "", 1 };
@@ -876,7 +1094,13 @@ zebra_mpls_vty_init (void)
install_element (CONFIG_NODE, &no_mpls_transit_lsp_cmd);
install_element (CONFIG_NODE, &no_mpls_transit_lsp_out_label_cmd);
install_element (CONFIG_NODE, &no_mpls_transit_lsp_all_cmd);
+ install_element (CONFIG_NODE, &mpls_label_bind_cmd);
+ install_element (CONFIG_NODE, &no_mpls_label_bind_cmd);
+
+ install_element (CONFIG_NODE, &mpls_label_global_block_cmd);
+ install_element (CONFIG_NODE, &no_mpls_label_global_block_cmd);
install_element (VIEW_NODE, &show_mpls_table_cmd);
install_element (VIEW_NODE, &show_mpls_table_lsp_cmd);
+ install_element (VIEW_NODE, &show_mpls_fec_cmd);
}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index b3e70e46f..e4d583d5f 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1084,7 +1084,25 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
return rib->nexthop_active_num;
}
+/*
+ * Is this RIB labeled-unicast? It must be of type BGP and all paths
+ * (nexthops) must have a label.
+ */
+int
+zebra_rib_labeled_unicast (struct rib *rib)
+{
+ struct nexthop *nexthop = NULL, *tnexthop;
+ int recursing;
+
+ if (rib->type != ZEBRA_ROUTE_BGP)
+ return 0;
+
+ for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
+ if (!nexthop->nh_label || !nexthop->nh_label->num_labels)
+ return 0;
+ return 1;
+}
/* Update flag indicates whether this is a "replace" or not. Currently, this
* is only used for IPv4.
@@ -1177,7 +1195,12 @@ rib_uninstall (struct route_node *rn, struct rib *rib)
if (! RIB_SYSTEM_ROUTE (rib))
rib_uninstall_kernel (rn, rib);
- UNSET_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB);
+
+ /* If labeled-unicast route, uninstall transit LSP. */
+ if (zebra_rib_labeled_unicast (rib))
+ zebra_mpls_lsp_uninstall (info->zvrf, rn, rib);
+
+ UNSET_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB);
}
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
@@ -1272,6 +1295,10 @@ rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
zvrf_id (zvrf), buf, rn, new, new->type);
}
+ /* If labeled-unicast route, install transit LSP. */
+ if (zebra_rib_labeled_unicast (new))
+ zebra_mpls_lsp_install (zvrf, rn, new);
+
if (!RIB_SYSTEM_ROUTE (new))
{
if (rib_install_kernel (rn, new, NULL))
@@ -1301,6 +1328,10 @@ rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
zvrf_id (zvrf), buf, rn, old, old->type);
}
+ /* If labeled-unicast route, uninstall transit LSP. */
+ if (zebra_rib_labeled_unicast (old))
+ zebra_mpls_lsp_uninstall (zvrf, rn, old);
+
if (!RIB_SYSTEM_ROUTE (old))
rib_uninstall_kernel (rn, old);
@@ -1354,6 +1385,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
/* Non-system route should be installed. */
if (!RIB_SYSTEM_ROUTE (new))
{
+ /* If labeled-unicast route, install transit LSP. */
+ if (zebra_rib_labeled_unicast (new))
+ zebra_mpls_lsp_install (zvrf, rn, new);
+
if (rib_install_kernel (rn, new, old))
{
char buf[SRCDEST2STR_BUFFER];
@@ -1368,6 +1403,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
{
if (RIB_SYSTEM_ROUTE(new))
{
+ /* If labeled-unicast route, uninstall transit LSP. */
+ if (zebra_rib_labeled_unicast (old))
+ zebra_mpls_lsp_uninstall (zvrf, rn, old);
+
if (!RIB_SYSTEM_ROUTE (old))
rib_uninstall_kernel (rn, old);
}
@@ -1404,6 +1443,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
nh_active ? "install failed" : "nexthop inactive");
}
+ /* If labeled-unicast route, uninstall transit LSP. */
+ if (zebra_rib_labeled_unicast (old))
+ zebra_mpls_lsp_uninstall (zvrf, rn, old);
+
if (!RIB_SYSTEM_ROUTE (old))
rib_uninstall_kernel (rn, old);
UNSET_FLAG (new->status, RIB_ENTRY_SELECTED_FIB);
@@ -2934,8 +2977,10 @@ rib_tables_iter_next (rib_tables_iter_t *iter)
} afi_safis[] = {
{ AFI_IP, SAFI_UNICAST },
{ AFI_IP, SAFI_MULTICAST },
+ { AFI_IP, SAFI_LABELED_UNICAST },
{ AFI_IP6, SAFI_UNICAST },
{ AFI_IP6, SAFI_MULTICAST },
+ { AFI_IP6, SAFI_LABELED_UNICAST },
};
table = NULL;
diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h
index 96d631d64..74c2a5217 100644
--- a/zebra/zebra_vrf.h
+++ b/zebra/zebra_vrf.h
@@ -25,6 +25,13 @@
#include <zebra/zebra_ns.h>
+/* MPLS (Segment Routing) global block */
+typedef struct mpls_srgb_t_
+{
+ u_int32_t start_label;
+ u_int32_t end_label;
+} mpls_srgb_t;
+
/* Routing table instance. */
struct zebra_vrf
{
@@ -79,6 +86,12 @@ struct zebra_vrf
/* MPLS label forwarding table */
struct hash *lsp_table;
+ /* MPLS FEC binding table */
+ struct route_table *fec_table[AFI_MAX];
+
+ /* MPLS Segment Routing Global block */
+ mpls_srgb_t mpls_srgb;
+
/* MPLS processing flags */
u_int16_t mpls_flags;
#define MPLS_FLAG_SCHEDULE_LSPS (1 << 0)
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 3477dc36d..416e5444e 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -934,6 +934,109 @@ zserv_rnh_unregister (struct zserv *client, int sock, u_short length,
return 0;
}
+#define ZEBRA_MIN_FEC_LENGTH 9
+
+/* FEC register */
+static int
+zserv_fec_register (struct zserv *client, int sock, u_short length)
+{
+ struct stream *s;
+ struct zebra_vrf *zvrf;
+ u_short l = 0;
+ struct prefix p;
+ u_int16_t flags;
+ u_int32_t label_index = MPLS_INVALID_LABEL_INDEX;
+
+ s = client->ibuf;
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (!zvrf)
+ return 0; // unexpected
+
+ /*
+ * The minimum amount of data that can be sent for one fec
+ * registration
+ */
+ if (length < ZEBRA_MIN_FEC_LENGTH)
+ {
+ zlog_err ("fec_register: Received a fec register of length %d, it is of insufficient size to properly decode",
+ length);
+ return -1;
+ }
+
+ while (l < length)
+ {
+ flags = stream_getw(s);
+ p.family = stream_getw(s);
+ if (p.family != AF_INET &&
+ p.family != AF_INET6)
+ {
+ zlog_err ("fec_register: Received unknown family type %d\n",
+ p.family);
+ return -1;
+ }
+ p.prefixlen = stream_getc(s);
+ l += 5;
+ stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
+ l += PSIZE(p.prefixlen);
+ if (flags & ZEBRA_FEC_REGISTER_LABEL_INDEX)
+ {
+ label_index = stream_getl(s);
+ l += 4;
+ }
+ zebra_mpls_fec_register (zvrf, &p, label_index, client);
+ }
+
+ return 0;
+}
+
+/* FEC unregister */
+static int
+zserv_fec_unregister (struct zserv *client, int sock, u_short length)
+{
+ struct stream *s;
+ struct zebra_vrf *zvrf;
+ u_short l = 0;
+ struct prefix p;
+ //u_int16_t flags;
+
+ s = client->ibuf;
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (!zvrf)
+ return 0; // unexpected
+
+ /*
+ * The minimum amount of data that can be sent for one
+ * fec unregistration
+ */
+ if (length < ZEBRA_MIN_FEC_LENGTH)
+ {
+ zlog_err ("fec_unregister: Received a fec unregister of length %d, it is of insufficient size to properly decode",
+ length);
+ return -1;
+ }
+
+ while (l < length)
+ {
+ //flags = stream_getw(s);
+ (void)stream_getw(s);
+ p.family = stream_getw(s);
+ if (p.family != AF_INET &&
+ p.family != AF_INET6)
+ {
+ zlog_err ("fec_unregister: Received unknown family type %d\n",
+ p.family);
+ return -1;
+ }
+ p.prefixlen = stream_getc(s);
+ l += 5;
+ stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
+ l += PSIZE(p.prefixlen);
+ zebra_mpls_fec_unregister (zvrf, &p, client);
+ }
+
+ return 0;
+}
+
/*
Modified version of zsend_ipv4_nexthop_lookup():
Query unicast rib if nexthop is not found on mrib.
@@ -1075,13 +1178,15 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
struct rib *rib;
struct prefix p;
u_char message;
- struct in_addr nexthop;
+ struct in_addr nhop_addr;
u_char nexthop_num;
u_char nexthop_type;
struct stream *s;
ifindex_t ifindex;
safi_t safi;
int ret;
+ mpls_label_t label;
+ struct nexthop *nexthop;
/* Get input stream. */
s = client->ibuf;
@@ -1123,13 +1228,19 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
rib_nexthop_ifindex_add (rib, ifindex);
break;
case NEXTHOP_TYPE_IPV4:
- nexthop.s_addr = stream_get_ipv4 (s);
- rib_nexthop_ipv4_add (rib, &nexthop, NULL);
+ nhop_addr.s_addr = stream_get_ipv4 (s);
+ nexthop = rib_nexthop_ipv4_add (rib, &nhop_addr, NULL);
+ /* For labeled-unicast, each nexthop is followed by label. */
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL))
+ {
+ label = (mpls_label_t)stream_getl (s);
+ nexthop_add_labels (nexthop, nexthop->nh_label_type, 1, &label);
+ }
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
- nexthop.s_addr = stream_get_ipv4 (s);
+ nhop_addr.s_addr = stream_get_ipv4 (s);
ifindex = stream_getl (s);
- rib_nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex);
+ rib_nexthop_ipv4_ifindex_add (rib, &nhop_addr, NULL, ifindex);
break;
case NEXTHOP_TYPE_IPV6:
stream_forward_getp (s, IPV6_MAX_BYTELEN);
@@ -1222,6 +1333,11 @@ zread_ipv4_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
break;
case NEXTHOP_TYPE_IPV4:
nexthop.s_addr = stream_get_ipv4 (s);
+ /* For labeled-unicast, each nexthop is followed by label, but
+ * we don't care for delete.
+ */
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_LABEL))
+ stream_forward_getp (s, sizeof(u_int32_t));
nexthop_p = (union g_addr *)&nexthop;
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
@@ -1407,7 +1523,7 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
{
unsigned int i;
struct stream *s;
- struct in6_addr nexthop;
+ struct in6_addr nhop_addr;
struct rib *rib;
u_char message;
u_char nexthop_num;
@@ -1418,11 +1534,14 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
static struct in6_addr nexthops[MULTIPATH_NUM];
static unsigned int ifindices[MULTIPATH_NUM];
int ret;
+ static mpls_label_t labels[MULTIPATH_NUM];
+ mpls_label_t label;
+ struct nexthop *nexthop;
/* Get input stream. */
s = client->ibuf;
- memset (&nexthop, 0, sizeof (struct in6_addr));
+ memset (&nhop_addr, 0, sizeof (struct in6_addr));
/* Allocate new rib. */
rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
@@ -1471,10 +1590,17 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
switch (nexthop_type)
{
case NEXTHOP_TYPE_IPV6:
- stream_get (&nexthop, s, 16);
- if (nh_count < multipath_num) {
- nexthops[nh_count++] = nexthop;
- }
+ stream_get (&nhop_addr, s, 16);
+ if (nh_count < MULTIPATH_NUM)
+ {
+ /* For labeled-unicast, each nexthop is followed by label. */
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL))
+ {
+ label = (mpls_label_t)stream_getl (s);
+ labels[nh_count++] = label;
+ }
+ nexthops[nh_count++] = nhop_addr;
+ }
break;
case NEXTHOP_TYPE_IFINDEX:
if (if_count < multipath_num) {
@@ -1492,9 +1618,11 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
{
if ((i < nh_count) && !IN6_IS_ADDR_UNSPECIFIED (&nexthops[i])) {
if ((i < if_count) && ifindices[i])
- rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]);
+ nexthop = rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]);
else
- rib_nexthop_ipv6_add (rib, &nexthops[i]);
+ nexthop = rib_nexthop_ipv6_add (rib, &nexthops[i]);
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL))
+ nexthop_add_labels (nexthop, nexthop->nh_label_type, 1, &labels[i]);
}
else {
if ((i < if_count) && ifindices[i])
@@ -1591,6 +1719,11 @@ zread_ipv6_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
{
case NEXTHOP_TYPE_IPV6:
stream_get (&nexthop, s, 16);
+ /* For labeled-unicast, each nexthop is followed by label, but
+ * we don't care for delete.
+ */
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_LABEL))
+ stream_forward_getp (s, sizeof(u_int32_t));
pnexthop = (union g_addr *)&nexthop;
break;
case NEXTHOP_TYPE_IFINDEX:
@@ -1761,14 +1894,14 @@ zread_mpls_labels (int command, struct zserv *client, u_short length,
if (command == ZEBRA_MPLS_LABELS_ADD)
{
mpls_lsp_install (zvrf, type, in_label, out_label, gtype, &gate,
- NULL, ifindex);
+ ifindex);
if (out_label != MPLS_IMP_NULL_LABEL)
mpls_ftn_update (1, zvrf, type, &prefix, gtype, &gate, ifindex,
distance, out_label);
}
else if (command == ZEBRA_MPLS_LABELS_DELETE)
{
- mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, NULL, ifindex);
+ mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, ifindex);
if (out_label != MPLS_IMP_NULL_LABEL)
mpls_ftn_update (0, zvrf, type, &prefix, gtype, &gate, ifindex,
distance, out_label);
@@ -1975,6 +2108,9 @@ zebra_client_close (struct zserv *client)
/* Release Label Manager chunks */
release_daemon_chunks (client->proto, client->instance);
+ /* Cleanup any FECs registered by this client. */
+ zebra_mpls_cleanup_fecs_for_client (vrf_info_lookup(VRF_DEFAULT), client);
+
/* Close file descriptor. */
if (client->sock)
{
@@ -2263,6 +2399,12 @@ zebra_client_read (struct thread *thread)
case ZEBRA_RELEASE_LABEL_CHUNK:
zread_label_manager_request (command, client, vrf_id);
break;
+ case ZEBRA_FEC_REGISTER:
+ zserv_fec_register (client, sock, length);
+ break;
+ case ZEBRA_FEC_UNREGISTER:
+ zserv_fec_unregister (client, sock, length);
+ break;
default:
zlog_info ("Zebra received unknown command %d", command);
break;