summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_attr.c49
-rw-r--r--bgpd/bgp_attr.h3
-rw-r--r--bgpd/bgp_bmp.c3
-rw-r--r--bgpd/bgp_snmp.c2
-rwxr-xr-xconfigure.ac6
-rw-r--r--doc/developer/building-frr-for-archlinux.rst129
-rw-r--r--doc/developer/building-frr-for-centos6.rst14
-rw-r--r--doc/developer/building.rst1
-rw-r--r--isisd/isis_cli.c4
-rw-r--r--lib/lib_vty.c2
-rw-r--r--lib/ntop.c2
-rw-r--r--ospfd/ospf_packet.c2
-rw-r--r--tests/bgpd/test_mp_attr.c21
-rw-r--r--tests/topotests/bgp_prefix_sid/__init__.py0
-rw-r--r--tests/topotests/bgp_prefix_sid/exabgp.env53
-rw-r--r--tests/topotests/bgp_prefix_sid/peer1/exabgp.cfg103
-rwxr-xr-xtests/topotests/bgp_prefix_sid/peer2/exa-receive.py37
-rw-r--r--tests/topotests/bgp_prefix_sid/peer2/exabgp.cfg19
-rw-r--r--tests/topotests/bgp_prefix_sid/r1/bgpd.conf15
-rw-r--r--tests/topotests/bgp_prefix_sid/r1/zebra.conf7
-rwxr-xr-xtests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py173
-rw-r--r--zebra/rt_netlink.c2
22 files changed, 611 insertions, 36 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 7c15fd3711..1b46a907b1 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -2382,8 +2382,7 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */
* Returns 0 if there was an error that needs to be passed up the stack
*/
static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
- struct bgp_attr_parser_args *args,
- struct bgp_nlri *mp_update)
+ struct bgp_attr_parser_args *args)
{
struct peer *const peer = args->peer;
struct attr *const attr = args->attr;
@@ -2421,15 +2420,6 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
/* Store label index; subsequently, we'll check on
* address-family */
attr->label_index = label_index;
-
- /*
- * Ignore the Label index attribute unless received for
- * labeled-unicast
- * SAFI.
- */
- if (!mp_update->length
- || mp_update->safi != SAFI_LABELED_UNICAST)
- attr->label_index = BGP_INVALID_LABEL_INDEX;
}
/* Placeholder code for the IPv6 SID type */
@@ -2628,8 +2618,7 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
/* Prefix SID attribute
* draft-ietf-idr-bgp-prefix-sid-05
*/
-bgp_attr_parse_ret_t bgp_attr_prefix_sid(struct bgp_attr_parser_args *args,
- struct bgp_nlri *mp_update)
+bgp_attr_parse_ret_t bgp_attr_prefix_sid(struct bgp_attr_parser_args *args)
{
struct peer *const peer = args->peer;
struct attr *const attr = args->attr;
@@ -2640,8 +2629,10 @@ bgp_attr_parse_ret_t bgp_attr_prefix_sid(struct bgp_attr_parser_args *args,
uint8_t type;
uint16_t length;
size_t headersz = sizeof(type) + sizeof(length);
+ size_t psid_parsed_length = 0;
- while (STREAM_READABLE(peer->curr) > 0) {
+ while (STREAM_READABLE(peer->curr) > 0
+ && psid_parsed_length < args->length) {
if (STREAM_READABLE(peer->curr) < headersz) {
flog_err(
@@ -2659,7 +2650,7 @@ bgp_attr_parse_ret_t bgp_attr_prefix_sid(struct bgp_attr_parser_args *args,
if (STREAM_READABLE(peer->curr) < length) {
flog_err(
EC_BGP_ATTR_LEN,
- "Malformed Prefix SID attribute - insufficient data (need %" PRIu8
+ "Malformed Prefix SID attribute - insufficient data (need %" PRIu16
" for attribute body, have %zu remaining in UPDATE)",
length, STREAM_READABLE(peer->curr));
return bgp_attr_malformed(args,
@@ -2667,10 +2658,23 @@ bgp_attr_parse_ret_t bgp_attr_prefix_sid(struct bgp_attr_parser_args *args,
args->total);
}
- ret = bgp_attr_psid_sub(type, length, args, mp_update);
+ ret = bgp_attr_psid_sub(type, length, args);
if (ret != BGP_ATTR_PARSE_PROCEED)
return ret;
+
+ psid_parsed_length += length + headersz;
+
+ if (psid_parsed_length > args->length) {
+ flog_err(
+ EC_BGP_ATTR_LEN,
+ "Malformed Prefix SID attribute - TLV overflow by attribute (need %zu"
+ " for TLV length, have %zu overflowed in UPDATE)",
+ length + headersz, psid_parsed_length - (length + headersz));
+ return bgp_attr_malformed(
+ args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
}
return BGP_ATTR_PARSE_PROCEED;
@@ -3066,7 +3070,7 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
startp);
break;
case BGP_ATTR_PREFIX_SID:
- ret = bgp_attr_prefix_sid(&attr_args, mp_update);
+ ret = bgp_attr_prefix_sid(&attr_args);
break;
case BGP_ATTR_PMSI_TUNNEL:
ret = bgp_attr_pmsi_tunnel(&attr_args);
@@ -3113,6 +3117,17 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
}
}
+ /*
+ * draft-ietf-idr-bgp-prefix-sid-27#section-3:
+ * About Prefix-SID path attribute,
+ * Label-Index TLV(type1) and The Originator SRGB TLV(type-3)
+ * may only appear in a BGP Prefix-SID attribute attached to
+ * IPv4/IPv6 Labeled Unicast prefixes ([RFC8277]).
+ * It MUST be ignored when received for other BGP AFI/SAFI combinations.
+ */
+ if (!attr->mp_nexthop_len || mp_update->safi != SAFI_LABELED_UNICAST)
+ attr->label_index = BGP_INVALID_LABEL_INDEX;
+
/* Check final read pointer is same as end pointer. */
if (BGP_INPUT_PNT(peer) != endp) {
flog_warn(EC_BGP_ATTRIBUTES_MISMATCH,
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 2e91f56df5..1c519c67f3 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -351,8 +351,7 @@ extern int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
extern int bgp_mp_unreach_parse(struct bgp_attr_parser_args *args,
struct bgp_nlri *);
extern bgp_attr_parse_ret_t
-bgp_attr_prefix_sid(struct bgp_attr_parser_args *args,
- struct bgp_nlri *mp_update);
+bgp_attr_prefix_sid(struct bgp_attr_parser_args *args);
extern struct bgp_attr_encap_subtlv *
encap_tlv_dup(struct bgp_attr_encap_subtlv *orig);
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c
index 24a9cab5d1..32865da376 100644
--- a/bgpd/bgp_bmp.c
+++ b/bgpd/bgp_bmp.c
@@ -664,8 +664,7 @@ static int bmp_peer_established(struct peer *peer)
return 0;
/* Check if this peer just went to Established */
- if ((peer->last_major_event != OpenConfirm) ||
- !(peer_established(peer)))
+ if ((peer->ostatus != OpenConfirm) || !(peer_established(peer)))
return 0;
if (peer->doppelganger && (peer->doppelganger->status != Deleted)) {
diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c
index d507161052..5cf0b73984 100644
--- a/bgpd/bgp_snmp.c
+++ b/bgpd/bgp_snmp.c
@@ -858,7 +858,7 @@ static int bgpTrapEstablished(struct peer *peer)
oid index[sizeof(oid) * IN_ADDR_SIZE];
/* Check if this peer just went to Established */
- if ((peer->last_major_event != OpenConfirm) || !(peer_established(peer)))
+ if ((peer->ostatus != OpenConfirm) || !(peer_established(peer)))
return 0;
ret = inet_aton(peer->host, &addr);
diff --git a/configure.ac b/configure.ac
index b4d227e794..41d1911c37 100755
--- a/configure.ac
+++ b/configure.ac
@@ -1782,11 +1782,15 @@ if test "$enable_rpki" = "yes"; then
fi
dnl ------------------------------------
-dnl pimd is not supported on OpenBSD
+dnl pimd is not supported on OpenBSD and MacOS
dnl ------------------------------------
if test "$enable_pimd" != "no"; then
AC_MSG_CHECKING([for pimd OS support])
case "$host_os" in
+ darwin*)
+ AC_MSG_RESULT([no])
+ enable_pimd="no"
+ ;;
openbsd*)
AC_MSG_RESULT([no])
enable_pimd="no"
diff --git a/doc/developer/building-frr-for-archlinux.rst b/doc/developer/building-frr-for-archlinux.rst
new file mode 100644
index 0000000000..7ede35ad9c
--- /dev/null
+++ b/doc/developer/building-frr-for-archlinux.rst
@@ -0,0 +1,129 @@
+Arch Linux
+================
+
+Installing Dependencies
+-----------------------
+
+.. code-block:: console
+
+ sudo pacman -Syu
+ sudo pacman -S \
+ git autoconf automake libtool make cmake pcre readline texinfo \
+ pkg-config pam json-c bison flex python-pytest \
+ c-ares python systemd python2-ipaddress python-sphinx \
+ systemd-libs net-snmp perl libcap
+
+.. include:: building-libyang.rst
+
+Protobuf
+^^^^^^^^
+
+.. code-block:: console
+
+ sudo pacman -S protobuf-c
+
+ZeroMQ
+^^^^^^
+
+.. code-block:: console
+
+ sudo pacman -S zeromq
+
+Building & Installing FRR
+-------------------------
+
+Add FRR user and groups
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+ sudo groupadd -r -g 92 frr
+ sudo groupadd -r -g 85 frrvty
+ sudo useradd --system -g frr --home-dir /var/run/frr/ \
+ -c "FRR suite" --shell /sbin/nologin frr
+ sudo usermod -a -G frrvty frr
+
+Compile
+^^^^^^^
+
+.. include:: include-compile.rst
+
+Install FRR configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+ sudo install -m 775 -o frr -g frr -d /var/log/frr
+ sudo install -m 775 -o frr -g frrvty -d /etc/frr
+ sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
+
+Tweak sysctls
+^^^^^^^^^^^^^
+
+Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
+MPLS (if supported by your platform). If your platform does not support MPLS,
+skip the MPLS related configuration in this section.
+
+Edit :file:`/etc/sysctl.conf`[*Create the file if it doesn't exist*] and
+append the following values (ignore the other settings):
+
+::
+
+ # Enable packet forwarding for IPv4
+ net.ipv4.ip_forward=1
+
+ # Enable packet forwarding for IPv6
+ net.ipv6.conf.all.forwarding=1
+
+Reboot or use ``sysctl -p`` to apply the same config to the running system.
+
+Add MPLS kernel modules
+"""""""""""""""""""""""
+
+To
+enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
+
+::
+
+ # Load MPLS Kernel Modules
+ mpls_router
+ mpls_iptunnel
+
+
+And load the kernel modules on the running system:
+
+.. code-block:: console
+
+ sudo modprobe mpls-router mpls-iptunnel
+
+Enable MPLS Forwarding
+""""""""""""""""""""""
+
+Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
+equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
+
+::
+
+ # Enable MPLS Label processing on all interfaces
+ net.mpls.conf.eth0.input=1
+ net.mpls.conf.eth1.input=1
+ net.mpls.conf.eth2.input=1
+ net.mpls.platform_labels=100000
+
+Install service files
+^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+ sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
+ sudo systemctl enable frr
+
+Start FRR
+^^^^^^^^^
+
+.. code-block:: shell
+
+ systemctl start frr
diff --git a/doc/developer/building-frr-for-centos6.rst b/doc/developer/building-frr-for-centos6.rst
index 04c6b922ce..b730a5ee32 100644
--- a/doc/developer/building-frr-for-centos6.rst
+++ b/doc/developer/building-frr-for-centos6.rst
@@ -116,7 +116,19 @@ Update rpm database & Install newer sphinx
sudo yum update
sudo yum install python27-sphinx
-.. include:: building-libyang.rst
+Install libyang and its dependencies:
+
+.. code-block:: shell
+
+ sudo yum install pcre-devel doxygen cmake
+ git clone https://github.com/CESNET/libyang.git
+ cd libyang
+ git checkout 090926a89d59a3c4000719505d563aaf6ac60f2
+ mkdir build ; cd build
+ cmake -DENABLE_LYD_PRIV=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr -D CMAKE_BUILD_TYPE:String="Release" ..
+ make build-rpm
+ sudo yum install ./rpms/RPMS/x86_64/libyang-0.16.111-0.x86_64.rpm ./rpms/RPMS/x86_64/libyang-devel-0.16.111-0.x86_64.rpm
+ cd ../..
Get FRR, compile it and install it (from Git)
---------------------------------------------
diff --git a/doc/developer/building.rst b/doc/developer/building.rst
index 859f612313..ef55954ac2 100644
--- a/doc/developer/building.rst
+++ b/doc/developer/building.rst
@@ -26,3 +26,4 @@ Building FRR
building-frr-for-ubuntu1404
building-frr-for-ubuntu1604
building-frr-for-ubuntu1804
+ building-frr-for-archlinux
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index 3144b3c28e..fc70a344c8 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -1398,8 +1398,8 @@ void cli_show_ip_isis_metric(struct vty *vty, struct lyd_node *dnode,
if (strmatch(l1, l2))
vty_out(vty, " isis metric %s\n", l1);
else {
- vty_out(vty, " isis metric %s level-1\n", l1);
- vty_out(vty, " isis metric %s level-2\n", l2);
+ vty_out(vty, " isis metric level-1 %s\n", l1);
+ vty_out(vty, " isis metric level-2 %s\n", l2);
}
}
diff --git a/lib/lib_vty.c b/lib/lib_vty.c
index 787da08e28..9c927ca4af 100644
--- a/lib/lib_vty.c
+++ b/lib/lib_vty.c
@@ -93,7 +93,7 @@ static int qmem_walker(void *arg, struct memgroup *mg, struct memtype *mt)
#endif
);
} else {
- if (mt->n_alloc != 0) {
+ if (mt->n_max != 0) {
char size[32];
snprintf(size, sizeof(size), "%6zu", mt->size);
#ifdef HAVE_MALLOC_USABLE_SIZE
diff --git a/lib/ntop.c b/lib/ntop.c
index 066e10e3e4..ccbf8793d3 100644
--- a/lib/ntop.c
+++ b/lib/ntop.c
@@ -165,7 +165,7 @@ inet4:
return dst;
}
-#ifndef INET_NTOP_NO_OVERRIDE
+#if !defined(INET_NTOP_NO_OVERRIDE) && !defined(__APPLE__)
/* we want to override libc inet_ntop, but make sure it shows up in backtraces
* as frr_inet_ntop (to avoid confusion while debugging)
*/
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index d87f02627b..0808f245e2 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -2335,7 +2335,7 @@ static struct stream *ospf_recv_packet(struct ospf *ospf, int fd,
ip_len = iph->ip_len;
-#if !defined(GNU_LINUX) && (OpenBSD < 200311) && (__FreeBSD_version < 1000000)
+#if defined(__FreeBSD__) && (__FreeBSD_version < 1000000)
/*
* Kernel network code touches incoming IP header parameters,
* before protocol specific processing.
diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c
index c97ea57150..7fabaad7fa 100644
--- a/tests/bgpd/test_mp_attr.c
+++ b/tests/bgpd/test_mp_attr.c
@@ -951,12 +951,19 @@ static struct test_segment mp_prefix_sid[] = {
"PREFIX-SID",
"PREFIX-SID Test 1",
{
- 0x01, 0x00, 0x07,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x02,
- 0x03, 0x00, 0x08, 0x00,
- 0x00, 0x0a, 0x1b, 0xfe,
- 0x00, 0x00, 0x0a
+ /* TLV[0] Latel-Index TLV */
+ 0x01, /* Type 0x01:Label-Index */
+ 0x00, 0x07, /* Length */
+ 0x00, /* RESERVED */
+ 0x00, 0x00, /* Flags */
+ 0x00, 0x00, 0x00, 0x02, /* Label Index */
+
+ /* TLV[1] SRGB TLV */
+ 0x03, /* Type 0x03:SRGB */
+ 0x00, 0x08, /* Length */
+ 0x00, 0x00, /* Flags */
+ 0x0a, 0x1b, 0xfe, /* SRGB[0] first label */
+ 0x00, 0x00, 0x0a /* SRBG[0] nb-labels in range */
},
.len = 21,
.parses = SHOULD_PARSE,
@@ -1027,7 +1034,7 @@ static void parse_test(struct peer *peer, struct test_segment *t, int type)
parse_ret = bgp_mp_unreach_parse(&attr_args, &nlri);
break;
case BGP_ATTR_PREFIX_SID:
- parse_ret = bgp_attr_prefix_sid(&attr_args, &nlri);
+ parse_ret = bgp_attr_prefix_sid(&attr_args);
break;
default:
printf("unknown type");
diff --git a/tests/topotests/bgp_prefix_sid/__init__.py b/tests/topotests/bgp_prefix_sid/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_prefix_sid/__init__.py
diff --git a/tests/topotests/bgp_prefix_sid/exabgp.env b/tests/topotests/bgp_prefix_sid/exabgp.env
new file mode 100644
index 0000000000..6c554f5fa8
--- /dev/null
+++ b/tests/topotests/bgp_prefix_sid/exabgp.env
@@ -0,0 +1,53 @@
+
+[exabgp.api]
+encoder = text
+highres = false
+respawn = false
+socket = ''
+
+[exabgp.bgp]
+openwait = 60
+
+[exabgp.cache]
+attributes = true
+nexthops = true
+
+[exabgp.daemon]
+daemonize = true
+pid = '/var/run/exabgp/exabgp.pid'
+user = 'exabgp'
+
+[exabgp.log]
+all = false
+configuration = true
+daemon = true
+destination = '/var/log/exabgp.log'
+enable = true
+level = INFO
+message = false
+network = true
+packets = false
+parser = false
+processes = true
+reactor = true
+rib = false
+routes = false
+short = false
+timers = false
+
+[exabgp.pdb]
+enable = false
+
+[exabgp.profile]
+enable = false
+file = ''
+
+[exabgp.reactor]
+speed = 1.0
+
+[exabgp.tcp]
+acl = false
+bind = ''
+delay = 0
+once = false
+port = 179
diff --git a/tests/topotests/bgp_prefix_sid/peer1/exabgp.cfg b/tests/topotests/bgp_prefix_sid/peer1/exabgp.cfg
new file mode 100644
index 0000000000..5b55366a0e
--- /dev/null
+++ b/tests/topotests/bgp_prefix_sid/peer1/exabgp.cfg
@@ -0,0 +1,103 @@
+group controller {
+ neighbor 10.0.0.1 {
+ router-id 10.0.0.101;
+ local-address 10.0.0.101;
+ local-as 2;
+ peer-as 1;
+
+ family {
+ ipv4 nlri-mpls;
+ }
+
+ static {
+ # ref: draft-ietf-idr-bgp-prefix-sid-27
+ #
+ # IANA temporarily assigned the following:
+ # attribute code type (suggested value: 40) to
+ # the BGP Prefix-SID attribute
+ #
+ # 0 1 2 3
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Type | Length | RESERVED |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Flags | Label Index |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Label Index |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # Figure. Label-Index TLV (Prefix-SID type-1)
+ #
+ # 0 1 2 3
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Type | Length | Flags |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Flags |
+ # +-+-+-+-+-+-+-+-+
+ #
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | SRGB 1 (6 octets) |
+ # | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ #
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | SRGB n (6 octets) |
+ # | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<Paste>
+ # Figure. Originator SRGB TLV (Prefix-SID type-3)
+
+ # ExaBGP generic-attribute binary pattern:
+ # Attribute-type: 0x28 (40:BGP_PREFIX_SID)
+ # Attribute-flag: 0xc0 (Option, Transitive)
+ # Attribute-body: Label-Index TLV and Originator SRGB TLV
+ # Label-Index TLV: 0x01000700000000000001
+ # Type (08bit): 0x01
+ # Length (16bit): 0x0007
+ # RESERVED (08bit): 0x00
+ # Flags (16bit): 0x0000
+ # Label Index (32bit): 0x00000001
+ # Originator SRGB TLV: 0x03000800000c350000000a
+ # Type (08bit): 0x03
+ # Length (16bit): 0x0008 (nb-SRGB is 1)
+ # Flags (16bit): 0x0000
+ # SRGB1 (48bit): 0x0c3500:0x00000a (800000-800010 is SRGB1)
+ route 3.0.0.1/32 next-hop 10.0.0.101 label [800001] attribute [0x28 0xc0 0x0100070000000000000103000800000c350000000a];
+
+ # ExaBGP generic-attribute binary pattern:
+ # Attribute-type: 0x28 (40:BGP_PREFIX_SID)
+ # Attribute-flag: 0xc0 (Option, Transitive)
+ # Attribute-body: Label-Index TLV and Originator SRGB TLV
+ # Label-Index TLV: 0x01000700000000000001
+ # Type (08bit): 0x01
+ # Length (16bit): 0x0007
+ # RESERVED (08bit): 0x00
+ # Flags (16bit): 0x0000
+ # Label Index (32bit): 0x00000002
+ # Originator SRGB TLV: 0x03000800000c350000000a
+ # Type (08bit): 0x03
+ # Length (16bit): 0x0008 (nb-SRGB is 1)
+ # Flags (16bit): 0x0000
+ # SRGB1 (48bit): 0x0c3500:0x00000a (800000-800010 is SRGB1)
+ route 3.0.0.2/32 next-hop 10.0.0.101 label [800002] attribute [0x28 0xc0 0x0100070000000000000203000800000c350000000a];
+
+ # ExaBGP generic-attribute binary pattern:
+ # Attribute-type: 0x28 (40:BGP_PREFIX_SID)
+ # Attribute-flag: 0xc0 (Option, Transitive)
+ # Attribute-body: Label-Index TLV and Originator SRGB TLV
+ # Label-Index TLV: 0x01000700000000000001
+ # Type (08bit): 0x01
+ # Length (16bit): 0x0007
+ # RESERVED (08bit): 0x00
+ # Flags (16bit): 0x0000
+ # Label Index (32bit): 0x00000003
+ # Originator SRGB TLV: 0x03000800000c350000000a
+ # Type (08bit): 0x03
+ # Length (16bit): 0x0008 (nb-SRGB is 1)
+ # Flags (16bit): 0x0000
+ # SRGB1 (48bit): 0x0c3500:0x00000a (800000-800010 is SRGB1)
+ route 3.0.0.3/32 next-hop 10.0.0.101 label [800003] attribute [0x28 0xc0 0x0100070000000000000303000800000c350000000a];
+ }
+ }
+}
diff --git a/tests/topotests/bgp_prefix_sid/peer2/exa-receive.py b/tests/topotests/bgp_prefix_sid/peer2/exa-receive.py
new file mode 100755
index 0000000000..eaa6a67872
--- /dev/null
+++ b/tests/topotests/bgp_prefix_sid/peer2/exa-receive.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+"""
+exa-receive.py: Save received routes form ExaBGP into file
+"""
+
+from sys import stdin,argv
+from datetime import datetime
+
+# 1st arg is peer number
+peer = int(argv[1])
+
+# When the parent dies we are seeing continual newlines, so we only access so many before stopping
+counter = 0
+
+routesavefile = open('/tmp/peer%s-received.log' % peer, 'w')
+
+while True:
+ try:
+ line = stdin.readline()
+ routesavefile.write(line)
+ routesavefile.flush()
+
+ if line == "":
+ counter += 1
+ if counter > 100:
+ break
+ continue
+
+ counter = 0
+ except KeyboardInterrupt:
+ pass
+ except IOError:
+ # most likely a signal during readline
+ pass
+
+routesavefile.close()
diff --git a/tests/topotests/bgp_prefix_sid/peer2/exabgp.cfg b/tests/topotests/bgp_prefix_sid/peer2/exabgp.cfg
new file mode 100644
index 0000000000..dabd88e03d
--- /dev/null
+++ b/tests/topotests/bgp_prefix_sid/peer2/exabgp.cfg
@@ -0,0 +1,19 @@
+group controller {
+
+ process receive-routes {
+ run "/etc/exabgp/exa-receive.py 2";
+ receive-routes;
+ encoder json;
+ }
+
+ neighbor 10.0.0.1 {
+ router-id 10.0.0.102;
+ local-address 10.0.0.102;
+ local-as 3;
+ peer-as 1;
+
+ family {
+ ipv4 nlri-mpls;
+ }
+ }
+}
diff --git a/tests/topotests/bgp_prefix_sid/r1/bgpd.conf b/tests/topotests/bgp_prefix_sid/r1/bgpd.conf
new file mode 100644
index 0000000000..7a38cc307f
--- /dev/null
+++ b/tests/topotests/bgp_prefix_sid/r1/bgpd.conf
@@ -0,0 +1,15 @@
+log stdout notifications
+log monitor notifications
+log commands
+!
+router bgp 1
+ bgp router-id 10.0.0.1
+ no bgp default ipv4-unicast
+ neighbor 10.0.0.101 remote-as 2
+ neighbor 10.0.0.102 remote-as 3
+ !
+ address-family ipv4 labeled-unicast
+ neighbor 10.0.0.101 activate
+ neighbor 10.0.0.102 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_prefix_sid/r1/zebra.conf b/tests/topotests/bgp_prefix_sid/r1/zebra.conf
new file mode 100644
index 0000000000..0cd26052f2
--- /dev/null
+++ b/tests/topotests/bgp_prefix_sid/r1/zebra.conf
@@ -0,0 +1,7 @@
+hostname r1
+!
+interface r1-eth0
+ ip address 10.0.0.1/24
+ no shutdown
+!
+line vty
diff --git a/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py
new file mode 100755
index 0000000000..dc203cabc5
--- /dev/null
+++ b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py
@@ -0,0 +1,173 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_prefix_sid.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by LINE Corporation
+# Copyright (c) 2020 by Hiroki Shirokura <slank.dev@gmail.com>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bgp_prefix_sid.py: Test BGP topology with EBGP on prefix-sid
+"""
+
+import json
+import os
+import sys
+import functools
+import pytest
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+
+
+class TemplateTopo(Topo):
+ def build(self, **_opts):
+ tgen = get_topogen(self)
+ router = tgen.add_router('r1')
+ switch = tgen.add_switch('s1')
+ switch.add_link(router)
+
+ switch = tgen.gears['s1']
+ peer1 = tgen.add_exabgp_peer('peer1', ip='10.0.0.101', defaultRoute='via 10.0.0.1')
+ peer2 = tgen.add_exabgp_peer('peer2', ip='10.0.0.102', defaultRoute='via 10.0.0.1')
+ switch.add_link(peer1)
+ switch.add_link(peer2)
+
+
+def setup_module(module):
+ tgen = Topogen(TemplateTopo, module.__name__)
+ tgen.start_topology()
+
+ router = tgen.gears['r1']
+ router.load_config(TopoRouter.RD_ZEBRA, os.path.join(CWD, '{}/zebra.conf'.format('r1')))
+ router.load_config(TopoRouter.RD_BGP, os.path.join(CWD, '{}/bgpd.conf'.format('r1')))
+ router.start()
+
+ logger.info('starting exaBGP on peer1')
+ peer_list = tgen.exabgp_peers()
+ for pname, peer in peer_list.iteritems():
+ peer_dir = os.path.join(CWD, pname)
+ env_file = os.path.join(CWD, 'exabgp.env')
+ logger.info('Running ExaBGP peer')
+ peer.start(peer_dir, env_file)
+ logger.info(pname)
+
+
+def teardown_module(module):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_r1_receive_and_advertise_prefix_sid_type1():
+ tgen = get_topogen()
+ router = tgen.gears['r1']
+
+ def _check_type1_r1(router, prefix, remoteLabel, labelIndex):
+ output = router.vtysh_cmd('show bgp ipv4 labeled-unicast {} json'.format(prefix))
+ output = json.loads(output)
+ expected = {
+ 'prefix': prefix,
+ 'advertisedTo': { '10.0.0.101':{}, '10.0.0.102':{} },
+ 'paths': [{
+ 'valid':True,
+ 'remoteLabel': remoteLabel,
+ 'labelIndex': labelIndex,
+ }]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_check_type1_r1, router, '3.0.0.1/32', 800001, 1)
+ success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assert result is None, 'Failed _check_type1_r1 in "{}"'.format(router)
+
+ test_func = functools.partial(_check_type1_r1, router, '3.0.0.2/32', 800002, 2)
+ success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assert result is None, 'Failed _check_type1_r1 in "{}"'.format(router)
+
+
+def exabgp_get_update_prefix(filename, afi, nexthop, prefix):
+ with open('/tmp/peer2-received.log') as f:
+ for line in f.readlines():
+ output = json.loads(line)
+ ret = output.get('neighbor')
+ if ret is None:
+ continue
+ ret = ret.get('message')
+ if ret is None:
+ continue
+ ret = ret.get('update')
+ if ret is None:
+ continue
+ ret = ret.get('announce')
+ if ret is None:
+ continue
+ ret = ret.get(afi)
+ if ret is None:
+ continue
+ ret = ret.get(nexthop)
+ if ret is None:
+ continue
+ ret = ret.get(prefix)
+ if ret is None:
+ continue
+ return output
+ return "Not found"
+
+
+def test_peer2_receive_prefix_sid_type1():
+ tgen = get_topogen()
+ peer2 = tgen.gears['peer2']
+
+ def _check_type1_peer2(prefix, labelindex):
+ output = exabgp_get_update_prefix('/tmp/peer2-received.log', 'ipv4 nlri-mpls', '10.0.0.101', prefix)
+ expected = {
+ 'type': 'update',
+ 'neighbor': {
+ 'ip': '10.0.0.1',
+ 'message': {
+ 'update': {
+ 'attribute': {
+ 'attribute-0x28-0xE0': '0x010007000000{:08x}'.format(labelindex)
+ },
+ 'announce': { 'ipv4 nlri-mpls': { '10.0.0.101': {} } }
+ }
+ }
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_check_type1_peer2, '3.0.0.1/32', labelindex=1)
+ success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assert result is None, 'Failed _check_type1_peer2 in "{}"'.format('peer2')
+
+ test_func = functools.partial(_check_type1_peer2, '3.0.0.2/32', labelindex=2)
+ success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assert result is None, 'Failed _check_type1_peer2 in "{}"'.format('peer2')
+
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ ret = pytest.main(args)
+ sys.exit(ret)
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index e40bf45f59..2cc520bbce 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -1340,6 +1340,8 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
bytelen);
rtnh->rtnh_len += sizeof(struct rtattr) + bytelen;
rtnh->rtnh_ifindex = nexthop->ifindex;
+ if (nexthop->weight)
+ rtnh->rtnh_hops = nexthop->weight - 1;
if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
*src = &nexthop->rmap_src;