summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_community.c6
-rw-r--r--bgpd/bgp_lcommunity.c6
-rw-r--r--bgpd/bgp_route.c146
-rw-r--r--bgpd/bgp_route.h1
-rw-r--r--bgpd/bgp_vty.c4
-rw-r--r--bgpd/bgp_zebra.c20
-rw-r--r--doc/developer/grpc.rst282
-rw-r--r--doc/user/bgp.rst4
-rw-r--r--doc/user/ospfd.rst2
-rw-r--r--doc/user/pathd.rst4
-rw-r--r--isisd/isisd.c6
-rw-r--r--lib/route_opaque.h38
-rw-r--r--lib/subdir.am1
-rw-r--r--lib/vrf.c2
-rw-r--r--ospf6d/ospf6_asbr.c2
-rw-r--r--ospfd/ospf_vty.c4
-rw-r--r--pimd/pim_igmp.c4
-rw-r--r--pimd/pim_oil.c8
-rw-r--r--tests/topotests/bgp_community_alias/r1/bgpd.conf4
-rw-r--r--tests/topotests/bgp_community_alias/r2/bgpd.conf9
-rw-r--r--tests/topotests/bgp_community_alias/r2/zebra.conf4
-rw-r--r--tests/topotests/bgp_community_alias/test_bgp-community-alias.py26
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py4
-rw-r--r--tests/topotests/ospf_sr_topo1/rt1/ospfd.conf2
-rw-r--r--tests/topotests/ospf_sr_topo1/rt2/ospfd.conf6
-rw-r--r--tests/topotests/ospf_sr_topo1/rt3/ospfd.conf6
-rw-r--r--tests/topotests/ospf_sr_topo1/rt4/ospfd.conf8
-rw-r--r--tests/topotests/ospf_sr_topo1/rt5/ospfd.conf8
-rw-r--r--tests/topotests/ospf_sr_topo1/rt6/ospfd.conf4
-rw-r--r--tests/topotests/zebra_opaque/__init__.py0
-rw-r--r--tests/topotests/zebra_opaque/r1/bgpd.conf5
-rw-r--r--tests/topotests/zebra_opaque/r1/zebra.conf4
-rw-r--r--tests/topotests/zebra_opaque/r2/bgpd.conf12
-rw-r--r--tests/topotests/zebra_opaque/r2/zebra.conf4
-rw-r--r--tests/topotests/zebra_opaque/test_zebra_opaque.py104
-rw-r--r--yang/frr-bgp-neighbor.yang2
-rw-r--r--yang/frr-bgp-peer-group.yang2
-rw-r--r--yang/frr-bgp.yang28
-rw-r--r--yang/frr-pim-rp.yang41
-rw-r--r--yang/frr-route-types.yang35
-rw-r--r--zebra/zebra_vty.c35
41 files changed, 754 insertions, 139 deletions
diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c
index b034ec9f7b..2aa6a56a5e 100644
--- a/bgpd/bgp_community.c
+++ b/bgpd/bgp_community.c
@@ -451,9 +451,11 @@ static void set_community_string(struct community *com, bool make_json)
val = comval & 0xFFFF;
char buf[32];
snprintf(buf, sizeof(buf), "%u:%d", as, val);
- strlcat(str, bgp_community2alias(buf), len);
+ const char *com2alias = bgp_community2alias(buf);
+
+ strlcat(str, com2alias, len);
if (make_json) {
- json_string = json_object_new_string(buf);
+ json_string = json_object_new_string(com2alias);
json_object_array_add(json_community_list,
json_string);
}
diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c
index ff34937efc..fa4d4aee28 100644
--- a/bgpd/bgp_lcommunity.c
+++ b/bgpd/bgp_lcommunity.c
@@ -232,11 +232,13 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json)
snprintf(lcsb, sizeof(lcsb), "%u:%u:%u", global, local1,
local2);
- len = strlcat(str_buf, bgp_community2alias(lcsb), str_buf_sz);
+ const char *com2alias = bgp_community2alias(lcsb);
+
+ len = strlcat(str_buf, com2alias, str_buf_sz);
assert((unsigned int)len < str_buf_sz);
if (make_json) {
- json_string = json_object_new_string(lcsb);
+ json_string = json_object_new_string(com2alias);
json_object_array_add(json_lcommunity_list,
json_string);
}
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 2c792b7abf..c61aedb560 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -23,6 +23,7 @@
#include <math.h>
#include "printfrr.h"
+#include "frrstr.h"
#include "prefix.h"
#include "linklist.h"
#include "memory.h"
@@ -7806,14 +7807,14 @@ int bgp_aggregate_set(struct bgp *bgp, struct prefix *prefix, afi_t afi,
DEFPY_YANG(
aggregate_addressv4, aggregate_addressv4_cmd,
- "[no] aggregate-address <A.B.C.D/M$prefix|A.B.C.D$addr A.B.C.D$mask> {"
+ "[no] aggregate-address <A.B.C.D/M$prefix|A.B.C.D$addr A.B.C.D$mask> [{"
"as-set$as_set_s"
"|summary-only$summary_only"
"|route-map WORD$rmap_name"
"|origin <egp|igp|incomplete>$origin_s"
"|matching-MED-only$match_med"
"|suppress-map WORD$suppress_map"
- "}",
+ "}]",
NO_STR
"Configure BGP aggregate entries\n"
"Aggregate prefix\n"
@@ -7896,14 +7897,14 @@ DEFPY_YANG(
}
DEFPY_YANG(aggregate_addressv6, aggregate_addressv6_cmd,
- "[no] aggregate-address X:X::X:X/M$prefix {"
+ "[no] aggregate-address X:X::X:X/M$prefix [{"
"as-set$as_set_s"
"|summary-only$summary_only"
"|route-map WORD$rmap_name"
"|origin <egp|igp|incomplete>$origin_s"
"|matching-MED-only$match_med"
"|suppress-map WORD$suppress_map"
- "}",
+ "}]",
NO_STR
"Configure BGP aggregate entries\n"
"Aggregate prefix\n"
@@ -10570,7 +10571,6 @@ static int bgp_show_community(struct vty *vty, struct bgp *bgp,
const char *comstr, int exact, afi_t afi,
safi_t safi, uint8_t show_flags);
-
static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
struct bgp_table *table, enum bgp_show_type type,
void *output_arg, char *rd, int is_last,
@@ -10647,6 +10647,48 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
continue;
}
+ if (type == bgp_show_type_community_alias) {
+ char *alias = output_arg;
+ char **communities;
+ int num;
+ bool found = false;
+
+ if (pi->attr->community) {
+ frrstr_split(pi->attr->community->str,
+ " ", &communities, &num);
+ for (int i = 0; i < num; i++) {
+ const char *com2alias =
+ bgp_community2alias(
+ communities[i]);
+ if (strncmp(alias, com2alias,
+ strlen(com2alias))
+ == 0) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found && pi->attr->lcommunity) {
+ frrstr_split(pi->attr->lcommunity->str,
+ " ", &communities, &num);
+ for (int i = 0; i < num; i++) {
+ const char *com2alias =
+ bgp_community2alias(
+ communities[i]);
+ if (strncmp(alias, com2alias,
+ strlen(com2alias))
+ == 0) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ continue;
+ }
+
if (type == bgp_show_type_rpki) {
if (dest_p->family == AF_INET
|| dest_p->family == AF_INET6)
@@ -11920,9 +11962,10 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
}
/* BGP route print out function with JSON */
-DEFPY (show_ip_bgp_json,
- show_ip_bgp_json_cmd,
- "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]\
+DEFPY(show_ip_bgp_json, show_ip_bgp_json_cmd,
+ "show [ip] bgp [<view|vrf> VIEWVRFNAME] [" BGP_AFI_CMD_STR
+ " [" BGP_SAFI_WITH_LABEL_CMD_STR
+ "]]\
[all$all]\
[cidr-only\
|dampening <flap-statistics|dampened-paths>\
@@ -11933,44 +11976,41 @@ DEFPY (show_ip_bgp_json,
|route-filter-translated-v4] [exact-match]\
|rpki <invalid|valid|notfound>\
|version (1-4294967295)\
+ |alias WORD\
] [json$uj [detail$detail] | wide$wide]",
- SHOW_STR
- IP_STR
- BGP_STR
- BGP_INSTANCE_HELP_STR
- BGP_AFI_HELP_STR
- BGP_SAFI_WITH_LABEL_HELP_STR
- "Display the entries for all address families\n"
- "Display only routes with non-natural netmasks\n"
- "Display detailed information about dampening\n"
- "Display flap statistics of routes\n"
- "Display paths suppressed due to dampening\n"
- "Display routes matching the communities\n"
- COMMUNITY_AANN_STR
- "Do not send outside local AS (well-known community)\n"
- "Do not advertise to any peer (well-known community)\n"
- "Do not export to next AS (well-known community)\n"
- "Graceful shutdown (well-known community)\n"
- "Do not export to any peer (well-known community)\n"
- "Inform EBGP peers to blackhole traffic to prefix (well-known community)\n"
- "Staled Long-lived Graceful Restart VPN route (well-known community)\n"
- "Removed because Long-lived Graceful Restart was not enabled for VPN route (well-known community)\n"
- "Should accept local VPN route if exported and imported into different VRF (well-known community)\n"
- "Should accept VPN route with local nexthop (well-known community)\n"
- "RT VPNv6 route filtering (well-known community)\n"
- "RT VPNv4 route filtering (well-known community)\n"
- "RT translated VPNv6 route filtering (well-known community)\n"
- "RT translated VPNv4 route filtering (well-known community)\n"
- "Exact match of the communities\n"
- "RPKI route types\n"
- "A valid path as determined by rpki\n"
- "A invalid path as determined by rpki\n"
- "A path that has no rpki data\n"
- "Display prefixes with matching version numbers\n"
- "Version number and above\n"
- JSON_STR
- "Display detailed version of JSON output\n"
- "Increase table width for longer prefixes\n")
+ SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
+ BGP_SAFI_WITH_LABEL_HELP_STR
+ "Display the entries for all address families\n"
+ "Display only routes with non-natural netmasks\n"
+ "Display detailed information about dampening\n"
+ "Display flap statistics of routes\n"
+ "Display paths suppressed due to dampening\n"
+ "Display routes matching the communities\n" COMMUNITY_AANN_STR
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Graceful shutdown (well-known community)\n"
+ "Do not export to any peer (well-known community)\n"
+ "Inform EBGP peers to blackhole traffic to prefix (well-known community)\n"
+ "Staled Long-lived Graceful Restart VPN route (well-known community)\n"
+ "Removed because Long-lived Graceful Restart was not enabled for VPN route (well-known community)\n"
+ "Should accept local VPN route if exported and imported into different VRF (well-known community)\n"
+ "Should accept VPN route with local nexthop (well-known community)\n"
+ "RT VPNv6 route filtering (well-known community)\n"
+ "RT VPNv4 route filtering (well-known community)\n"
+ "RT translated VPNv6 route filtering (well-known community)\n"
+ "RT translated VPNv4 route filtering (well-known community)\n"
+ "Exact match of the communities\n"
+ "RPKI route types\n"
+ "A valid path as determined by rpki\n"
+ "A invalid path as determined by rpki\n"
+ "A path that has no rpki data\n"
+ "Display prefixes with matching version numbers\n"
+ "Version number and above\n"
+ "Display prefixes with matching BGP community alias\n"
+ "BGP community alias\n" JSON_STR
+ "Display detailed version of JSON output\n"
+ "Increase table width for longer prefixes\n")
{
afi_t afi = AFI_IP6;
safi_t safi = SAFI_UNICAST;
@@ -11980,6 +12020,7 @@ DEFPY (show_ip_bgp_json,
int exact_match = 0;
char *community = NULL;
char *prefix_version = NULL;
+ char *bgp_community_alias = NULL;
bool first = true;
uint8_t show_flags = 0;
enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED;
@@ -12056,6 +12097,12 @@ DEFPY (show_ip_bgp_json,
prefix_version = argv[idx + 1]->arg;
}
+ /* Display prefixes with matching BGP community alias */
+ if (argv_find(argv, argc, "alias", &idx)) {
+ sh_type = bgp_show_type_community_alias;
+ bgp_community_alias = argv[idx + 1]->arg;
+ }
+
if (!all) {
/* show bgp: AFI_IP6, show ip bgp: AFI_IP */
if (community)
@@ -12066,6 +12113,10 @@ DEFPY (show_ip_bgp_json,
return bgp_show(vty, bgp, afi, safi, sh_type,
prefix_version, show_flags,
rpki_target_state);
+ else if (bgp_community_alias)
+ return bgp_show(vty, bgp, afi, safi, sh_type,
+ bgp_community_alias, show_flags,
+ rpki_target_state);
else
return bgp_show(vty, bgp, afi, safi, sh_type, NULL,
show_flags, rpki_target_state);
@@ -12108,6 +12159,11 @@ DEFPY (show_ip_bgp_json,
sh_type, prefix_version,
show_flags,
rpki_target_state);
+ else if (bgp_community_alias)
+ return bgp_show(
+ vty, bgp, afi, safi, sh_type,
+ bgp_community_alias, show_flags,
+ rpki_target_state);
else
bgp_show(vty, bgp, afi, safi, sh_type,
NULL, show_flags,
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index e58213a688..6d6008ff55 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -42,6 +42,7 @@ enum bgp_show_type {
bgp_show_type_neighbor,
bgp_show_type_cidr_only,
bgp_show_type_prefix_longer,
+ bgp_show_type_community_alias,
bgp_show_type_community_all,
bgp_show_type_community,
bgp_show_type_community_exact,
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index e73ec20448..77f1aadff7 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -5070,7 +5070,7 @@ ALIAS_HIDDEN(neighbor_set_peer_group, neighbor_set_peer_group_hidden_cmd,
DEFUN_YANG (no_neighbor_set_peer_group,
no_neighbor_set_peer_group_cmd,
- "no neighbor <A.B.C.D|X:X::X:X|WORD> peer-group [PGNAME]",
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> peer-group PGNAME",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
@@ -5091,7 +5091,7 @@ DEFUN_YANG (no_neighbor_set_peer_group,
}
ALIAS_HIDDEN(no_neighbor_set_peer_group, no_neighbor_set_peer_group_hidden_cmd,
- "no neighbor <A.B.C.D|X:X::X:X|WORD> peer-group [PGNAME]",
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> peer-group PGNAME",
NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
"Member of the peer-group\n"
"Peer-group name\n")
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 2bf57130be..97f781b2bf 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -33,6 +33,7 @@
#include "memory.h"
#include "lib/json.h"
#include "lib/bfd.h"
+#include "lib/route_opaque.h"
#include "filter.h"
#include "mpls.h"
#include "vxlan.h"
@@ -1400,11 +1401,24 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
is_add = (valid_nh_count || nhg_id) ? true : false;
if (is_add && CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) {
- struct aspath *aspath = info->attr->aspath;
+ struct bgp_zebra_opaque bzo = {};
+
+ strlcpy(bzo.aspath, info->attr->aspath->str,
+ sizeof(bzo.aspath));
+
+ if (info->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))
+ strlcpy(bzo.community, info->attr->community->str,
+ sizeof(bzo.community));
+
+ if (info->attr->flag
+ & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))
+ strlcpy(bzo.lcommunity, info->attr->lcommunity->str,
+ sizeof(bzo.lcommunity));
SET_FLAG(api.message, ZAPI_MESSAGE_OPAQUE);
- api.opaque.length = strlen(aspath->str) + 1;
- memcpy(api.opaque.data, aspath->str, api.opaque.length);
+ api.opaque.length = MIN(sizeof(struct bgp_zebra_opaque),
+ ZAPI_MESSAGE_OPAQUE_LENGTH);
+ memcpy(api.opaque.data, &bzo, api.opaque.length);
}
if (allow_recursion)
diff --git a/doc/developer/grpc.rst b/doc/developer/grpc.rst
index 8029a08b73..cb164bdabf 100644
--- a/doc/developer/grpc.rst
+++ b/doc/developer/grpc.rst
@@ -4,6 +4,17 @@
Northbound gRPC
***************
+To enable gRPC support one needs to add `--enable-grpc` when running
+`configure`. Additionally, when launching each daemon one needs to request
+the gRPC module be loaded and which port to bind to. This can be done by adding
+`-M grpc:<port>` to the daemon's CLI arguments.
+
+Currently there is no gRPC "routing" so you will need to bind your gRPC
+`channel` to the particular daemon's gRPC port to interact with that daemon's
+gRPC northbound interface.
+
+The minimum version of gRPC known to work is 1.16.1.
+
.. _grpc-languages-bindings:
Programming Language Bindings
@@ -17,14 +28,277 @@ next step is to generate the FRR northbound bindings. To generate the
northbound bindings you'll need the programming language binding
generator tools and those are language specific.
-Next sections will use Ruby as an example for writing scripts to use
+C++ Example
+-----------
+
+The next sections will use C++ as an example for accessing FRR
+northbound through gRPC.
+
+.. _grpc-c++-generate:
+
+Generating C++ FRR Bindings
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Generating FRR northbound bindings for C++ example:
+
+::
+ # Install gRPC (e.g., on Ubuntu 20.04)
+ sudo apt-get install libgrpc++-dev libgrpc-dev
+
+ mkdir /tmp/frr-cpp
+ cd grpc
+
+ protoc --cpp_out=/tmp/frr-cpp \
+ --grpc_out=/tmp/frr-cpp \
+ -I $(pwd) \
+ --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` \
+ frr-northbound.proto
+
+
+.. _grpc-c++-if-sample:
+
+Using C++ To Get Version and Interfaces State
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Below is a sample program to print all interfaces discovered.
+
+::
+
+ # test.cpp
+ #include <string>
+ #include <sstream>
+ #include <grpc/grpc.h>
+ #include <grpcpp/create_channel.h>
+ #include "frr-northbound.pb.h"
+ #include "frr-northbound.grpc.pb.h"
+
+ int main() {
+ frr::GetRequest request;
+ frr::GetResponse reply;
+ grpc::ClientContext context;
+ grpc::Status status;
+
+ auto channel = grpc::CreateChannel("localhost:50051",
+ grpc::InsecureChannelCredentials());
+ auto stub = frr::Northbound::NewStub(channel);
+
+ request.set_type(frr::GetRequest::ALL);
+ request.set_encoding(frr::JSON);
+ request.set_with_defaults(true);
+ request.add_path("/frr-interface:lib");
+ auto stream = stub->Get(&context, request);
+
+ std::ostringstream ss;
+ while (stream->Read(&reply))
+ ss << reply.data().data() << std::endl;
+
+ status = stream->Finish();
+ assert(status.ok());
+ std::cout << "Interface Info:\n" << ss.str() << std::endl;
+ }
+
+Below is how to compile and run the program, with the example output:
+
+::
+
+ $ g++ -o test test.cpp frr-northbound.grpc.pb.cc frr-northbound.pb.cc -lgrpc++ -lprotobuf
+ $ ./test
+ Interface Info:
+ {
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "lo",
+ "vrf": "default",
+ "state": {
+ "if-index": 1,
+ "mtu": 0,
+ "mtu6": 65536,
+ "speed": 0,
+ "metric": 0,
+ "phy-address": "00:00:00:00:00:00"
+ },
+ "frr-zebra:zebra": {
+ "state": {
+ "up-count": 0,
+ "down-count": 0,
+ "ptm-status": "disabled"
+ }
+ }
+ },
+ {
+ "name": "r1-eth0",
+ "vrf": "default",
+ "state": {
+ "if-index": 2,
+ "mtu": 1500,
+ "mtu6": 1500,
+ "speed": 10000,
+ "metric": 0,
+ "phy-address": "02:37:ac:63:59:b9"
+ },
+ "frr-zebra:zebra": {
+ "state": {
+ "up-count": 0,
+ "down-count": 0,
+ "ptm-status": "disabled"
+ }
+ }
+ }
+ ]
+ },
+ "frr-zebra:zebra": {
+ "mcast-rpf-lookup": "mrib-then-urib",
+ "workqueue-hold-timer": 10,
+ "zapi-packets": 1000,
+ "import-kernel-table": {
+ "distance": 15
+ },
+ "dplane-queue-limit": 200
+ }
+ }
+
+
+
+.. _grpc-python-example:
+
+Python Example
+--------------
+
+The next sections will use Python as an example for writing scripts to use
the northbound.
+.. _grpc-python-generate:
+
+Generating Python FRR Bindings
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Generating FRR northbound bindings for Python example:
+
+::
+
+ # Install python3 virtual environment capability e.g.,
+ sudo apt-get install python3-venv
+
+ # Create a virtual environment for python grpc and activate
+ python3 -m venv venv-grpc
+ source venv-grpc/bin/activate
+
+ # Install grpc requirements
+ pip install grpcio grpcio-tools
+
+ mkdir /tmp/frr-python
+ cd grpc
+
+ python3 -m grpc_tools.protoc \
+ --python_out=/tmp/frr-python \
+ --grpc_python_out=/tmp/frr-python \
+ -I $(pwd) \
+ frr-northbound.proto
+
+.. _grpc-python-if-sample:
+
+Using Python To Get Capabilities and Interfaces State
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Below is a sample script to print capabilities and all interfaces Python
+discovered. This demostrates the 2 different RPC results one gets from gRPC,
+Unary (`GetCapabilities`) and Streaming (`Get`) for the interface state.
+
+::
+
+ import grpc
+ import frr_northbound_pb2
+ import frr_northbound_pb2_grpc
+
+ channel = grpc.insecure_channel('localhost:50051')
+ stub = frr_northbound_pb2_grpc.NorthboundStub(channel)
+
+ # Print Capabilities
+ request = frr_northbound_pb2.GetCapabilitiesRequest()
+ response = stub.GetCapabilities(request)
+ print(response)
+
+ # Print Interface State and Config
+ request = frr_northbound_pb2.GetRequest()
+ request.path.append("/frr-interface:lib")
+ request.type=frr_northbound_pb2.GetRequest.ALL
+ request.encoding=frr_northbound_pb2.XML
+
+ for r in stub.Get(request):
+ print(r.data.data)
+
+The previous script will output something like:
+
+::
+
+ frr_version: "7.7-dev-my-manual-build"
+ rollback_support: true
+ supported_modules {
+ name: "frr-filter"
+ organization: "FRRouting"
+ revision: "2019-07-04"
+ }
+ supported_modules {
+ name: "frr-interface"
+ organization: "FRRouting"
+ revision: "2020-02-05"
+ }
+ [...]
+ supported_encodings: JSON
+ supported_encodings: XML
+
+ <lib xmlns="http://frrouting.org/yang/interface">
+ <interface>
+ <name>lo</name>
+ <vrf>default</vrf>
+ <state>
+ <if-index>1</if-index>
+ <mtu>0</mtu>
+ <mtu6>65536</mtu6>
+ <speed>0</speed>
+ <metric>0</metric>
+ <phy-address>00:00:00:00:00:00</phy-address>
+ </state>
+ <zebra xmlns="http://frrouting.org/yang/zebra">
+ <state>
+ <up-count>0</up-count>
+ <down-count>0</down-count>
+ </state>
+ </zebra>
+ </interface>
+ <interface>
+ <name>r1-eth0</name>
+ <vrf>default</vrf>
+ <state>
+ <if-index>2</if-index>
+ <mtu>1500</mtu>
+ <mtu6>1500</mtu6>
+ <speed>10000</speed>
+ <metric>0</metric>
+ <phy-address>f2:62:2e:f3:4c:e4</phy-address>
+ </state>
+ <zebra xmlns="http://frrouting.org/yang/zebra">
+ <state>
+ <up-count>0</up-count>
+ <down-count>0</down-count>
+ </state>
+ </zebra>
+ </interface>
+ </lib>
+
+.. _grpc-ruby-example:
+
+Ruby Example
+------------
+
+Next sections will use Ruby as an example for writing scripts to use
+the northbound.
.. _grpc-ruby-generate:
Generating Ruby FRR Bindings
-----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Generating FRR northbound bindings for Ruby example:
@@ -52,7 +326,7 @@ Generating FRR northbound bindings for Ruby example:
.. _grpc-ruby-if-sample:
Using Ruby To Get Interfaces State
-----------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Here is a sample script to print all interfaces FRR discovered:
@@ -141,7 +415,7 @@ The previous script will output something like this:
.. _grpc-ruby-bfd-profile-sample:
Using Ruby To Create BFD Profiles
----------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In this example you'll learn how to edit configuration using JSON
and programmatic (XPath) format.
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index f6aa5d1ca0..7f653cb7b7 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -2111,6 +2111,10 @@ things on the wire.
Large Community: lcommunity-1 65001:123:2
Last update: Fri Apr 16 12:51:27 2021
+.. clicmd:: show bgp [afi] [safi] [all] alias WORD [wide|json]
+
+ Display prefixes with matching BGP community alias.
+
.. _bgp-using-communities-in-route-map:
Using Communities in Route Maps
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index b321d99ad8..c8b25db8af 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -855,7 +855,7 @@ Traffic Engineering
flood in AREA <area-id> with Opaque Type-10, respectively in AS with Opaque
Type-11. In all case, Opaque-LSA TLV=6.
-.. clicmd:: no mpls-te export
+.. clicmd:: mpls-te export
Export Traffic Engineering Data Base to other daemons through the ZAPI
Opaque Link State messages.
diff --git a/doc/user/pathd.rst b/doc/user/pathd.rst
index 4c7611bc04..f27360cca7 100644
--- a/doc/user/pathd.rst
+++ b/doc/user/pathd.rst
@@ -104,11 +104,11 @@ Configuration Commands
Configure segment routing traffic engineering.
-.. clicmd:: [no] mpls-te <on|off>
+.. clicmd:: mpls-te <on|off>
Activate/Deactivate use of internal Traffic Engineering Database
-.. clicmd:: [no] mpls-te import <ospfv2|ospfv3|isis>
+.. clicmd:: mpls-te import <ospfv2|ospfv3|isis>
Load data from the selected igp
diff --git a/isisd/isisd.c b/isisd/isisd.c
index bda2295ae1..77b18f9cf7 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -1920,9 +1920,9 @@ DEFUN(no_debug_isis_ldp_sync, no_debug_isis_ldp_sync_cmd,
DEFUN (show_hostname,
show_hostname_cmd,
- "show " PROTO_NAME " hostname",
- SHOW_STR
- PROTO_HELP
+ "show " PROTO_NAME " [vrf <NAME|all>] hostname",
+ SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
+ "All VRFs\n"
"IS-IS Dynamic hostname mapping\n")
{
struct listnode *node;
diff --git a/lib/route_opaque.h b/lib/route_opaque.h
new file mode 100644
index 0000000000..599a0363eb
--- /dev/null
+++ b/lib/route_opaque.h
@@ -0,0 +1,38 @@
+/* Opaque data for Zebra from other daemons.
+ *
+ * Copyright (C) 2021 Donatas Abraitis <donatas.abraitis@gmail.com>
+ *
+ * This file is part of FRRouting (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 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_ROUTE_OPAQUE_H
+#define FRR_ROUTE_OPAQUE_H
+
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_lcommunity.h"
+
+struct bgp_zebra_opaque {
+ char aspath[ASPATH_STR_DEFAULT_LEN];
+
+ /* Show at least 10 communities AA:BB */
+ char community[COMMUNITY_SIZE * 20];
+
+ /* Show at least 10 large-communities AA:BB:CC */
+ char lcommunity[LCOMMUNITY_SIZE * 30];
+};
+
+#endif /* FRR_ROUTE_OPAQUE_H */
diff --git a/lib/subdir.am b/lib/subdir.am
index 480c2938d0..4015c67ea8 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -247,6 +247,7 @@ pkginclude_HEADERS += \
lib/queue.h \
lib/ringbuf.h \
lib/routemap.h \
+ lib/route_opaque.h \
lib/sbuf.h \
lib/seqlock.h \
lib/sha256.h \
diff --git a/lib/vrf.c b/lib/vrf.c
index b6a53839cf..d99ec12ba8 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -675,7 +675,7 @@ int vrf_handler_create(struct vty *vty, const char *vrfname,
if (strlen(vrfname) > VRF_NAMSIZ) {
if (vty)
vty_out(vty,
- "%% VRF name %s invalid: length exceeds %d bytes",
+ "%% VRF name %s invalid: length exceeds %d bytes\n",
vrfname, VRF_NAMSIZ);
else
flog_warn(
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 96dcdba68f..245e5dcd3d 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -1282,7 +1282,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
/* create new entry */
route = ospf6_route_create();
route->type = OSPF6_DEST_TYPE_NETWORK;
- memcpy(&route->prefix, prefix, sizeof(struct prefix));
+ prefix_copy(&route->prefix, prefix);
info = (struct ospf6_external_info *)XCALLOC(
MTYPE_OSPF6_EXTERNAL_INFO, sizeof(struct ospf6_external_info));
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 04b6bdd961..fb2d790532 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -8926,7 +8926,7 @@ DEFUN (ip_ospf_area,
argv_find(argv, argc, "area", &idx);
areaid = argv[idx + 1]->arg;
- if (ifp->vrf_id && !instance)
+ if (!instance)
ospf = ospf_lookup_by_vrf_id(ifp->vrf_id);
else
ospf = ospf_lookup_instance(instance);
@@ -9050,7 +9050,7 @@ DEFUN (no_ip_ospf_area,
if (argv_find(argv, argc, "(1-65535)", &idx))
instance = strtol(argv[idx]->arg, NULL, 10);
- if (ifp->vrf_id && !instance)
+ if (!instance)
ospf = ospf_lookup_by_vrf_id(ifp->vrf_id);
else
ospf = ospf_lookup_instance(instance);
diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c
index f2b909e268..73dcdbddb4 100644
--- a/pimd/pim_igmp.c
+++ b/pimd/pim_igmp.c
@@ -1028,8 +1028,8 @@ struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list,
sin.sin_addr = ifaddr;
sin.sin_port = 0;
if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
- zlog_warn("Could not bind IGMP socket for %pI4 on %s",
- &ifaddr, ifp->name);
+ zlog_warn("Could not bind IGMP socket for %pI4 on %s: %s(%d)",
+ &ifaddr, ifp->name, strerror(errno), errno);
close(fd);
return NULL;
diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c
index 0a4e3e1a6f..a3ca44bb50 100644
--- a/pimd/pim_oil.c
+++ b/pimd/pim_oil.c
@@ -426,9 +426,11 @@ static void pim_channel_update_mute(struct channel_oil *c_oil)
struct pim_interface *pim_reg_ifp;
struct pim_interface *vxlan_ifp;
- pim_reg_ifp = c_oil->pim->regiface->info;
- if (pim_reg_ifp)
- pim_channel_update_oif_mute(c_oil, pim_reg_ifp);
+ if (c_oil->pim->regiface) {
+ pim_reg_ifp = c_oil->pim->regiface->info;
+ if (pim_reg_ifp)
+ pim_channel_update_oif_mute(c_oil, pim_reg_ifp);
+ }
vxlan_ifp = pim_vxlan_get_term_ifp(c_oil->pim);
if (vxlan_ifp)
pim_channel_update_oif_mute(c_oil, vxlan_ifp);
diff --git a/tests/topotests/bgp_community_alias/r1/bgpd.conf b/tests/topotests/bgp_community_alias/r1/bgpd.conf
index 2cf84d0b70..06113bdd2a 100644
--- a/tests/topotests/bgp_community_alias/r1/bgpd.conf
+++ b/tests/topotests/bgp_community_alias/r1/bgpd.conf
@@ -1,7 +1,7 @@
!
-bgp community alias 65002:1 community-r2-1
+bgp community alias 65001:1 community-r2-1
bgp community alias 65002:2 community-r2-2
-bgp community alias 65002:1:1 large-community-r2-1
+bgp community alias 65001:1:1 large-community-r2-1
!
router bgp 65001
no bgp ebgp-requires-policy
diff --git a/tests/topotests/bgp_community_alias/r2/bgpd.conf b/tests/topotests/bgp_community_alias/r2/bgpd.conf
index 517ef70f2a..fc67ff2ad2 100644
--- a/tests/topotests/bgp_community_alias/r2/bgpd.conf
+++ b/tests/topotests/bgp_community_alias/r2/bgpd.conf
@@ -6,7 +6,14 @@ router bgp 65002
neighbor 192.168.1.1 route-map r1 out
exit-address-family
!
+ip prefix-list p1 permit 172.16.16.1/32
+ip prefix-list p2 permit 172.16.16.2/32
+!
route-map r1 permit 10
+ match ip address prefix-list p1
+ set community 65001:1 65001:2
+ set large-community 65001:1:1 65001:1:2
+route-map r1 permit 20
+ match ip address prefix-list p2
set community 65002:1 65002:2
- set large-community 65002:1:1 65002:2:1
!
diff --git a/tests/topotests/bgp_community_alias/r2/zebra.conf b/tests/topotests/bgp_community_alias/r2/zebra.conf
index cffe827363..a806628a8e 100644
--- a/tests/topotests/bgp_community_alias/r2/zebra.conf
+++ b/tests/topotests/bgp_community_alias/r2/zebra.conf
@@ -1,4 +1,8 @@
!
+int lo
+ ip address 172.16.16.1/32
+ ip address 172.16.16.2/32
+!
int r2-eth0
ip address 192.168.1.2/24
!
diff --git a/tests/topotests/bgp_community_alias/test_bgp-community-alias.py b/tests/topotests/bgp_community_alias/test_bgp-community-alias.py
index a43e5f937e..90eeaaa731 100644
--- a/tests/topotests/bgp_community_alias/test_bgp-community-alias.py
+++ b/tests/topotests/bgp_community_alias/test_bgp-community-alias.py
@@ -84,12 +84,14 @@ def test_bgp_community_alias():
router = tgen.gears["r1"]
def _bgp_converge(router):
- output = json.loads(router.vtysh_cmd("show ip bgp 192.168.1.0/24 json"))
+ output = json.loads(
+ router.vtysh_cmd("show bgp ipv4 unicast 172.16.16.1/32 json")
+ )
expected = {
"paths": [
{
- "community": {"string": "community-r2-1 community-r2-2"},
- "largeCommunity": {"string": "large-community-r2-1 65002:2:1"},
+ "community": {"string": "community-r2-1 65001:2"},
+ "largeCommunity": {"string": "large-community-r2-1 65001:1:2"},
}
]
}
@@ -97,9 +99,25 @@ def test_bgp_community_alias():
test_func = functools.partial(_bgp_converge, router)
success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
-
assert result is None, 'Cannot see BGP community aliases "{}"'.format(router)
+ def _bgp_show_prefixes_by_alias(router):
+ output = json.loads(
+ router.vtysh_cmd("show bgp ipv4 unicast alias community-r2-2 json detail")
+ )
+ expected = {
+ "routes": {
+ "172.16.16.2/32": [{"community": {"string": "65002:1 community-r2-2"}}]
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_show_prefixes_by_alias, router)
+ success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, 'Cannot see BGP prefixes by community alias "{}"'.format(
+ router
+ )
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
index 650ba20b8c..f7b9bad5fa 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
@@ -59,8 +59,8 @@ luCommand(
"VRF cust1 IP config",
)
luCommand(
- rtr,
- "ip route show vrf r4-cust2".format(rtr),
+ "r4",
+ "ip route show vrf r4-cust2",
"192.168...0/24 dev r.-eth",
"pass",
"VRF cust2 interface route",
diff --git a/tests/topotests/ospf_sr_topo1/rt1/ospfd.conf b/tests/topotests/ospf_sr_topo1/rt1/ospfd.conf
index 94dba7c061..6a12ae5011 100644
--- a/tests/topotests/ospf_sr_topo1/rt1/ospfd.conf
+++ b/tests/topotests/ospf_sr_topo1/rt1/ospfd.conf
@@ -12,6 +12,8 @@ interface lo
!
interface eth-sw1
ip ospf network broadcast
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
router ospf
ospf router-id 1.1.1.1
diff --git a/tests/topotests/ospf_sr_topo1/rt2/ospfd.conf b/tests/topotests/ospf_sr_topo1/rt2/ospfd.conf
index b47e788062..adf4d09235 100644
--- a/tests/topotests/ospf_sr_topo1/rt2/ospfd.conf
+++ b/tests/topotests/ospf_sr_topo1/rt2/ospfd.conf
@@ -12,12 +12,18 @@ interface lo
!
interface eth-sw1
ip ospf network broadcast
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
interface eth-rt4-1
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
interface eth-rt4-2
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
router ospf
ospf router-id 2.2.2.2
diff --git a/tests/topotests/ospf_sr_topo1/rt3/ospfd.conf b/tests/topotests/ospf_sr_topo1/rt3/ospfd.conf
index 238d82ff97..c45c1069fb 100644
--- a/tests/topotests/ospf_sr_topo1/rt3/ospfd.conf
+++ b/tests/topotests/ospf_sr_topo1/rt3/ospfd.conf
@@ -12,12 +12,18 @@ interface lo
!
interface eth-sw1
ip ospf network broadcast
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
interface eth-rt5-1
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
interface eth-rt5-2
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
router ospf
ospf router-id 3.3.3.3
diff --git a/tests/topotests/ospf_sr_topo1/rt4/ospfd.conf b/tests/topotests/ospf_sr_topo1/rt4/ospfd.conf
index b12e0729ad..9853ce64cf 100644
--- a/tests/topotests/ospf_sr_topo1/rt4/ospfd.conf
+++ b/tests/topotests/ospf_sr_topo1/rt4/ospfd.conf
@@ -12,15 +12,23 @@ interface lo
!
interface eth-rt2-1
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
interface eth-rt2-2
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
interface eth-rt5
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
interface eth-rt6
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
router ospf
ospf router-id 4.4.4.4
diff --git a/tests/topotests/ospf_sr_topo1/rt5/ospfd.conf b/tests/topotests/ospf_sr_topo1/rt5/ospfd.conf
index 4e7b24c03a..e6a755c430 100644
--- a/tests/topotests/ospf_sr_topo1/rt5/ospfd.conf
+++ b/tests/topotests/ospf_sr_topo1/rt5/ospfd.conf
@@ -12,15 +12,23 @@ interface lo
!
interface eth-rt3-1
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
interface eth-rt3-2
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
interface eth-rt4
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
interface eth-rt6
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
router ospf
ospf router-id 5.5.5.5
diff --git a/tests/topotests/ospf_sr_topo1/rt6/ospfd.conf b/tests/topotests/ospf_sr_topo1/rt6/ospfd.conf
index c6d07d169e..1ec71e4454 100644
--- a/tests/topotests/ospf_sr_topo1/rt6/ospfd.conf
+++ b/tests/topotests/ospf_sr_topo1/rt6/ospfd.conf
@@ -12,9 +12,13 @@ interface lo
!
interface eth-rt4
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
interface eth-rt5
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
router ospf
ospf router-id 6.6.6.6
diff --git a/tests/topotests/zebra_opaque/__init__.py b/tests/topotests/zebra_opaque/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/zebra_opaque/__init__.py
diff --git a/tests/topotests/zebra_opaque/r1/bgpd.conf b/tests/topotests/zebra_opaque/r1/bgpd.conf
new file mode 100644
index 0000000000..b0eac45bba
--- /dev/null
+++ b/tests/topotests/zebra_opaque/r1/bgpd.conf
@@ -0,0 +1,5 @@
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+!
diff --git a/tests/topotests/zebra_opaque/r1/zebra.conf b/tests/topotests/zebra_opaque/r1/zebra.conf
new file mode 100644
index 0000000000..b29940f46a
--- /dev/null
+++ b/tests/topotests/zebra_opaque/r1/zebra.conf
@@ -0,0 +1,4 @@
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
diff --git a/tests/topotests/zebra_opaque/r2/bgpd.conf b/tests/topotests/zebra_opaque/r2/bgpd.conf
new file mode 100644
index 0000000000..517ef70f2a
--- /dev/null
+++ b/tests/topotests/zebra_opaque/r2/bgpd.conf
@@ -0,0 +1,12 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ address-family ipv4 unicast
+ redistribute connected
+ neighbor 192.168.1.1 route-map r1 out
+ exit-address-family
+!
+route-map r1 permit 10
+ set community 65002:1 65002:2
+ set large-community 65002:1:1 65002:2:1
+!
diff --git a/tests/topotests/zebra_opaque/r2/zebra.conf b/tests/topotests/zebra_opaque/r2/zebra.conf
new file mode 100644
index 0000000000..cffe827363
--- /dev/null
+++ b/tests/topotests/zebra_opaque/r2/zebra.conf
@@ -0,0 +1,4 @@
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
diff --git a/tests/topotests/zebra_opaque/test_zebra_opaque.py b/tests/topotests/zebra_opaque/test_zebra_opaque.py
new file mode 100644
index 0000000000..cc52fbd1a7
--- /dev/null
+++ b/tests/topotests/zebra_opaque/test_zebra_opaque.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2021 by
+# Donatas Abraitis <donatas.abraitis@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 if Opaque Data is accessable from other daemons in Zebra
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+import functools
+
+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, *_args, **_opts):
+ tgen = get_topogen(self)
+
+ for routern in range(1, 3):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_zebra_opaque():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router = tgen.gears["r1"]
+
+ def _bgp_converge(router):
+ output = json.loads(router.vtysh_cmd("show ip route 192.168.1.0/24 json"))
+ expected = {
+ "192.168.1.0/24": [
+ {
+ "communities": "65002:1 65002:2",
+ "largeCommunities": "65002:1:1 65002:2:1",
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge, router)
+ success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+
+ assert result is None, 'Cannot see BGP community aliases "{}"'.format(router)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/yang/frr-bgp-neighbor.yang b/yang/frr-bgp-neighbor.yang
index d6688eed29..03af643ba2 100644
--- a/yang/frr-bgp-neighbor.yang
+++ b/yang/frr-bgp-neighbor.yang
@@ -90,8 +90,6 @@ submodule frr-bgp-neighbor {
"Don't send open messages to this neighbor.";
}
- uses structure-neighbor-group-capability-options;
-
uses neighbor-update-source;
uses structure-neighbor-group-ebgp-multihop;
diff --git a/yang/frr-bgp-peer-group.yang b/yang/frr-bgp-peer-group.yang
index 746ced30cc..80c9ecff2a 100644
--- a/yang/frr-bgp-peer-group.yang
+++ b/yang/frr-bgp-peer-group.yang
@@ -76,6 +76,8 @@ submodule frr-bgp-peer-group {
uses neighbor-remote-as;
uses neighbor-parameters;
+
+ uses structure-neighbor-group-capability-options;
}
grouping bgp-peer-group-list {
diff --git a/yang/frr-bgp.yang b/yang/frr-bgp.yang
index a779bb2054..0e15195dd5 100644
--- a/yang/frr-bgp.yang
+++ b/yang/frr-bgp.yang
@@ -11,10 +11,6 @@ module frr-bgp {
prefix inet;
}
- import ietf-routing-types {
- prefix rt-types;
- }
-
import frr-interface {
prefix frr-interface;
}
@@ -23,6 +19,10 @@ module frr-bgp {
prefix frr-bt;
}
+ import frr-route-types {
+ prefix frr-route-types;
+ }
+
include "frr-bgp-common";
include "frr-bgp-common-structure";
@@ -230,6 +230,8 @@ module frr-bgp {
}
uses neighbor-parameters;
+
+ uses structure-neighbor-group-capability-options;
}
list unnumbered-neighbor {
@@ -264,6 +266,12 @@ module frr-bgp {
uses neighbor-remote-as;
uses neighbor-parameters;
+
+ uses structure-neighbor-group-capability-options {
+ refine "frr-bgp:capability-options/extended-nexthop-capability" {
+ default "true";
+ }
+ }
}
}
@@ -405,7 +413,7 @@ module frr-bgp {
description
"A list of network routes.";
leaf prefix {
- type rt-types:ipv4-multicast-group-address;
+ type frr-route-types:ipv4-multicast-group-prefix;
description
"IPv4 multicast destination prefix.";
}
@@ -425,7 +433,7 @@ module frr-bgp {
description
"A list of aggregated routes.";
leaf prefix {
- type rt-types:ipv4-multicast-group-address;
+ type frr-route-types:ipv4-multicast-group-prefix;
description
"IPv4 multicast destination prefix.";
}
@@ -438,7 +446,7 @@ module frr-bgp {
description
"A list of routes with a particular admin distance.";
leaf prefix {
- type rt-types:ipv4-multicast-group-address;
+ type frr-route-types:ipv4-multicast-group-prefix;
description
"IPv4 multicast destination prefix.";
}
@@ -459,7 +467,7 @@ module frr-bgp {
description
"A list of network routes.";
leaf prefix {
- type rt-types:ipv6-multicast-group-address;
+ type frr-route-types:ipv6-multicast-group-prefix;
description
"IPv6 multicast destination prefix.";
}
@@ -479,7 +487,7 @@ module frr-bgp {
description
"A list of aggregated routes.";
leaf prefix {
- type rt-types:ipv6-multicast-group-address;
+ type frr-route-types:ipv6-multicast-group-prefix;
description
"IPv6 multicast destination prefix.";
}
@@ -492,7 +500,7 @@ module frr-bgp {
description
"A list of routes with a particular admin distance.";
leaf prefix {
- type rt-types:ipv6-multicast-group-address;
+ type frr-route-types:ipv6-multicast-group-prefix;
description
"IPv6 multicast destination prefix.";
}
diff --git a/yang/frr-pim-rp.yang b/yang/frr-pim-rp.yang
index a2eca5100a..33b453b299 100644
--- a/yang/frr-pim-rp.yang
+++ b/yang/frr-pim-rp.yang
@@ -8,10 +8,6 @@ module frr-pim-rp {
prefix "inet";
}
- import ietf-routing-types {
- prefix "rt-types";
- }
-
import frr-routing {
prefix "frr-rt";
}
@@ -20,6 +16,10 @@ module frr-pim-rp {
prefix "frr-pim";
}
+ import frr-route-types {
+ prefix frr-route-types;
+ }
+
organization
"FRRouting";
@@ -63,37 +63,6 @@ module frr-pim-rp {
"RFC XXXX: A YANG Data Model for PIM RP";
}
- typedef ipv4-multicast-group-address-prefix {
- type inet:ipv4-prefix{
- pattern '(2((2[4-9])|(3[0-9]))\.)(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){2}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(/(([4-9])|([1-2][0-9])|(3[0-2])))';
- }
- description
- "This type represents an IPv4 multicast group prefix,
- which is in the range from 224.0.0.0 to 239.255.255.255.";
- }
-
- typedef ipv6-multicast-group-address-prefix {
- type inet:ipv6-prefix {
- pattern
- '(((FF|ff)[0-9a-fA-F]{2}):)([0-9a-fA-F]{0,4}:){0,5}((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))(/((1[6-9])|([2-9][0-9])|(1[0-1][0-9])|(12[0-8])))';
- pattern
- '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)(/.+)';
- }
- description
- "This type represents an IPv6 multicast group prefix,
- which is in the range of FF00::/8.";
- }
-
- typedef ip-multicast-group-address-prefix {
- description "The IP-Multicast-Group-Address-Prefix type represents an IP multicast address
- prefix and is IP version neutral. The format of the textual representations implies the IP
- version. It includes a prefix-length, separated by a '/' sign.";
- type union {
- type ipv4-multicast-group-address-prefix;
- type ipv6-multicast-group-address-prefix;
- }
- } // typedef ip-multicast-group-address-prefix
-
typedef plist-ref {
type string;
}
@@ -124,7 +93,7 @@ module frr-pim-rp {
description "Use group-list or prefix-list";
case group-list {
leaf-list group-list{
- type ip-multicast-group-address-prefix;
+ type frr-route-types:ip-multicast-group-prefix;
description
"List of multicast group address.";
}
diff --git a/yang/frr-route-types.yang b/yang/frr-route-types.yang
index 5a0f58071f..aeb52a6520 100644
--- a/yang/frr-route-types.yang
+++ b/yang/frr-route-types.yang
@@ -3,6 +3,10 @@ module frr-route-types {
namespace "http://frrouting.org/yang/route-types";
prefix frr-route-types;
+ import ietf-inet-types {
+ prefix inet;
+ }
+
organization
"FRRouting";
contact
@@ -145,4 +149,35 @@ module frr-route-types {
type frr-route-types-v6;
}
}
+
+ typedef ipv4-multicast-group-prefix {
+ type inet:ipv4-prefix {
+ pattern '(2((2[4-9])|(3[0-9]))\.)(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){2}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(/(([4-9])|([1-2][0-9])|(3[0-2])))';
+ }
+ description
+ "This type represents an IPv4 multicast group prefix,
+ which is in the range from 224.0.0.0 to 239.255.255.255.";
+ }
+
+ typedef ipv6-multicast-group-prefix {
+ type inet:ipv6-prefix {
+ pattern
+ '(((FF|ff)[0-9a-fA-F]{2}):)([0-9a-fA-F]{0,4}:){0,5}((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))(/((1[6-9])|([2-9][0-9])|(1[0-1][0-9])|(12[0-8])))';
+ pattern
+ '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)(/.+)';
+ }
+ description
+ "This type represents an IPv6 multicast group prefix,
+ which is in the range of FF00::/8.";
+ }
+
+ typedef ip-multicast-group-prefix {
+ description "The IP-Multicast-Group-Address-Prefix type represents an IP multicast address
+ prefix and is IP version neutral. The format of the textual representations implies the IP
+ version. It includes a prefix-length, separated by a '/' sign.";
+ type union {
+ type ipv4-multicast-group-prefix;
+ type ipv6-multicast-group-prefix;
+ }
+ }
}
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 8061f34d2b..861600596e 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -42,6 +42,7 @@
#include "zebra/redistribute.h"
#include "zebra/zebra_routemap.h"
#include "lib/json.h"
+#include "lib/route_opaque.h"
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_evpn_mh.h"
#ifndef VTYSH_EXTRACT_PL
@@ -421,6 +422,8 @@ static void show_nexthop_detail_helper(struct vty *vty,
static void zebra_show_ip_route_opaque(struct vty *vty, struct route_entry *re,
struct json_object *json)
{
+ struct bgp_zebra_opaque bzo = {};
+
if (!re->opaque)
return;
@@ -433,13 +436,27 @@ static void zebra_show_ip_route_opaque(struct vty *vty, struct route_entry *re,
vty_out(vty, " Opaque Data: %s",
(char *)re->opaque->data);
break;
- case ZEBRA_ROUTE_BGP:
- if (json)
- json_object_string_add(json, "asPath",
- (char *)re->opaque->data);
- else
- vty_out(vty, " AS-Path: %s",
- (char *)re->opaque->data);
+ case ZEBRA_ROUTE_BGP: {
+ memcpy(&bzo, re->opaque->data, re->opaque->length);
+
+ if (json) {
+ json_object_string_add(json, "asPath", bzo.aspath);
+ json_object_string_add(json, "communities",
+ bzo.community);
+ json_object_string_add(json, "largeCommunities",
+ bzo.lcommunity);
+ } else {
+ vty_out(vty, " AS-Path : %s\n", bzo.aspath);
+
+ if (bzo.community[0] != '\0')
+ vty_out(vty, " Communities : %s\n",
+ bzo.community);
+
+ if (bzo.lcommunity[0] != '\0')
+ vty_out(vty, " Large-Communities: %s\n",
+ bzo.lcommunity);
+ }
+ }
default:
break;
}
@@ -2530,8 +2547,8 @@ DEFPY (evpn_mh_neigh_holdtime,
"Duration in seconds\n")
{
- return zebra_evpn_mh_neigh_holdtime_update(vty, duration,
- no ? true : false);
+ return zebra_evpn_mh_neigh_holdtime_update(vty, duration,
+ no ? true : false);
}
DEFPY (evpn_mh_startup_delay,