int write = 0;
for (ALL_LIST_ELEMENTS_RO (vrf_iflist(VRF_DEFAULT), node, ifp)) {
- vty_out (vty, "interface %s\n",ifp->name);
+ vty_frame (vty, "interface %s\n",ifp->name);
if (ifp->desc)
vty_out (vty, " description %s\n",ifp->desc);
babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp);
write++;
}
}
- vty_out (vty, "!\n");
+ vty_endframe (vty, "!\n");
write++;
}
return write;
api.prefix = quagga_prefix;
if(metric >= KERNEL_INFINITY) {
- api.flags = ZEBRA_FLAG_REJECT;
+ zapi_route_set_blackhole(&api, BLACKHOLE_REJECT);
} else {
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 1;
#include "bgpd/bgp_encap_types.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_zebra.h"
+#include "bgpd/bgp_nexthop.h"
/*
* Definitions and external declarations.
return 0;
}
+ /* Update the tunnel-ip hash */
+ bgp_tip_del(bgp, &vpn->originator_ip);
+ bgp_tip_add(bgp, &originator_ip);
+
+ /* filter routes as martian nexthop db has changed */
+ bgp_filter_evpn_routes_upon_martian_nh_change(bgp);
+
/* Need to withdraw type-3 route as the originator IP is part
* of the key.
*/
/* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */
stream_putc(s, 8 + 10 + 4 + 1 + len + 3);
stream_put(s, prd->val, 8);
- if (attr && attr)
+ if (attr)
stream_put(s, &(attr->evpn_overlay.eth_s_id), 10);
else
stream_put(s, &temp, 10);
stream_put_ipv4(s, p_evpn_p->ip.ipaddr_v4.s_addr);
else
stream_put(s, &p_evpn_p->ip.ipaddr_v6, 16);
- if (attr && attr) {
+ if (attr) {
if (IS_IPADDR_V4(&p_evpn_p->ip))
stream_put_ipv4(s,
attr->evpn_overlay.gw_ip.ipv4.s_addr);
return buf;
}
+/*
+ * Function to convert evpn route to json format.
+ * NOTE: We don't use prefix2str as the output here is a bit different.
+ */
+void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json)
+{
+ char buf1[ETHER_ADDR_STRLEN];
+ char buf2[PREFIX2STR_BUFFER];
+
+ if (!json)
+ return;
+
+ if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) {
+ json_object_int_add(json, "routeType", p->prefix.route_type);
+ json_object_int_add(json, "ethTag", 0);
+ json_object_int_add(json, "ipLen",
+ IS_EVPN_PREFIX_IPADDR_V4(p)
+ ? IPV4_MAX_BITLEN
+ : IPV6_MAX_BITLEN);
+ json_object_string_add(json, "ip",
+ inet_ntoa(p->prefix.ip.ipaddr_v4));
+ } else if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ if (IS_EVPN_PREFIX_IPADDR_NONE(p)) {
+ json_object_int_add(json, "routeType",
+ p->prefix.route_type);
+ json_object_int_add(
+ json, "esi",
+ 0); /* TODO: we don't support esi yet */
+ json_object_int_add(json, "ethTag", 0);
+ json_object_int_add(json, "macLen", 8 * ETH_ALEN);
+ json_object_string_add(json, "mac",
+ prefix_mac2str(&p->prefix.mac,
+ buf1,
+ sizeof(buf1)));
+ } else {
+ u_char family;
+
+ family = IS_EVPN_PREFIX_IPADDR_V4(p) ? AF_INET
+ : AF_INET6;
+
+ json_object_int_add(json, "routeType",
+ p->prefix.route_type);
+ json_object_int_add(
+ json, "esi",
+ 0); /* TODO: we don't support esi yet */
+ json_object_int_add(json, "ethTag", 0);
+ json_object_int_add(json, "macLen", 8 * ETH_ALEN);
+ json_object_string_add(json, "mac",
+ prefix_mac2str(&p->prefix.mac,
+ buf1,
+ sizeof(buf1)));
+ json_object_int_add(json, "ipLen",
+ IS_EVPN_PREFIX_IPADDR_V4(p)
+ ? IPV4_MAX_BITLEN
+ : IPV6_MAX_BITLEN);
+ json_object_string_add(
+ json, "ip",
+ inet_ntop(family, &p->prefix.ip.ip.addr, buf2,
+ PREFIX2STR_BUFFER));
+ }
+ } else {
+ /* Currently, this is to cater to other AF_ETHERNET code. */
+ }
+}
+
/*
* Function to convert evpn route to string.
* NOTE: We don't use prefix2str as the output here is a bit different.
return install_uninstall_evpn_route(bgp, afi, safi, p, ri, 0);
}
+/* filter routes which have martian next hops */
+int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp)
+{
+ afi_t afi;
+ safi_t safi;
+ struct bgp_node *rd_rn, *rn;
+ struct bgp_table *table;
+ struct bgp_info *ri;
+
+ afi = AFI_L2VPN;
+ safi = SAFI_EVPN;
+
+ /* Walk entire global routing table and evaluate routes which could be
+ * imported into this VPN. Note that we cannot just look at the routes
+ * for the VNI's RD -
+ * remote routes applicable for this VNI could have any RD.
+ */
+ /* EVPN routes are a 2-level table. */
+ for (rd_rn = bgp_table_top(bgp->rib[afi][safi]); rd_rn;
+ rd_rn = bgp_route_next(rd_rn)) {
+ table = (struct bgp_table *)(rd_rn->info);
+ if (!table)
+ continue;
+
+ for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+
+ for (ri = rn->info; ri; ri = ri->next) {
+
+ /* Consider "valid" remote routes applicable for
+ * this VNI. */
+ if (!(ri->type == ZEBRA_ROUTE_BGP
+ && ri->sub_type == BGP_ROUTE_NORMAL))
+ continue;
+
+ if (bgp_nexthop_self(bgp, ri->attr->nexthop)) {
+
+ char attr_str[BUFSIZ];
+ char pbuf[PREFIX_STRLEN];
+
+ bgp_dump_attr(ri->attr, attr_str,
+ BUFSIZ);
+
+ if (bgp_debug_update(ri->peer, &rn->p,
+ NULL, 1))
+ zlog_debug(
+ "%u: prefix %s with attr %s - DENIED due to martian or self nexthop",
+ bgp->vrf_id,
+ prefix2str(
+ &rn->p, pbuf,
+ sizeof(pbuf)),
+ attr_str);
+
+ bgp_evpn_unimport_route(bgp, afi, safi,
+ &rn->p, ri);
+
+ bgp_rib_remove(rn, ri, ri->peer, afi,
+ safi);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
/*
* Handle del of a local MACIP.
*/
*/
delete_routes_for_vni(bgp, vpn);
+ /*
+ * tunnel is no longer active, del tunnel ip address from tip_hash
+ */
+ bgp_tip_del(bgp, &vpn->originator_ip);
+
/* Clear "live" flag and see if hash needs to be freed. */
UNSET_FLAG(vpn->flags, VNI_FLAG_LIVE);
if (!is_vni_configured(vpn))
}
}
- /* if the VNI is live already, there is nothibng more to do */
+ /* if the VNI is live already, there is nothing more to do */
if (is_vni_live(vpn))
return 0;
/* Mark as "live" */
SET_FLAG(vpn->flags, VNI_FLAG_LIVE);
+ /* tunnel is now active, add tunnel-ip to db */
+ bgp_tip_add(bgp, &originator_ip);
+
+ /* filter routes as nexthop database has changed */
+ bgp_filter_evpn_routes_upon_martian_nh_change(bgp);
+
/* Create EVPN type-3 route and schedule for processing. */
build_evpn_type3_prefix(&p, vpn->originator_ip);
if (update_evpn_route(bgp, vpn, &p, 0)) {
*/
install_routes_for_vni(bgp, vpn);
+ /* If we are advertising gateway mac-ip
+ It needs to be conveyed again to zebra */
+ bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip, vpn->vni);
+
return 0;
}
extern void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw);
extern char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len);
extern char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len);
+extern void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json);
extern void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
struct prefix_rd *prd, mpls_label_t *label,
struct attr *attr, int addpath_encode,
struct prefix *p, struct bgp_info *ri);
extern int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi,
struct prefix *p, struct bgp_info *ri);
+extern int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp);
extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni,
struct ethaddr *mac, struct ipaddr *ip);
extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni,
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
+#define RT_ADDRSTRLEN 28
+
/* EVPN prefix lengths. */
#define EVPN_TYPE_2_ROUTE_PREFIXLEN 224
#define EVPN_TYPE_3_ROUTE_PREFIXLEN 224
#define SHOW_DISPLAY_STANDARD 0
#define SHOW_DISPLAY_TAGS 1
#define SHOW_DISPLAY_OVERLAY 2
+#define VNI_STR_LEN 32
/*
* Context for VNI hash walk - used by callbacks.
struct bgp *bgp;
struct vty *vty;
struct in_addr vtep_ip;
-};
-
-struct evpn_config_write {
- int write;
- struct vty *vty;
+ json_object *json;
};
#if defined(HAVE_CUMULUS)
-static void display_import_rt(struct vty *vty, struct irt_node *irt)
+static void display_import_rt(struct vty *vty, struct irt_node *irt,
+ json_object *json)
{
u_char *pnt;
u_char type, sub_type;
} eip;
struct listnode *node, *nnode;
struct bgpevpn *tmp_vpn;
+ json_object *json_rt = NULL;
+ json_object *json_vnis = NULL;
+ char rt_buf[RT_ADDRSTRLEN];
+ if (json) {
+ json_rt = json_object_new_object();
+ json_vnis = json_object_new_array();
+ }
/* TODO: This needs to go into a function */
eas.val |= (*pnt++ << 8);
eas.val |= (*pnt++);
- vty_out(vty, "Route-target: %u:%u", eas.as, eas.val);
+ snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val);
+
+ if (json)
+ json_object_string_add(json_rt, "rt", rt_buf);
+ else
+ vty_out(vty, "Route-target: %s", rt_buf);
+
break;
case ECOMMUNITY_ENCODE_IP:
eip.val = (*pnt++ << 8);
eip.val |= (*pnt++);
- vty_out(vty, "Route-target: %s:%u", inet_ntoa(eip.ip), eip.val);
+ snprintf(rt_buf, RT_ADDRSTRLEN, "%s:%u", inet_ntoa(eip.ip),
+ eip.val);
+
+ if (json)
+ json_object_string_add(json_rt, "rt", rt_buf);
+ else
+ vty_out(vty, "Route-target: %s", rt_buf);
+
break;
case ECOMMUNITY_ENCODE_AS4:
eas.val = (*pnt++ << 8);
eas.val |= (*pnt++);
- vty_out(vty, "Route-target: %u:%u", eas.as, eas.val);
+ snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val);
+
+ if (json)
+ json_object_string_add(json_rt, "rt", rt_buf);
+ else
+ vty_out(vty, "Route-target: %s", rt_buf);
+
break;
default:
return;
}
- vty_out(vty, "\n");
- vty_out(vty, "List of VNIs importing routes with this route-target:\n");
+ if (!json) {
+ vty_out(vty,
+ "\nList of VNIs importing routes with this route-target:\n");
+ }
+
+ for (ALL_LIST_ELEMENTS(irt->vnis, node, nnode, tmp_vpn)) {
+ if (json)
+ json_object_array_add(
+ json_vnis, json_object_new_int64(tmp_vpn->vni));
+ else
+ vty_out(vty, " %u\n", tmp_vpn->vni);
+ }
- for (ALL_LIST_ELEMENTS(irt->vnis, node, nnode, tmp_vpn))
- vty_out(vty, " %u\n", tmp_vpn->vni);
+ if (json) {
+ json_object_object_add(json_rt, "vnis", json_vnis);
+ json_object_object_add(json, rt_buf, json_rt);
+ }
}
-static void show_import_rt_entry(struct hash_backet *backet, struct vty *vty)
+static void show_import_rt_entry(struct hash_backet *backet, void *args[])
{
+ json_object *json = NULL;
+ struct vty *vty = NULL;
struct irt_node *irt = (struct irt_node *)backet->data;
- display_import_rt(vty, irt);
+
+ vty = args[0];
+ json = args[1];
+
+ display_import_rt(vty, irt, json);
+
+ return;
}
static void bgp_evpn_show_route_rd_header(struct vty *vty,
- struct bgp_node *rd_rn)
+ struct bgp_node *rd_rn,
+ json_object *json)
{
u_int16_t type;
struct rd_as rd_as;
struct rd_ip rd_ip;
u_char *pnt;
+ char rd_str[RD_ADDRSTRLEN];
pnt = rd_rn->p.u.val;
/* Decode RD type. */
type = decode_rd_type(pnt);
+ if (json)
+ return;
+
vty_out(vty, "Route Distinguisher: ");
switch (type) {
case RD_TYPE_AS:
decode_rd_as(pnt + 2, &rd_as);
- vty_out(vty, "%u:%d", rd_as.as, rd_as.val);
+ snprintf(rd_str, RD_ADDRSTRLEN, "%u:%d", rd_as.as, rd_as.val);
break;
case RD_TYPE_IP:
decode_rd_ip(pnt + 2, &rd_ip);
- vty_out(vty, "%s:%d", inet_ntoa(rd_ip.ip), rd_ip.val);
+ snprintf(rd_str, RD_ADDRSTRLEN, "%s:%d", inet_ntoa(rd_ip.ip),
+ rd_ip.val);
break;
default:
- vty_out(vty, "Unknown RD type");
+ snprintf(rd_str, RD_ADDRSTRLEN, "Unknown RD type");
break;
}
- vty_out(vty, "\n");
+ vty_out(vty, "%s\n", rd_str);
}
-static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp)
+static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
+ json_object *json)
{
char ri_header[] =
" Network Next Hop Metric LocPrf Weight Path\n";
+ if (json)
+ return;
+
+
vty_out(vty, "BGP table version is 0, local router ID is %s\n",
inet_ntoa(bgp->router_id));
vty_out(vty,
vty_out(vty, "%s", ri_header);
}
-static void display_vni(struct vty *vty, struct bgpevpn *vpn)
+static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
{
char buf1[INET6_ADDRSTRLEN];
char *ecom_str;
struct listnode *node, *nnode;
struct ecommunity *ecom;
+ json_object *json_import_rtl;
+ json_object *json_export_rtl;
+
+ if (json) {
+ json_import_rtl = json_object_new_array();
+ json_export_rtl = json_object_new_array();
+ json_object_int_add(json, "vni", vpn->vni);
+ json_object_string_add(json, "kernelFlag",
+ is_vni_live(vpn) ? "Yes" : "No");
+ json_object_string_add(
+ json, "rd",
+ prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN));
+ json_object_string_add(json, "originatorIp",
+ inet_ntoa(vpn->originator_ip));
+ json_object_string_add(json, "advertiseGatewayMacip",
+ vpn->advertise_gw_macip ? "Yes" : "No");
+ } else {
+ vty_out(vty, "VNI: %d", vpn->vni);
+ if (is_vni_live(vpn))
+ vty_out(vty, " (known to the kernel)");
+ vty_out(vty, "\n");
- vty_out(vty, "VNI: %d", vpn->vni);
- if (is_vni_live(vpn))
- vty_out(vty, " (known to the kernel)");
- vty_out(vty, "\n");
+ vty_out(vty, " RD: %s\n",
+ prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN));
+ vty_out(vty, " Originator IP: %s\n",
+ inet_ntoa(vpn->originator_ip));
+ vty_out(vty, " Advertise-gw-macip : %s\n",
+ vpn->advertise_gw_macip ? "Yes" : "No");
+ }
- vty_out(vty, " RD: %s\n",
- prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN));
- vty_out(vty, " Originator IP: %s\n", inet_ntoa(vpn->originator_ip));
- vty_out(vty, " Advertise-gw-macip : %s\n",
- vpn->advertise_gw_macip ? "Yes" : "No");
+ if (!json)
+ vty_out(vty, " Import Route Target:\n");
- vty_out(vty, " Import Route Target:\n");
for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
ecom_str = ecommunity_ecom2str(ecom,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- vty_out(vty, " %s\n", ecom_str);
+
+ if (json)
+ json_object_array_add(json_import_rtl,
+ json_object_new_string(ecom_str));
+ else
+ vty_out(vty, " %s\n", ecom_str);
+
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
}
- vty_out(vty, " Export Route Target:\n");
+ if (json)
+ json_object_object_add(json, "importRts", json_import_rtl);
+ else
+ vty_out(vty, " Export Route Target:\n");
+
for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) {
ecom_str = ecommunity_ecom2str(ecom,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- vty_out(vty, " %s\n", ecom_str);
+
+ if (json)
+ json_object_array_add(json_export_rtl,
+ json_object_new_string(ecom_str));
+ else
+ vty_out(vty, " %s\n", ecom_str);
+
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
}
+
+ if (json)
+ json_object_object_add(json, "exportRts", json_export_rtl);
}
static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
- struct vty *vty, struct in_addr vtep_ip)
+ struct vty *vty, struct in_addr vtep_ip,
+ json_object *json)
{
struct bgp_node *rn;
struct bgp_info *ri;
for (rn = bgp_table_top(vpn->route_table); rn;
rn = bgp_route_next(rn)) {
struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
+ int add_prefix_to_json = 0;
+ char prefix_str[BUFSIZ];
+ json_object *json_paths = NULL;
+ json_object *json_prefix = NULL;
+
+ bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str,
+ sizeof(prefix_str));
if (type && evp->prefix.route_type != type)
continue;
+ if (json)
+ json_prefix = json_object_new_object();
+
if (rn->info) {
/* Overall header/legend displayed once. */
if (header) {
- bgp_evpn_show_route_header(vty, bgp);
+ bgp_evpn_show_route_header(vty, bgp, json);
header = 0;
}
prefix_cnt++;
}
+ if (json)
+ json_paths = json_object_new_array();
+
/* For EVPN, the prefix is displayed for each path (to fit in
* with code that already exists).
*/
for (ri = rn->info; ri; ri = ri->next) {
+ json_object *json_path = NULL;
+
if (vtep_ip.s_addr
&& !IPV4_ADDR_SAME(&(vtep_ip),
&(ri->attr->nexthop)))
continue;
+ if (json)
+ json_path = json_object_new_array();
+
+ route_vty_out(vty, &rn->p, ri, 0, SAFI_EVPN, json_path);
+
+ if (json)
+ json_object_array_add(json_paths, json_path);
+
path_cnt++;
- route_vty_out(vty, &rn->p, ri, 0, SAFI_EVPN, NULL);
+ add_prefix_to_json = 1;
+ }
+
+ if (json && add_prefix_to_json) {
+ json_object_string_add(json_prefix, "prefix",
+ prefix_str);
+ json_object_int_add(json_prefix, "prefixLen",
+ rn->p.prefixlen);
+ json_object_object_add(json_prefix, "paths",
+ json_paths);
+ json_object_object_add(json, prefix_str, json_prefix);
}
}
- if (prefix_cnt == 0)
- vty_out(vty, "No EVPN prefixes %sexist for this VNI\n",
- type ? "(of requested type) " : "");
- else
- vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s\n",
- prefix_cnt, path_cnt,
- type ? " (of requested type)" : "");
+ if (json) {
+ json_object_int_add(json, "numPrefix", prefix_cnt);
+ json_object_int_add(json, "numPaths", path_cnt);
+ } else {
+ if (prefix_cnt == 0)
+ vty_out(vty, "No EVPN prefixes %sexist for this VNI",
+ type ? "(of requested type) " : "");
+ else
+ vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s",
+ prefix_cnt, path_cnt,
+ type ? " (of requested type)" : "");
+ }
}
static void show_vni_routes_hash(struct hash_backet *backet, void *arg)
struct bgpevpn *vpn = (struct bgpevpn *)backet->data;
struct vni_walk_ctx *wctx = arg;
struct vty *vty = wctx->vty;
+ json_object *json = wctx->json;
+ json_object *json_vni = NULL;
+ char vni_str[VNI_STR_LEN];
+
+ snprintf(vni_str, VNI_STR_LEN, "%d", vpn->vni);
+ if (json) {
+ json_vni = json_object_new_object();
+ json_object_int_add(json_vni, "vni", vpn->vni);
+ } else {
+ vty_out(vty, "\nVNI: %d\n\n", vpn->vni);
+ }
- vty_out(vty, "\nVNI: %d\n\n", vpn->vni);
- show_vni_routes(wctx->bgp, vpn, 0, wctx->vty, wctx->vtep_ip);
+ show_vni_routes(wctx->bgp, vpn, 0, wctx->vty, wctx->vtep_ip, json_vni);
+
+ if (json)
+ json_object_object_add(json, vni_str, json_vni);
}
-static void show_vni_entry(struct hash_backet *backet, struct vty *vty)
+static void show_vni_entry(struct hash_backet *backet, void *args[])
{
+ struct vty *vty;
+ json_object *json;
+ json_object *json_vni;
+ json_object *json_import_rtl;
+ json_object *json_export_rtl;
struct bgpevpn *vpn = (struct bgpevpn *)backet->data;
char buf1[10];
char buf2[INET6_ADDRSTRLEN];
struct listnode *node, *nnode;
struct ecommunity *ecom;
+ vty = args[0];
+ json = args[1];
+
+ if (json) {
+ json_vni = json_object_new_object();
+ json_import_rtl = json_object_new_array();
+ json_export_rtl = json_object_new_array();
+ }
+
buf1[0] = '\0';
if (is_vni_live(vpn))
sprintf(buf1, "*");
- vty_out(vty, "%-1s %-10u %-15s %-21s", buf1, vpn->vni,
- inet_ntoa(vpn->originator_ip),
- prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN));
+ if (json) {
+ json_object_int_add(json_vni, "vni", vpn->vni);
+ json_object_string_add(json_vni, "inKernel",
+ is_vni_live(vpn) ? "True" : "False");
+ json_object_string_add(json_vni, "originatorIp",
+ inet_ntoa(vpn->originator_ip));
+ json_object_string_add(
+ json_vni, "rd",
+ prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN));
+ } else {
+ vty_out(vty, "%-1s %-10u %-15s %-21s", buf1, vpn->vni,
+ inet_ntoa(vpn->originator_ip),
+ prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN));
+ }
for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
ecom_str = ecommunity_ecom2str(ecom,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- if (listcount(vpn->import_rtl) > 1)
- sprintf(rt_buf, "%s, ...", ecom_str);
- else
- sprintf(rt_buf, "%s", ecom_str);
- vty_out(vty, " %-25s", rt_buf);
+ if (json) {
+ json_object_array_add(json_import_rtl,
+ json_object_new_string(ecom_str));
+ } else {
+ if (listcount(vpn->import_rtl) > 1)
+ sprintf(rt_buf, "%s, ...", ecom_str);
+ else
+ sprintf(rt_buf, "%s", ecom_str);
+ vty_out(vty, " %-25s", rt_buf);
+ }
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
- break;
+
+ /* If there are multiple import RTs we break here and show only
+ * one */
+ if (!json)
+ break;
}
+ if (json)
+ json_object_object_add(json_vni, "importRTs", json_import_rtl);
+
for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) {
ecom_str = ecommunity_ecom2str(ecom,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- if (listcount(vpn->export_rtl) > 1)
- sprintf(rt_buf, "%s, ...", ecom_str);
- else
- sprintf(rt_buf, "%s", ecom_str);
- vty_out(vty, " %-25s", rt_buf);
+ if (json) {
+ json_object_array_add(json_export_rtl,
+ json_object_new_string(ecom_str));
+ } else {
+ if (listcount(vpn->export_rtl) > 1)
+ sprintf(rt_buf, "%s, ...", ecom_str);
+ else
+ sprintf(rt_buf, "%s", ecom_str);
+ vty_out(vty, " %-25s", rt_buf);
+ }
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
- break;
+
+ /* If there are multiple export RTs we break here and show only
+ * one */
+ if (!json)
+ break;
+ }
+
+ if (json) {
+ char vni_str[VNI_STR_LEN];
+
+ json_object_object_add(json_vni, "exportRTs", json_export_rtl);
+ snprintf(vni_str, VNI_STR_LEN, "%u", vpn->vni);
+ json_object_object_add(json, vni_str, json_vni);
+ } else {
+ vty_out(vty, "\n");
}
- vty_out(vty, "\n");
}
#endif /* HAVE_CUMULUS */
if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
continue;
- if ((table = rn->info) != NULL) {
- rd_header = 1;
-
- for (rm = bgp_table_top(table); rm;
- rm = bgp_route_next(rm))
- for (ri = rm->info; ri; ri = ri->next) {
- total_count++;
- if (type == bgp_show_type_neighbor) {
- union sockunion *su =
- output_arg;
-
- if (ri->peer->su_remote == NULL
- || !sockunion_same(
- ri->peer->su_remote,
- su))
- continue;
- }
- if (header == 0) {
- if (use_json) {
- if (option
- == SHOW_DISPLAY_TAGS) {
- json_object_int_add(
- json,
- "bgpTableVersion",
- 0);
- json_object_string_add(
- json,
- "bgpLocalRouterId",
- inet_ntoa(
- bgp->router_id));
- json_object_object_add(
- json,
- "bgpStatusCodes",
- json_scode);
- json_object_object_add(
- json,
- "bgpOriginCodes",
- json_ocode);
- }
- } else {
- if (option
- == SHOW_DISPLAY_TAGS)
- vty_out(vty,
- V4_HEADER_TAG);
- else if (
- option
- == SHOW_DISPLAY_OVERLAY)
- vty_out(vty,
- V4_HEADER_OVERLAY);
- else {
- vty_out(vty,
- "BGP table version is 0, local router ID is %s\n",
- inet_ntoa(
- bgp->router_id));
- vty_out(vty,
- "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal\n");
- vty_out(vty,
- "Origin codes: i - IGP, e - EGP, ? - incomplete\n\n");
- vty_out(vty,
- V4_HEADER);
- }
- }
- header = 0;
- }
- if (rd_header) {
- u_int16_t type;
- struct rd_as rd_as;
- struct rd_ip rd_ip;
- u_char *pnt;
+ if ((table = rn->info) == NULL)
+ continue;
- pnt = rn->p.u.val;
+ rd_header = 1;
- /* Decode RD type. */
- type = decode_rd_type(pnt);
- /* Decode RD value. */
- if (type == RD_TYPE_AS)
- decode_rd_as(pnt + 2,
- &rd_as);
- else if (type == RD_TYPE_AS4)
- decode_rd_as4(pnt + 2,
- &rd_as);
- else if (type == RD_TYPE_IP)
- decode_rd_ip(pnt + 2,
- &rd_ip);
- if (use_json) {
- char buffer[BUFSIZ];
- if (type == RD_TYPE_AS
- || type == RD_TYPE_AS4)
- sprintf(buffer,
- "%u:%d",
- rd_as.as,
- rd_as.val);
- else if (type
- == RD_TYPE_IP)
- sprintf(buffer,
- "%s:%d",
- inet_ntoa(
- rd_ip.ip),
- rd_ip.val);
+ for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm))
+ for (ri = rm->info; ri; ri = ri->next) {
+ total_count++;
+ if (type == bgp_show_type_neighbor) {
+ union sockunion *su = output_arg;
+
+ if (ri->peer->su_remote == NULL
+ || !sockunion_same(
+ ri->peer->su_remote, su))
+ continue;
+ }
+ if (header == 0) {
+ if (use_json) {
+ if (option
+ == SHOW_DISPLAY_TAGS) {
+ json_object_int_add(
+ json,
+ "bgpTableVersion",
+ 0);
json_object_string_add(
- json_nroute,
- "routeDistinguisher",
- buffer);
- } else {
+ json,
+ "bgpLocalRouterId",
+ inet_ntoa(
+ bgp->router_id));
+ json_object_object_add(
+ json,
+ "bgpStatusCodes",
+ json_scode);
+ json_object_object_add(
+ json,
+ "bgpOriginCodes",
+ json_ocode);
+ }
+ } else {
+ if (option == SHOW_DISPLAY_TAGS)
+ vty_out(vty,
+ V4_HEADER_TAG);
+ else if (
+ option
+ == SHOW_DISPLAY_OVERLAY)
+ vty_out(vty,
+ V4_HEADER_OVERLAY);
+ else {
+ vty_out(vty,
+ "BGP table version is 0, local router ID is %s\n",
+ inet_ntoa(
+ bgp->router_id));
vty_out(vty,
- "Route Distinguisher: ");
- if (type == RD_TYPE_AS)
- vty_out(vty,
- "as2 %u:%d",
- rd_as.as,
- rd_as.val);
- else if (type
- == RD_TYPE_AS4)
- vty_out(vty,
- "as4 %u:%d",
- rd_as.as,
- rd_as.val);
- else if (type
- == RD_TYPE_IP)
- vty_out(vty,
- "ip %s:%d",
- inet_ntoa(
- rd_ip.ip),
- rd_ip.val);
- vty_out(vty, "\n\n");
+ "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal\n");
+ vty_out(vty,
+ "Origin codes: i - IGP, e - EGP, ? - incomplete\n\n");
+ vty_out(vty, V4_HEADER);
}
- rd_header = 0;
}
- if (use_json)
- json_array =
- json_object_new_array();
- else
- json_array = NULL;
- if (option == SHOW_DISPLAY_TAGS)
- route_vty_out_tag(
- vty, &rm->p, ri, 0,
- SAFI_EVPN, json_array);
- else if (option == SHOW_DISPLAY_OVERLAY)
- route_vty_out_overlay(
- vty, &rm->p, ri, 0,
- json_array);
- else
- route_vty_out(vty, &rm->p, ri,
- 0, SAFI_EVPN,
- json_array);
- output_count++;
+ header = 0;
}
- /* XXX json */
- }
+ if (rd_header) {
+ u_int16_t type;
+ struct rd_as rd_as;
+ struct rd_ip rd_ip;
+ u_char *pnt;
+
+ pnt = rn->p.u.val;
+
+ /* Decode RD type. */
+ type = decode_rd_type(pnt);
+ /* Decode RD value. */
+ if (type == RD_TYPE_AS)
+ decode_rd_as(pnt + 2, &rd_as);
+ else if (type == RD_TYPE_AS4)
+ decode_rd_as4(pnt + 2, &rd_as);
+ else if (type == RD_TYPE_IP)
+ decode_rd_ip(pnt + 2, &rd_ip);
+ if (use_json) {
+ char buffer[BUFSIZ];
+ if (type == RD_TYPE_AS
+ || type == RD_TYPE_AS4)
+ sprintf(buffer, "%u:%d",
+ rd_as.as,
+ rd_as.val);
+ else if (type == RD_TYPE_IP)
+ sprintf(buffer, "%s:%d",
+ inet_ntoa(
+ rd_ip.ip),
+ rd_ip.val);
+ json_object_string_add(
+ json_nroute,
+ "routeDistinguisher",
+ buffer);
+ } else {
+ vty_out(vty,
+ "Route Distinguisher: ");
+ if (type == RD_TYPE_AS)
+ vty_out(vty,
+ "as2 %u:%d",
+ rd_as.as,
+ rd_as.val);
+ else if (type == RD_TYPE_AS4)
+ vty_out(vty,
+ "as4 %u:%d",
+ rd_as.as,
+ rd_as.val);
+ else if (type == RD_TYPE_IP)
+ vty_out(vty, "ip %s:%d",
+ inet_ntoa(
+ rd_ip.ip),
+ rd_ip.val);
+ vty_out(vty, "\n\n");
+ }
+ rd_header = 0;
+ }
+ if (use_json)
+ json_array = json_object_new_array();
+ else
+ json_array = NULL;
+ if (option == SHOW_DISPLAY_TAGS)
+ route_vty_out_tag(vty, &rm->p, ri, 0,
+ SAFI_EVPN,
+ json_array);
+ else if (option == SHOW_DISPLAY_OVERLAY)
+ route_vty_out_overlay(vty, &rm->p, ri,
+ 0, json_array);
+ else
+ route_vty_out(vty, &rm->p, ri, 0,
+ SAFI_EVPN, json_array);
+ output_count++;
+ }
+ /* XXX json */
}
if (output_count == 0)
vty_out(vty, "No prefixes displayed, %ld exist\n", total_count);
/*
* Display import RT mapping to VNIs (vty handler)
*/
-static void evpn_show_import_rts(struct vty *vty, struct bgp *bgp)
+static void evpn_show_import_rts(struct vty *vty, struct bgp *bgp,
+ json_object *json)
{
+ void *args[2];
+
+ args[0] = vty;
+ args[1] = json;
+
hash_iterate(
bgp->import_rt_hash,
(void (*)(struct hash_backet *, void *))show_import_rt_entry,
- vty);
+ args);
}
/*
* Display EVPN routes for all VNIs - vty handler.
*/
static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp,
- struct in_addr vtep_ip)
+ struct in_addr vtep_ip, json_object *json)
{
u_int32_t num_vnis;
struct vni_walk_ctx wctx;
wctx.bgp = bgp;
wctx.vty = vty;
wctx.vtep_ip = vtep_ip;
+ wctx.json = json;
hash_iterate(bgp->vnihash, (void (*)(struct hash_backet *,
void *))show_vni_routes_hash,
&wctx);
* Display EVPN routes for a VNI -- for specific type-3 route (vty handler).
*/
static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
- vni_t vni, struct in_addr orig_ip)
+ vni_t vni, struct in_addr orig_ip,
+ json_object *json)
{
struct bgpevpn *vpn;
struct prefix_evpn p;
u_int32_t path_cnt = 0;
afi_t afi;
safi_t safi;
+ json_object *json_paths = NULL;
afi = AFI_L2VPN;
safi = SAFI_EVPN;
build_evpn_type3_prefix(&p, orig_ip);
rn = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
if (!rn || !rn->info) {
- vty_out(vty, "%% Network not in table\n");
+ if (!json)
+ vty_out(vty, "%% Network not in table\n");
return;
}
+ if (json)
+ json_paths = json_object_new_array();
+
/* Prefix and num paths displayed once per prefix. */
- route_vty_out_detail_header(vty, bgp, rn, NULL, afi, safi, NULL);
+ route_vty_out_detail_header(vty, bgp, rn, NULL, afi, safi, json);
/* Display each path for this prefix. */
for (ri = rn->info; ri; ri = ri->next) {
- route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi, NULL);
+ json_object *json_path = NULL;
+
+ if (json)
+ json_path = json_object_new_array();
+
+ route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi,
+ json_path);
+
+ if (json)
+ json_object_array_add(json_paths, json_path);
+
path_cnt++;
}
- vty_out(vty, "\nDisplayed %u paths for requested prefix\n", path_cnt);
+ if (json) {
+ if (path_cnt)
+ json_object_object_add(json, "paths", json_paths);
+
+ json_object_int_add(json, "numPaths", path_cnt);
+ } else {
+ vty_out(vty, "\nDisplayed %u paths for requested prefix\n",
+ path_cnt);
+ }
}
/*
*/
static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
vni_t vni, struct ethaddr *mac,
- struct ipaddr *ip)
+ struct ipaddr *ip, json_object *json)
{
struct bgpevpn *vpn;
struct prefix_evpn p;
u_int32_t path_cnt = 0;
afi_t afi;
safi_t safi;
+ json_object *json_paths = NULL;
afi = AFI_L2VPN;
safi = SAFI_EVPN;
/* Locate VNI. */
vpn = bgp_evpn_lookup_vni(bgp, vni);
if (!vpn) {
- vty_out(vty, "VNI not found\n");
+ if (!json)
+ vty_out(vty, "VNI not found\n");
return;
}
build_evpn_type2_prefix(&p, mac, ip);
rn = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
if (!rn || !rn->info) {
- vty_out(vty, "%% Network not in table\n");
+ if (!json)
+ vty_out(vty, "%% Network not in table\n");
return;
}
+ if (json)
+ json_paths = json_object_new_array();
+
/* Prefix and num paths displayed once per prefix. */
- route_vty_out_detail_header(vty, bgp, rn, NULL, afi, safi, NULL);
+ route_vty_out_detail_header(vty, bgp, rn, NULL, afi, safi, json);
/* Display each path for this prefix. */
for (ri = rn->info; ri; ri = ri->next) {
- route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi, NULL);
+ json_object *json_path = NULL;
+
+ if (json)
+ json_path = json_object_new_array();
+
+ route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi,
+ json_path);
+
+ if (json)
+ json_object_array_add(json_paths, json_path);
+
path_cnt++;
}
- vty_out(vty, "\nDisplayed %u paths for requested prefix\n", path_cnt);
+ if (json) {
+ if (path_cnt)
+ json_object_object_add(json, "paths", json_paths);
+
+ json_object_int_add(json, "numPaths", path_cnt);
+ } else {
+ vty_out(vty, "\nDisplayed %u paths for requested prefix\n",
+ path_cnt);
+ }
}
/*
* If the vtep_ip is non zero, only routes behind that vtep are shown
*/
static void evpn_show_routes_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
- int type, struct in_addr vtep_ip)
+ int type, struct in_addr vtep_ip,
+ json_object *json)
{
struct bgpevpn *vpn;
/* Locate VNI. */
vpn = bgp_evpn_lookup_vni(bgp, vni);
if (!vpn) {
- vty_out(vty, "VNI not found\n");
+ if (!json)
+ vty_out(vty, "VNI not found\n");
return;
}
/* Walk this VNI's route table and display appropriate routes. */
- show_vni_routes(bgp, vpn, type, vty, vtep_ip);
+ show_vni_routes(bgp, vpn, type, vty, vtep_ip, json);
}
/*
*/
static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
struct prefix_rd *prd, struct ethaddr *mac,
- struct ipaddr *ip)
+ struct ipaddr *ip, json_object *json)
{
struct prefix_evpn p;
struct bgp_node *rn;
afi_t afi;
safi_t safi;
u_int32_t path_cnt = 0;
+ json_object *json_paths = NULL;
+ char prefix_str[BUFSIZ];
afi = AFI_L2VPN;
safi = SAFI_EVPN;
rn = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi,
(struct prefix *)&p, prd);
if (!rn || !rn->info) {
- vty_out(vty, "%% Network not in table\n");
+ if (!json)
+ vty_out(vty, "%% Network not in table\n");
return;
}
+ bgp_evpn_route2str((struct prefix_evpn *)&p, prefix_str,
+ sizeof(prefix_str));
+
/* Prefix and num paths displayed once per prefix. */
- route_vty_out_detail_header(vty, bgp, rn, prd, afi, safi, NULL);
+ route_vty_out_detail_header(vty, bgp, rn, prd, afi, safi, json);
+
+ if (json)
+ json_paths = json_object_new_array();
/* Display each path for this prefix. */
for (ri = rn->info; ri; ri = ri->next) {
- route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi, NULL);
+ json_object *json_path = NULL;
+
+ if (json)
+ json_path = json_object_new_array();
+
+ route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi,
+ json_path);
+
+ if (json)
+ json_object_array_add(json_paths, json_path);
+
path_cnt++;
}
- vty_out(vty, "\nDisplayed %u paths for requested prefix\n", path_cnt);
+ if (json && path_cnt) {
+ if (path_cnt)
+ json_object_object_add(json, prefix_str, json_paths);
+ json_object_int_add(json, "numPaths", path_cnt);
+ } else {
+ vty_out(vty, "\nDisplayed %u paths for requested prefix\n",
+ path_cnt);
+ }
}
/*
* If 'type' is non-zero, only routes matching that type are shown.
*/
static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
- struct prefix_rd *prd, int type)
+ struct prefix_rd *prd, int type,
+ json_object *json)
{
struct bgp_node *rd_rn;
struct bgp_table *table;
afi_t afi;
safi_t safi;
u_int32_t prefix_cnt, path_cnt;
+ char rd_str[RD_ADDRSTRLEN];
+ json_object *json_rd = NULL;
+ int add_rd_to_json = 0;
afi = AFI_L2VPN;
safi = SAFI_EVPN;
prefix_cnt = path_cnt = 0;
+ prefix_rd2str((struct prefix_rd *)prd, rd_str, sizeof(rd_str));
+
rd_rn = bgp_node_lookup(bgp->rib[afi][safi], (struct prefix *)prd);
if (!rd_rn)
return;
+
table = (struct bgp_table *)rd_rn->info;
if (table == NULL)
return;
+ if (json) {
+ json_rd = json_object_new_object();
+ json_object_string_add(json_rd, "rd", rd_str);
+ }
+
/* Display all prefixes with this RD. */
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
+ json_object *json_prefix = NULL;
+ json_object *json_paths = NULL;
+ char prefix_str[BUFSIZ];
+ int add_prefix_to_json = 0;
+
+ bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str,
+ sizeof(prefix_str));
if (type && evp->prefix.route_type != type)
continue;
+ if (json)
+ json_prefix = json_object_new_object();
+
if (rn->info) {
/* RD header and legend - once overall. */
- if (rd_header) {
+ if (rd_header && !json) {
vty_out(vty,
"EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:"
"[MAC]\n");
/* Prefix and num paths displayed once per prefix. */
route_vty_out_detail_header(vty, bgp, rn, prd, afi,
- safi, NULL);
+ safi, json_prefix);
prefix_cnt++;
}
+ if (json)
+ json_paths = json_object_new_array();
+
/* Display each path for this prefix. */
for (ri = rn->info; ri; ri = ri->next) {
+ json_object *json_path = NULL;
+
+ if (json)
+ json_path = json_object_new_array();
+
route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi,
- NULL);
+ json_path);
+
+ if (json)
+ json_object_array_add(json_paths, json_path);
+
path_cnt++;
+ add_prefix_to_json = 1;
+ add_rd_to_json = 1;
+ }
+
+ if (json && add_prefix_to_json) {
+ json_object_object_add(json_prefix, "paths",
+ json_paths);
+ json_object_object_add(json_rd, prefix_str,
+ json_prefix);
}
}
- if (prefix_cnt == 0)
- vty_out(vty, "No prefixes exist with this RD%s\n",
- type ? " (of requested type)" : "");
- else
- vty_out(vty,
- "\nDisplayed %u prefixes (%u paths) with this RD%s\n",
- prefix_cnt, path_cnt,
- type ? " (of requested type)" : "");
+ if (json && add_rd_to_json)
+ json_object_object_add(json, rd_str, json_rd);
+
+ if (json) {
+ json_object_int_add(json, "numPrefix", prefix_cnt);
+ json_object_int_add(json, "numPaths", path_cnt);
+ } else {
+ if (prefix_cnt == 0)
+ vty_out(vty, "No prefixes exist with this RD%s\n",
+ type ? " (of requested type)" : "");
+ else
+ vty_out(vty,
+ "\nDisplayed %u prefixes (%u paths) with this RD%s\n",
+ prefix_cnt, path_cnt,
+ type ? " (of requested type)" : "");
+ }
}
/*
* Display BGP EVPN routing table - all routes (vty handler).
* If 'type' is non-zero, only routes matching that type are shown.
*/
-static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type)
+static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
+ json_object *json)
{
struct bgp_node *rd_rn;
struct bgp_table *table;
*/
for (rd_rn = bgp_table_top(bgp->rib[afi][safi]); rd_rn;
rd_rn = bgp_route_next(rd_rn)) {
+ char rd_str[RD_ADDRSTRLEN];
+ json_object *json_rd = NULL; /* contains routes for an RD */
+ int add_rd_to_json = 0;
+
table = (struct bgp_table *)rd_rn->info;
if (table == NULL)
continue;
+ prefix_rd2str((struct prefix_rd *)&rd_rn->p, rd_str,
+ sizeof(rd_str));
+
+ if (json) {
+ json_rd = json_object_new_object();
+ json_object_string_add(json_rd, "rd", rd_str);
+ }
+
rd_header = 1;
/* Display all prefixes for an RD */
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+ json_object *json_prefix =
+ NULL; /* contains prefix under a RD */
+ json_object *json_paths =
+ NULL; /* array of paths under a prefix*/
struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
+ char prefix_str[BUFSIZ];
+ int add_prefix_to_json = 0;
+
+ bgp_evpn_route2str((struct prefix_evpn *)&rn->p,
+ prefix_str, sizeof(prefix_str));
if (type && evp->prefix.route_type != type)
continue;
if (rn->info) {
/* Overall header/legend displayed once. */
if (header) {
- bgp_evpn_show_route_header(vty, bgp);
+ bgp_evpn_show_route_header(vty, bgp,
+ json);
header = 0;
}
/* RD header - per RD. */
if (rd_header) {
- bgp_evpn_show_route_rd_header(vty,
- rd_rn);
+ bgp_evpn_show_route_rd_header(
+ vty, rd_rn, json);
rd_header = 0;
}
prefix_cnt++;
}
+ if (json) {
+ json_prefix = json_object_new_object();
+ json_paths = json_object_new_array();
+ json_object_string_add(json_prefix, "prefix",
+ prefix_str);
+ json_object_int_add(json_prefix, "prefixLen",
+ rn->p.prefixlen);
+ }
+
/* For EVPN, the prefix is displayed for each path (to
* fit in
* with code that already exists).
*/
for (ri = rn->info; ri; ri = ri->next) {
+ json_object *json_path = NULL;
path_cnt++;
+ add_prefix_to_json = 1;
+ add_rd_to_json = 1;
+
+ if (json)
+ json_path = json_object_new_array();
+
route_vty_out(vty, &rn->p, ri, 0, SAFI_EVPN,
- NULL);
+ json_path);
+
+ if (json)
+ json_object_array_add(json_paths,
+ json_path);
+ }
+
+ if (json && add_prefix_to_json) {
+ json_object_object_add(json_prefix, "paths",
+ json_paths);
+ json_object_object_add(json_rd, prefix_str,
+ json_prefix);
}
}
+
+ if (json && add_rd_to_json)
+ json_object_object_add(json, rd_str, json_rd);
}
- if (prefix_cnt == 0)
- vty_out(vty, "No EVPN prefixes %sexist\n",
- type ? "(of requested type) " : "");
- else
- vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s\n",
- prefix_cnt, path_cnt,
- type ? " (of requested type)" : "");
+ if (json) {
+ json_object_int_add(json, "numPrefix", prefix_cnt);
+ json_object_int_add(json, "numPaths", path_cnt);
+ } else {
+ if (prefix_cnt == 0) {
+ vty_out(vty, "No EVPN prefixes %sexist\n",
+ type ? "(of requested type) " : "");
+ } else {
+ vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s\n",
+ prefix_cnt, path_cnt,
+ type ? " (of requested type)" : "");
+ }
+ }
}
/*
* Display specified VNI (vty handler)
*/
-static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni)
+static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
+ json_object *json)
{
struct bgpevpn *vpn;
vpn = bgp_evpn_lookup_vni(bgp, vni);
if (!vpn) {
- vty_out(vty, "VNI not found\n");
- return;
+ if (json) {
+ vty_out(vty, "{}\n");
+ } else {
+ vty_out(vty, "VNI not found\n");
+ return;
+ }
}
- display_vni(vty, vpn);
+ display_vni(vty, vpn, json);
}
/*
* Display a VNI (upon user query).
*/
-static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp)
+static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp,
+ json_object *json)
{
u_int32_t num_vnis;
+ void *args[2];
num_vnis = hashcount(bgp->vnihash);
if (!num_vnis)
return;
- vty_out(vty, "Number of VNIs: %u\n", num_vnis);
- vty_out(vty, "Flags: * - Kernel \n");
- vty_out(vty, " %-10s %-15s %-21s %-25s %-25s\n", "VNI", "Orig IP",
- "RD", "Import RT", "Export RT");
+
+ if (json) {
+ json_object_int_add(json, "numVnis", num_vnis);
+ } else {
+ vty_out(vty, "Number of VNIs: %u\n", num_vnis);
+ vty_out(vty, "Flags: * - Kernel\n");
+ vty_out(vty, " %-10s %-15s %-21s %-25s %-25s\n", "VNI",
+ "Orig IP", "RD", "Import RT", "Export RT");
+ }
+
+ args[0] = vty;
+ args[1] = json;
hash_iterate(bgp->vnihash,
(void (*)(struct hash_backet *, void *))show_vni_entry,
- vty);
+ args);
}
/*
}
#endif /* HAVE_CUMULUS */
-static void write_vni_config(struct vty *vty, struct bgpevpn *vpn, int *write)
+static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
{
char buf1[INET6_ADDRSTRLEN];
- afi_t afi = AFI_L2VPN;
- safi_t safi = SAFI_EVPN;
char *ecom_str;
struct listnode *node, *nnode;
struct ecommunity *ecom;
if (is_vni_configured(vpn)) {
- bgp_config_write_family_header(vty, afi, safi, write);
vty_out(vty, " vni %d\n", vpn->vni);
if (is_rd_configured(vpn))
vty_out(vty, " rd %s\n",
}
static void write_vni_config_for_entry(struct hash_backet *backet,
- struct evpn_config_write *cfg)
+ struct vty *vty)
{
struct bgpevpn *vpn = (struct bgpevpn *)backet->data;
- write_vni_config(cfg->vty, vpn, &cfg->write);
+ write_vni_config(vty, vpn);
}
#if defined(HAVE_CUMULUS)
/*
* Display VNI information - for all or a specific VNI
*/
-DEFUN (show_bgp_l2vpn_evpn_vni,
- show_bgp_l2vpn_evpn_vni_cmd,
- "show bgp l2vpn evpn vni [(1-16777215)]",
- SHOW_STR
- BGP_STR
- L2VPN_HELP_STR
- EVPN_HELP_STR
- "Show VNI\n"
- "VNI number\n")
+DEFUN(show_bgp_l2vpn_evpn_vni,
+ show_bgp_l2vpn_evpn_vni_cmd,
+ "show bgp l2vpn evpn vni [(1-16777215)] [json]",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Show VNI\n"
+ "VNI number\n"
+ JSON_STR)
{
struct bgp *bgp;
vni_t vni;
int idx = 0;
+ u_char uj = 0;
+ json_object *json = NULL;
+
+ uj = use_json(argc, argv);
bgp = bgp_get_default();
if (!bgp)
if (!argv_find(argv, argc, "evpn", &idx))
return CMD_WARNING;
- if (argc == ((idx + 1) + 1)) {
- vty_out(vty, "Advertise gateway macip flag: %s\n",
- bgp->advertise_gw_macip ? "Enabled" : "Disabled");
+ if (uj)
+ json = json_object_new_object();
- /* Display all VNIs */
- vty_out(vty, "Advertise All VNI flag: %s\n",
- bgp->advertise_all_vni ? "Enabled" : "Disabled");
- evpn_show_all_vnis(vty, bgp);
+ if ((uj && argc == ((idx + 1) + 2)) || (!uj && argc == (idx + 1) + 1)) {
+ if (uj) {
+ json_object_string_add(json, "advertiseGatewayMacip",
+ bgp->advertise_gw_macip
+ ? "Enabled"
+ : "Disabled");
+ json_object_string_add(json, "advertiseAllVnis",
+ bgp->advertise_all_vni
+ ? "Enabled"
+ : "Disabled");
+ } else {
+ vty_out(vty, "Advertise Gateway Macip: %s\n",
+ bgp->advertise_gw_macip ? "Enabled"
+ : "Disabled");
+
+ /* Display all VNIs */
+ vty_out(vty, "Advertise All VNI flag: %s\n",
+ bgp->advertise_all_vni ? "Enabled"
+ : "Disabled");
+ }
+
+ evpn_show_all_vnis(vty, bgp, json);
} else {
+ int vni_idx = 0;
+
+ if (!argv_find(argv, argc, "vni", &vni_idx))
+ return CMD_WARNING;
+
/* Display specific VNI */
- vni = strtoul(argv[argc - 1]->arg, NULL, 10);
- evpn_show_vni(vty, bgp, vni);
+ vni = strtoul(argv[vni_idx + 1]->arg, NULL, 10);
+ evpn_show_vni(vty, bgp, vni, json);
+ }
+
+ if (uj) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
}
return CMD_SUCCESS;
/*
* Display EVPN neighbor summary.
*/
-DEFUN (show_bgp_l2vpn_evpn_summary,
- show_bgp_l2vpn_evpn_summary_cmd,
- "show bgp l2vpn evpn summary [json]",
- SHOW_STR
- BGP_STR
- L2VPN_HELP_STR
- EVPN_HELP_STR
- "Summary of BGP neighbor status\n"
- JSON_STR)
+DEFUN(show_bgp_l2vpn_evpn_summary,
+ show_bgp_l2vpn_evpn_summary_cmd,
+ "show bgp l2vpn evpn summary [json]",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Summary of BGP neighbor status\n"
+ JSON_STR)
{
u_char uj = use_json(argc, argv);
return bgp_show_summary_vty(vty, NULL, AFI_L2VPN, SAFI_EVPN, uj);
/*
* Display global EVPN routing table.
*/
-DEFUN (show_bgp_l2vpn_evpn_route,
- show_bgp_l2vpn_evpn_route_cmd,
- "show bgp l2vpn evpn route [type <macip|multicast>]",
- SHOW_STR
- BGP_STR
- L2VPN_HELP_STR
- EVPN_HELP_STR
- "EVPN route information\n"
- "Specify Route type\n"
- "MAC-IP (Type-2) route\n"
- "Multicast (Type-3) route\n")
+DEFUN(show_bgp_l2vpn_evpn_route,
+ show_bgp_l2vpn_evpn_route_cmd,
+ "show bgp l2vpn evpn route [type <macip|multicast>] [json]",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "EVPN route information\n"
+ "Specify Route type\n"
+ "MAC-IP (Type-2) route\n"
+ "Multicast (Type-3) route\n"
+ JSON_STR)
{
struct bgp *bgp;
- int idx = 0;
+ int type_idx;
int type = 0;
+ u_char uj = 0;
+ json_object *json = NULL;
+
+ uj = use_json(argc, argv);
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
- if (!argv_find(argv, argc, "evpn", &idx))
- return CMD_WARNING;
+ if (uj)
+ json = json_object_new_object();
- if (argc == ((idx + 1) + 3)) {
+ /* get the type */
+ if (argv_find(argv, argc, "type", &type_idx)) {
/* Specific type is requested */
- if (strncmp(argv[argc - 1]->arg, "ma", 2) == 0)
+ if (strncmp(argv[type_idx + 1]->arg, "ma", 2) == 0)
type = BGP_EVPN_MAC_IP_ROUTE;
- else if (strncmp(argv[argc - 1]->arg, "mu", 2) == 0)
+ else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
type = BGP_EVPN_IMET_ROUTE;
else
return CMD_WARNING;
}
- evpn_show_all_routes(vty, bgp, type);
+ evpn_show_all_routes(vty, bgp, type, json);
+
+ if (uj) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
return CMD_SUCCESS;
}
/*
* Display global EVPN routing table for specific RD.
*/
-DEFUN (show_bgp_l2vpn_evpn_route_rd,
- show_bgp_l2vpn_evpn_route_rd_cmd,
- "show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn [type <macip|multicast>]",
- SHOW_STR
- BGP_STR
- L2VPN_HELP_STR
- EVPN_HELP_STR
- "EVPN route information\n"
- "Route Distinguisher\n"
- "ASN:XX or A.B.C.D:XX\n"
- "Specify Route type\n"
- "MAC-IP (Type-2) route\n"
- "Multicast (Type-3) route\n")
+DEFUN(show_bgp_l2vpn_evpn_route_rd,
+ show_bgp_l2vpn_evpn_route_rd_cmd,
+ "show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn [type <macip|multicast>] [json]",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "EVPN route information\n"
+ "Route Distinguisher\n"
+ "ASN:XX or A.B.C.D:XX\n"
+ "Specify Route type\n"
+ "MAC-IP (Type-2) route\n"
+ "Multicast (Type-3) route\n"
+ JSON_STR)
{
struct bgp *bgp;
int ret;
struct prefix_rd prd;
- int idx = 0;
int type = 0;
+ int rd_idx = 0;
+ int type_idx = 0;
+ int uj = 0;
+ json_object *json = NULL;
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
- if (!argv_find(argv, argc, "evpn", &idx))
- return CMD_WARNING;
+ /* check if we need json output */
+ uj = use_json(argc, argv);
+ if (uj)
+ json = json_object_new_object();
- ret = str2prefix_rd(argv[idx + 3]->arg, &prd);
- if (!ret) {
- vty_out(vty, "%% Malformed Route Distinguisher\n");
- return CMD_WARNING;
+ /* get the RD */
+ if (argv_find(argv, argc, "rd", &rd_idx)) {
+ ret = str2prefix_rd(argv[rd_idx + 1]->arg, &prd);
+
+ if (!ret) {
+ vty_out(vty, "%% Malformed Route Distinguisher\n");
+ return CMD_WARNING;
+ }
}
- if (argc == ((idx + 1) + 5)) {
+ /* get the type */
+ if (argv_find(argv, argc, "type", &type_idx)) {
/* Specific type is requested */
- if (strncmp(argv[argc - 1]->arg, "ma", 2) == 0)
+ if (strncmp(argv[type_idx + 1]->arg, "ma", 2) == 0)
type = BGP_EVPN_MAC_IP_ROUTE;
- else if (strncmp(argv[argc - 1]->arg, "mu", 2) == 0)
+ else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
type = BGP_EVPN_IMET_ROUTE;
else
return CMD_WARNING;
}
- evpn_show_route_rd(vty, bgp, &prd, type);
+ evpn_show_route_rd(vty, bgp, &prd, type, json);
+
+ if (uj) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
return CMD_SUCCESS;
}
/*
* Display global EVPN routing table for specific RD and MACIP.
*/
-DEFUN (show_bgp_l2vpn_evpn_route_rd_macip,
- show_bgp_l2vpn_evpn_route_rd_macip_cmd,
- "show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD]",
- SHOW_STR
- BGP_STR
- L2VPN_HELP_STR
- EVPN_HELP_STR
- "EVPN route information\n"
- "Route Distinguisher\n"
- "ASN:XX or A.B.C.D:XX\n"
- "MAC\n"
- "MAC address (e.g., 00:e0:ec:20:12:62)\n"
- "IP\n"
- "IP address (IPv4 or IPv6)\n")
+DEFUN(show_bgp_l2vpn_evpn_route_rd_macip,
+ show_bgp_l2vpn_evpn_route_rd_macip_cmd,
+ "show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD] [json]",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "EVPN route information\n"
+ "Route Distinguisher\n"
+ "ASN:XX or A.B.C.D:XX\n"
+ "MAC\n"
+ "MAC address (e.g., 00:e0:ec:20:12:62)\n"
+ "IP\n"
+ "IP address (IPv4 or IPv6)\n"
+ JSON_STR)
{
struct bgp *bgp;
int ret;
struct prefix_rd prd;
struct ethaddr mac;
struct ipaddr ip;
- int idx = 0;
+ int rd_idx = 0;
+ int mac_idx = 0;
+ int ip_idx = 0;
+ int uj = 0;
+ json_object *json = NULL;
+
+ memset(&mac, 0, sizeof(struct ethaddr));
+ memset(&ip, 0, sizeof(struct ipaddr));
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
- if (!argv_find(argv, argc, "evpn", &idx))
- return CMD_WARNING;
+ /* check if we need json output */
+ uj = use_json(argc, argv);
+ if (uj)
+ json = json_object_new_object();
- ret = str2prefix_rd(argv[idx + 3]->arg, &prd);
- if (!ret) {
- vty_out(vty, "%% Malformed Route Distinguisher\n");
- return CMD_WARNING;
+ /* get the prd */
+ if (argv_find(argv, argc, "rd", &rd_idx)) {
+ ret = str2prefix_rd(argv[rd_idx + 1]->arg, &prd);
+ if (!ret) {
+ vty_out(vty, "%% Malformed Route Distinguisher\n");
+ return CMD_WARNING;
+ }
}
- if (!prefix_str2mac(argv[idx + 5]->arg, &mac)) {
- vty_out(vty, "%% Malformed MAC address\n");
- return CMD_WARNING;
+
+ /* get the mac */
+ if (argv_find(argv, argc, "mac", &mac_idx)) {
+ if (!prefix_str2mac(argv[mac_idx + 1]->arg, &mac)) {
+ vty_out(vty, "%% Malformed MAC address\n");
+ return CMD_WARNING;
+ }
}
- memset(&ip, 0, sizeof(ip));
- if (argc == (idx + 1 + 7) && argv[argc - 1]->arg != NULL) {
- /* Specific MAC+IP requested */
- if (str2ipaddr(argv[argc - 1]->arg, &ip) != 0) {
+
+ /* get the ip if specified */
+ if (argv_find(argv, argc, "ip", &ip_idx)) {
+ if (str2ipaddr(argv[ip_idx + 1]->arg, &ip) != 0) {
vty_out(vty, "%% Malformed IP address\n");
return CMD_WARNING;
}
}
- evpn_show_route_rd_macip(vty, bgp, &prd, &mac, &ip);
+ evpn_show_route_rd_macip(vty, bgp, &prd, &mac, &ip, json);
+
+ if (uj) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
return CMD_SUCCESS;
}
/*
* Display per-VNI EVPN routing table.
*/
-DEFUN (show_bgp_l2vpn_evpn_route_vni,
- show_bgp_l2vpn_evpn_route_vni_cmd,
- "show bgp l2vpn evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>]",
- SHOW_STR
- BGP_STR
- L2VPN_HELP_STR
- EVPN_HELP_STR
- "EVPN route information\n"
- "VXLAN Network Identifier\n"
- "VNI number\n"
- "Specify Route type\n"
- "MAC-IP (Type-2) route\n"
- "Multicast (Type-3) route\n"
- "Remote VTEP\n"
- "Remote VTEP IP address\n")
+DEFUN(show_bgp_l2vpn_evpn_route_vni, show_bgp_l2vpn_evpn_route_vni_cmd,
+ "show bgp l2vpn evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>] [json]",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "EVPN route information\n"
+ "VXLAN Network Identifier\n"
+ "VNI number\n"
+ "Specify Route type\n"
+ "MAC-IP (Type-2) route\n"
+ "Multicast (Type-3) route\n"
+ "Remote VTEP\n"
+ "Remote VTEP IP address\n"
+ JSON_STR)
{
vni_t vni;
struct bgp *bgp;
struct in_addr vtep_ip;
int type = 0;
int idx = 0;
+ int uj = 0;
+ json_object *json = NULL;
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
+ /* check if we need json output */
+ uj = use_json(argc, argv);
+ if (uj)
+ json = json_object_new_object();
+
if (!argv_find(argv, argc, "evpn", &idx))
return CMD_WARNING;
vni = strtoul(argv[idx + 3]->arg, NULL, 10);
- if (argc == (idx + 1 + 5) && argv[idx + 4]->arg) {
+ if ((!uj && ((argc == (idx + 1 + 5)) && argv[idx + 4]->arg))
+ || (uj && ((argc == (idx + 1 + 6)) && argv[idx + 4]->arg))) {
if (strncmp(argv[idx + 4]->arg, "type", 4) == 0) {
if (strncmp(argv[idx + 5]->arg, "ma", 2) == 0)
type = BGP_EVPN_MAC_IP_ROUTE;
return CMD_WARNING;
}
- evpn_show_routes_vni(vty, bgp, vni, type, vtep_ip);
+ evpn_show_routes_vni(vty, bgp, vni, type, vtep_ip, json);
+
+ if (uj) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
return CMD_SUCCESS;
}
/*
* Display per-VNI EVPN routing table for specific MACIP.
*/
-DEFUN (show_bgp_l2vpn_evpn_route_vni_macip,
- show_bgp_l2vpn_evpn_route_vni_macip_cmd,
- "show bgp l2vpn evpn route vni (1-16777215) mac WORD [ip WORD]",
- SHOW_STR
- BGP_STR
- L2VPN_HELP_STR
- EVPN_HELP_STR
- "EVPN route information\n"
- "VXLAN Network Identifier\n"
- "VNI number\n"
- "MAC\n"
- "MAC address (e.g., 00:e0:ec:20:12:62)\n"
- "IP\n"
- "IP address (IPv4 or IPv6)\n")
+DEFUN(show_bgp_l2vpn_evpn_route_vni_macip,
+ show_bgp_l2vpn_evpn_route_vni_macip_cmd,
+ "show bgp l2vpn evpn route vni (1-16777215) mac WORD [ip WORD] [json]",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "EVPN route information\n"
+ "VXLAN Network Identifier\n"
+ "VNI number\n"
+ "MAC\n"
+ "MAC address (e.g., 00:e0:ec:20:12:62)\n"
+ "IP\n"
+ "IP address (IPv4 or IPv6)\n"
+ JSON_STR)
{
vni_t vni;
struct bgp *bgp;
struct ethaddr mac;
struct ipaddr ip;
int idx = 0;
+ int uj = 0;
+ json_object *json = NULL;
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
+ /* check if we need json output */
+ uj = use_json(argc, argv);
+ if (uj)
+ json = json_object_new_object();
+
if (!argv_find(argv, argc, "evpn", &idx))
return CMD_WARNING;
+ /* get the VNI */
vni = strtoul(argv[idx + 3]->arg, NULL, 10);
+
+ /* get the mac */
if (!prefix_str2mac(argv[idx + 5]->arg, &mac)) {
vty_out(vty, "%% Malformed MAC address\n");
return CMD_WARNING;
}
+
+ /* get the ip */
memset(&ip, 0, sizeof(ip));
- if (argc == (idx + 1 + 7) && argv[idx + 7]->arg != NULL) {
+ if ((!uj && ((argc == (idx + 1 + 7)) && argv[idx + 7]->arg != NULL))
+ || (uj
+ && ((argc == (idx + 1 + 8)) && argv[idx + 7]->arg != NULL))) {
if (str2ipaddr(argv[idx + 7]->arg, &ip) != 0) {
vty_out(vty, "%% Malformed IP address\n");
return CMD_WARNING;
}
}
- evpn_show_route_vni_macip(vty, bgp, vni, &mac, &ip);
+ evpn_show_route_vni_macip(vty, bgp, vni, &mac, &ip, json);
+
+ if (uj) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
return CMD_SUCCESS;
}
/*
* Display per-VNI EVPN routing table for specific multicast IP (remote VTEP).
*/
-DEFUN (show_bgp_l2vpn_evpn_route_vni_multicast,
- show_bgp_l2vpn_evpn_route_vni_multicast_cmd,
- "show bgp l2vpn evpn route vni (1-16777215) multicast A.B.C.D",
- SHOW_STR
- BGP_STR
- L2VPN_HELP_STR
- EVPN_HELP_STR
- "EVPN route information\n"
- "VXLAN Network Identifier\n"
- "VNI number\n"
- "Multicast (Type-3) route\n"
- "Originating Router IP address\n")
+DEFUN(show_bgp_l2vpn_evpn_route_vni_multicast,
+ show_bgp_l2vpn_evpn_route_vni_multicast_cmd,
+ "show bgp l2vpn evpn route vni (1-16777215) multicast A.B.C.D [json]",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "EVPN route information\n"
+ "VXLAN Network Identifier\n"
+ "VNI number\n"
+ "Multicast (Type-3) route\n"
+ "Originating Router IP address\n"
+ JSON_STR)
{
vni_t vni;
struct bgp *bgp;
int ret;
struct in_addr orig_ip;
int idx = 0;
+ int uj = 0;
+ json_object *json = NULL;
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
+ /* check if we need json output */
+ uj = use_json(argc, argv);
+ if (uj)
+ json = json_object_new_object();
+
if (!argv_find(argv, argc, "evpn", &idx))
return CMD_WARNING;
+ /* get the VNI */
vni = strtoul(argv[idx + 3]->arg, NULL, 10);
+
+ /* get the ip */
ret = inet_aton(argv[idx + 5]->arg, &orig_ip);
if (!ret) {
vty_out(vty, "%% Malformed Originating Router IP address\n");
return CMD_WARNING;
}
- evpn_show_route_vni_multicast(vty, bgp, vni, orig_ip);
+ evpn_show_route_vni_multicast(vty, bgp, vni, orig_ip, json);
+
+ if (uj) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
return CMD_SUCCESS;
}
/*
* Display per-VNI EVPN routing table - for all VNIs.
*/
-DEFUN (show_bgp_l2vpn_evpn_route_vni_all,
- show_bgp_l2vpn_evpn_route_vni_all_cmd,
- "show bgp l2vpn evpn route vni all [vtep A.B.C.D]",
- SHOW_STR
- BGP_STR
- L2VPN_HELP_STR
- EVPN_HELP_STR
- "EVPN route information\n"
- "VXLAN Network Identifier\n"
- "All VNIs\n"
- "Remote VTEP\n"
- "Remote VTEP IP address\n")
+DEFUN(show_bgp_l2vpn_evpn_route_vni_all,
+ show_bgp_l2vpn_evpn_route_vni_all_cmd,
+ "show bgp l2vpn evpn route vni all [vtep A.B.C.D] [json]",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "EVPN route information\n"
+ "VXLAN Network Identifier\n"
+ "All VNIs\n"
+ "Remote VTEP\n"
+ "Remote VTEP IP address\n"
+ JSON_STR)
{
struct bgp *bgp;
struct in_addr vtep_ip;
int idx = 0;
+ int uj = 0;
+ json_object *json = NULL;
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
+ /* check if we need json output */
+ uj = use_json(argc, argv);
+ if (uj)
+ json = json_object_new_object();
+
if (!argv_find(argv, argc, "evpn", &idx))
return CMD_WARNING;
vtep_ip.s_addr = 0;
- if (argc == (idx + 1 + 5) && argv[idx + 5]->arg) {
+ if ((!uj && (argc == (idx + 1 + 5) && argv[idx + 5]->arg))
+ || (uj && (argc == (idx + 1 + 6) && argv[idx + 5]->arg))) {
if (!inet_aton(argv[idx + 5]->arg, &vtep_ip)) {
vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING;
}
}
- evpn_show_routes_vni_all(vty, bgp, vtep_ip);
+ evpn_show_routes_vni_all(vty, bgp, vtep_ip, json);
+
+ if (uj) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
return CMD_SUCCESS;
}
/*
* Display EVPN import route-target hash table
*/
-DEFUN (show_bgp_l2vpn_evpn_import_rt,
- show_bgp_l2vpn_evpn_import_rt_cmd,
- "show bgp l2vpn evpn import-rt",
- SHOW_STR
- BGP_STR
- L2VPN_HELP_STR
- EVPN_HELP_STR
- "Show import route target\n")
+DEFUN(show_bgp_l2vpn_evpn_import_rt,
+ show_bgp_l2vpn_evpn_import_rt_cmd,
+ "show bgp l2vpn evpn import-rt [json]",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Show import route target\n"
+ JSON_STR)
{
struct bgp *bgp;
+ u_char uj = 0;
+ json_object *json = NULL;
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
- evpn_show_import_rts(vty, bgp);
+ uj = use_json(argc, argv);
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_import_rts(vty, bgp, json);
+
+ if (uj) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
return CMD_SUCCESS;
}
* Output EVPN configuration information.
*/
void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
- safi_t safi, int *write)
+ safi_t safi)
{
- struct evpn_config_write cfg;
-
- if (bgp->vnihash) {
- cfg.write = *write;
- cfg.vty = vty;
+ if (bgp->vnihash)
hash_iterate(bgp->vnihash,
(void (*)(struct hash_backet *,
void *))write_vni_config_for_entry,
- &cfg);
- *write = cfg.write;
- }
+ vty);
- if (bgp->advertise_all_vni) {
- bgp_config_write_family_header(vty, afi, safi, write);
+ if (bgp->advertise_all_vni)
vty_out(vty, " advertise-all-vni\n");
- }
- if (bgp->advertise_gw_macip) {
- bgp_config_write_family_header(vty, afi, safi, write);
+ if (bgp->advertise_gw_macip)
vty_out(vty, " advertise-default-gw\n");
- }
}
void bgp_ethernetvpn_init(void)
#define _FRR_BGP_EVPN_VTY_H
extern void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp,
- afi_t afi, safi_t safi, int *write);
+ afi_t afi, safi_t safi);
extern void bgp_ethernetvpn_init(void);
#define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n"
DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp")
DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate")
DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address")
+DEFINE_MTYPE(BGPD, TIP_ADDR, "BGP own tunnel-ip address")
DEFINE_MTYPE(BGPD, BGP_REDIST, "BGP redistribution")
DEFINE_MTYPE(BGPD, BGP_FILTER_NAME, "BGP Filter Information")
DECLARE_MTYPE(BGP_REGEXP)
DECLARE_MTYPE(BGP_AGGREGATE)
DECLARE_MTYPE(BGP_ADDR)
+DECLARE_MTYPE(TIP_ADDR)
DECLARE_MTYPE(BGP_REDIST)
DECLARE_MTYPE(BGP_FILTER_NAME)
}
}
-/* BGP own address structure */
-struct bgp_addr {
- struct in_addr addr;
- int refcnt;
-};
+static void *bgp_tip_hash_alloc(void *p)
+{
+ const struct in_addr *val = (const struct in_addr *)p;
+ struct tip_addr *addr;
+
+ addr = XMALLOC(MTYPE_TIP_ADDR, sizeof(struct tip_addr));
+ addr->refcnt = 0;
+ addr->addr.s_addr = val->s_addr;
+
+ return addr;
+}
+
+static void bgp_tip_hash_free(void *addr)
+{
+ XFREE(MTYPE_TIP_ADDR, addr);
+}
+
+static unsigned int bgp_tip_hash_key_make(void *p)
+{
+ const struct tip_addr *addr = p;
+
+ return jhash_1word(addr->addr.s_addr, 0);
+}
+
+static int bgp_tip_hash_cmp(const void *p1, const void *p2)
+{
+ const struct tip_addr *addr1 = p1;
+ const struct tip_addr *addr2 = p2;
+
+ return addr1->addr.s_addr == addr2->addr.s_addr;
+}
+
+void bgp_tip_hash_init(struct bgp *bgp)
+{
+ bgp->tip_hash =
+ hash_create(bgp_tip_hash_key_make, bgp_tip_hash_cmp, NULL);
+}
+
+void bgp_tip_hash_destroy(struct bgp *bgp)
+{
+ if (bgp->tip_hash == NULL)
+ return;
+ hash_clean(bgp->tip_hash, bgp_tip_hash_free);
+ hash_free(bgp->tip_hash);
+ bgp->tip_hash = NULL;
+}
+
+void bgp_tip_add(struct bgp *bgp, struct in_addr *tip)
+{
+ struct tip_addr tmp;
+ struct tip_addr *addr;
+
+ tmp.addr = *tip;
+
+ addr = hash_get(bgp->tip_hash, &tmp, bgp_tip_hash_alloc);
+ if (!addr)
+ return;
+
+ addr->refcnt++;
+}
+
+void bgp_tip_del(struct bgp *bgp, struct in_addr *tip)
+{
+ struct tip_addr tmp;
+ struct tip_addr *addr;
+
+ tmp.addr = *tip;
+
+ addr = hash_lookup(bgp->tip_hash, &tmp);
+ /* may have been deleted earlier by bgp_interface_down() */
+ if (addr == NULL)
+ return;
+
+ addr->refcnt--;
+
+ if (addr->refcnt == 0) {
+ hash_release(bgp->tip_hash, addr);
+ XFREE(MTYPE_TIP_ADDR, addr);
+ }
+}
static void *bgp_address_hash_alloc(void *p)
{
int bgp_nexthop_self(struct bgp *bgp, struct in_addr nh_addr)
{
struct bgp_addr tmp, *addr;
+ struct tip_addr tmp_tip, *tip;
tmp.addr = nh_addr;
if (addr)
return 1;
+ tmp_tip.addr = nh_addr;
+ tip = hash_lookup(bgp->tip_hash, &tmp_tip);
+ if (tip)
+ return 1;
+
return 0;
}
struct bgp *bgp;
};
+/* BGP own address structure */
+struct bgp_addr {
+ struct in_addr addr;
+ int refcnt;
+};
+
+/* Own tunnel-ip address structure */
+struct tip_addr {
+ struct in_addr addr;
+ int refcnt;
+};
+
extern int bgp_nexthop_lookup(afi_t, struct peer *peer, struct bgp_info *,
int *, int *);
extern void bgp_connected_add(struct bgp *bgp, struct connected *c);
extern void bgp_scan_vty_init(void);
extern void bgp_address_init(struct bgp *bgp);
extern void bgp_address_destroy(struct bgp *bgp);
+extern void bgp_tip_add(struct bgp *bgp, struct in_addr *tip);
+extern void bgp_tip_del(struct bgp *bgp, struct in_addr *tip);
+extern void bgp_tip_hash_init(struct bgp *bgp);
+extern void bgp_tip_hash_destroy(struct bgp *bgp);
#endif /* _QUAGGA_BGP_NEXTHOP_H */
evaluate_paths(bnc);
}
+/*
+ * Cleanup nexthop registration and status information for BGP nexthops
+ * pertaining to this VRF. This is invoked upon VRF deletion.
+ */
+void bgp_cleanup_nexthops(struct bgp *bgp)
+{
+ afi_t afi;
+ struct bgp_node *rn;
+ struct bgp_nexthop_cache *bnc;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ if (!bgp->nexthop_cache_table[afi])
+ continue;
+
+ for (rn = bgp_table_top(bgp->nexthop_cache_table[afi]); rn;
+ rn = bgp_route_next(rn)) {
+ bnc = rn->info;
+ if (!bnc)
+ continue;
+
+ /* Clear relevant flags. */
+ UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
+ UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
+ UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
+ }
+ }
+}
+
/**
* make_prefix - make a prefix structure from the path (essentially
* path's node.
*/
extern void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer);
+/*
+ * Cleanup nexthop registration and status information for BGP nexthops
+ * pertaining to this VRF. This is invoked upon VRF deletion.
+ */
+extern void bgp_cleanup_nexthops(struct bgp *bgp);
+
#endif /* _BGP_NHT_H */
as_t local_as;
u_int32_t restart_time;
u_char afi_safi_count = 0;
- struct utsname names;
int adv_addpath_tx = 0;
/* Remember current pointer for Opt Parm Len. */
}
/* Hostname capability */
- uname(&names);
- if (names.nodename[0] != '\0') {
+ if (cmd_hostname_get()) {
SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_ADV);
stream_putc(s, BGP_OPEN_OPT_CAP);
rcapp = stream_get_endp(s); /* Ptr to length placeholder */
stream_putc(s, CAPABILITY_CODE_FQDN);
capp = stream_get_endp(s);
stream_putc(s, 0); /* dummy len for now */
- len = strlen(names.nodename);
+ len = strlen(cmd_hostname_get());
if (len > BGP_MAX_HOSTNAME)
len = BGP_MAX_HOSTNAME;
stream_putc(s, len);
- stream_put(s, names.nodename, len);
-#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME
- if ((names.domainname[0] != '\0')
- && (strcmp(names.domainname, "(none)") != 0)) {
- len = strlen(names.domainname);
+ stream_put(s, cmd_hostname_get(), len);
+ if (cmd_domainname_get()) {
+ len = strlen(cmd_domainname_get());
if (len > BGP_MAX_HOSTNAME)
len = BGP_MAX_HOSTNAME;
stream_putc(s, len);
- stream_put(s, names.domainname, len);
+ stream_put(s, cmd_domainname_get(), len);
} else
-#endif
- {
stream_putc(s, 0); /* 0 length */
- }
/* Set the lengths straight */
len = stream_get_endp(s) - rcapp - 1;
stream_putc_at(s, capp, len);
if (bgp_debug_neighbor_events(peer))
-#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME
zlog_debug(
"%s Sending hostname cap with hn = %s, dn = %s",
- peer->host, names.nodename, names.domainname);
-#else
- zlog_debug("%s Sending hostname cap with hn = %s",
- peer->host, names.nodename);
-#endif
+ peer->host, cmd_hostname_get(),
+ cmd_domainname_get());
}
/* Sending base graceful-restart capability irrespective of the config
/* 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.
+ * necessary to do this upon changes to best path except if the label
+ * index changes
*/
if (bgp->allocate_mpls_labels[afi][safi]) {
if (new_select) {
struct bgp_process_queue *pqnode = data;
struct bgp *bgp = pqnode->bgp;
struct bgp_table *table;
- struct bgp_node *rn, *nrn;
+ struct bgp_node *rn;
/* eoiu marker */
if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER)) {
bgp_process_main_one(bgp, NULL, 0, 0);
-
+ /* should always have dedicated wq call */
+ assert(STAILQ_FIRST(&pqnode->pqueue) == NULL);
return WQ_SUCCESS;
}
- STAILQ_FOREACH_SAFE(rn, &pqnode->pqueue, pq, nrn) {
+ while (!STAILQ_EMPTY(&pqnode->pqueue)) {
+ rn = STAILQ_FIRST(&pqnode->pqueue);
+ STAILQ_REMOVE_HEAD(&pqnode->pqueue, pq);
+ STAILQ_NEXT(rn, pq) = NULL; /* complete unlink */
table = bgp_node_table(rn);
-
+ /* note, new RNs may be added as part of processing */
bgp_process_main_one(bgp, rn, table->afi, table->safi);
bgp_unlock_node(rn);
bm->process_main_queue->spec.yield = 50 * 1000L;
}
-static struct bgp_process_queue *bgp_process_queue_work(struct work_queue *wq,
- struct bgp *bgp)
+static struct bgp_process_queue *bgp_processq_alloc(struct bgp *bgp)
{
struct bgp_process_queue *pqnode;
pqnode->bgp = bgp_lock(bgp);
STAILQ_INIT(&pqnode->pqueue);
- work_queue_add(wq, pqnode);
-
return pqnode;
}
#define ARBITRARY_PROCESS_QLEN 10000
struct work_queue *wq = bm->process_main_queue;
struct bgp_process_queue *pqnode;
+ int pqnode_reuse = 0;
/* already scheduled for processing? */
if (CHECK_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED))
if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) ||
pqnode->bgp != bgp || pqnode->queued >= ARBITRARY_PROCESS_QLEN)
- pqnode = bgp_process_queue_work(wq, bgp);
+ pqnode = bgp_processq_alloc(bgp);
+ else
+ pqnode_reuse = 1;
} else
- pqnode = bgp_process_queue_work(wq, bgp);
-
+ pqnode = bgp_processq_alloc(bgp);
/* all unlocked in bgp_process_wq */
bgp_table_lock(bgp_node_table(rn));
SET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED);
bgp_lock_node(rn);
+ /* can't be enqueued twice */
+ assert(STAILQ_NEXT(rn, pq) == NULL);
STAILQ_INSERT_TAIL(&pqnode->pqueue, rn, pq);
pqnode->queued++;
+ if (!pqnode_reuse)
+ work_queue_add(wq, pqnode);
+
return;
}
if (bm->process_main_queue == NULL)
return;
- pqnode = bgp_process_queue_work(bm->process_main_queue, bgp);
+ pqnode = bgp_processq_alloc(bgp);
SET_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER);
+ work_queue_add(bm->process_main_queue, pqnode);
}
static int bgp_maximum_prefix_restart_timer(struct thread *thread)
/* Unconditionally remove the route from the RIB, without taking
* damping into consideration (eg, because the session went down)
*/
-static void bgp_rib_remove(struct bgp_node *rn, struct bgp_info *ri,
- struct peer *peer, afi_t afi, safi_t safi)
+void bgp_rib_remove(struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,
+ afi_t afi, safi_t safi)
{
bgp_aggregate_decrement(peer->bgp, &rn->p, ri, afi, safi);
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
for (ain = rn->adj_in; ain; ain = ain->next) {
- if (ain->peer == peer) {
- struct bgp_info *ri = rn->info;
- mpls_label_t label =
- (ri && ri->extra) ? ri->extra->label
- : MPLS_INVALID_LABEL;
+ if (ain->peer != peer)
+ continue;
- ret = bgp_update(
- peer, &rn->p, ain->addpath_rx_id,
- ain->attr, afi, safi, ZEBRA_ROUTE_BGP,
- BGP_ROUTE_NORMAL, prd, &label, 1, NULL);
+ struct bgp_info *ri = rn->info;
+ mpls_label_t label = (ri && ri->extra)
+ ? ri->extra->label
+ : MPLS_INVALID_LABEL;
- if (ret < 0) {
- bgp_unlock_node(rn);
- return;
- }
+ ret = bgp_update(peer, &rn->p, ain->addpath_rx_id,
+ ain->attr, afi, safi, ZEBRA_ROUTE_BGP,
+ BGP_ROUTE_NORMAL, prd, &label, 1,
+ NULL);
+
+ if (ret < 0) {
+ bgp_unlock_node(rn);
+ return;
}
}
}
/* It is possible that we have multiple paths for a prefix from a peer
* if that peer is using AddPath.
*/
- for (ri = rn->info; ri; ri = ri->next)
- if (ri->peer == peer) {
- /* graceful restart STALE flag set. */
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)
- && peer->nsf[afi][safi]
- && !CHECK_FLAG(ri->flags, BGP_INFO_STALE)
- && !CHECK_FLAG(ri->flags, BGP_INFO_UNUSEABLE))
- bgp_info_set_flag(rn, ri, BGP_INFO_STALE);
- else {
- /* If this is an EVPN route, process for
- * un-import. */
- if (safi == SAFI_EVPN)
- bgp_evpn_unimport_route(peer->bgp, afi,
- safi, &rn->p,
- ri);
- bgp_rib_remove(rn, ri, peer, afi, safi);
- }
+ for (ri = rn->info; ri; ri = ri->next) {
+ if (ri->peer != peer)
+ continue;
+
+ /* graceful restart STALE flag set. */
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)
+ && peer->nsf[afi][safi]
+ && !CHECK_FLAG(ri->flags, BGP_INFO_STALE)
+ && !CHECK_FLAG(ri->flags, BGP_INFO_UNUSEABLE))
+ bgp_info_set_flag(rn, ri, BGP_INFO_STALE);
+ else {
+ /* If this is an EVPN route, process for
+ * un-import. */
+ if (safi == SAFI_EVPN)
+ bgp_evpn_unimport_route(peer->bgp, afi, safi,
+ &rn->p, ri);
+ bgp_rib_remove(rn, ri, peer, afi, safi);
}
+ }
return WQ_SUCCESS;
}
struct bgp_info *ri;
/* look for neighbor in tables */
- if ((table = rn->info) != NULL) {
- for (rm = bgp_table_top(table); rm;
- rm = bgp_route_next(rm))
- for (ri = rm->info; ri; ri = ri->next)
- if (ri->peer == peer) {
- if (CHECK_FLAG(
- ri->flags,
- BGP_INFO_STALE))
- bgp_rib_remove(
- rm, ri,
- peer,
- afi,
- safi);
- break;
- }
- }
+ if ((table = rn->info) == NULL)
+ continue;
+
+ for (rm = bgp_table_top(table); rm;
+ rm = bgp_route_next(rm))
+ for (ri = rm->info; ri; ri = ri->next) {
+ if (ri->peer != peer)
+ continue;
+ if (!CHECK_FLAG(ri->flags,
+ BGP_INFO_STALE))
+ break;
+
+ bgp_rib_remove(rm, ri, peer, afi, safi);
+ break;
+ }
}
} else {
for (rn = bgp_table_top(peer->bgp->rib[afi][safi]); rn;
rn = bgp_route_next(rn))
- for (ri = rn->info; ri; ri = ri->next)
- if (ri->peer == peer) {
- if (CHECK_FLAG(ri->flags,
- BGP_INFO_STALE))
- bgp_rib_remove(rn, ri, peer,
- afi, safi);
+ for (ri = rn->info; ri; ri = ri->next) {
+ if (ri->peer != peer)
+ continue;
+ if (!CHECK_FLAG(ri->flags, BGP_INFO_STALE))
break;
- }
+ bgp_rib_remove(rn, ri, peer, afi, safi);
+ break;
+ }
}
}
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
for (rn = bgp_table_top(bgp->route[afi][safi]); rn;
- rn = bgp_route_next(rn))
- if (rn->info != NULL) {
- if ((safi == SAFI_MPLS_VPN)
- || (safi == SAFI_ENCAP)
- || (safi == SAFI_EVPN)) {
- table = rn->info;
-
- for (rm = bgp_table_top(table);
- rm;
- rm = bgp_route_next(rm)) {
- bgp_static = rm->info;
- bgp_static_update_safi(
- bgp, &rm->p,
- bgp_static, afi,
- safi);
- }
- } else {
- bgp_static_update(bgp, &rn->p,
- rn->info, afi,
- safi);
+ rn = bgp_route_next(rn)) {
+ if (rn->info == NULL)
+ continue;
+
+ if ((safi == SAFI_MPLS_VPN)
+ || (safi == SAFI_ENCAP)
+ || (safi == SAFI_EVPN)) {
+ table = rn->info;
+
+ for (rm = bgp_table_top(table); rm;
+ rm = bgp_route_next(rm)) {
+ bgp_static = rm->info;
+ bgp_static_update_safi(
+ bgp, &rm->p, bgp_static,
+ afi, safi);
}
+ } else {
+ bgp_static_update(bgp, &rn->p, rn->info,
+ afi, safi);
}
+ }
}
/* Called from bgp_delete(). Delete all static routes from the BGP
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
for (rn = bgp_table_top(bgp->route[afi][safi]); rn;
- rn = bgp_route_next(rn))
- if (rn->info != NULL) {
- if ((safi == SAFI_MPLS_VPN)
- || (safi == SAFI_ENCAP)
- || (safi == SAFI_EVPN)) {
- table = rn->info;
-
- for (rm = bgp_table_top(table);
- rm;
- rm = bgp_route_next(rm)) {
- bgp_static = rm->info;
- bgp_static_withdraw_safi(
- bgp, &rm->p,
- AFI_IP, safi,
- (struct
- prefix_rd *)&rn
- ->p);
- bgp_static_free(
- bgp_static);
- rn->info = NULL;
- bgp_unlock_node(rn);
- }
- } else {
- bgp_static = rn->info;
- bgp_static_withdraw(bgp, &rn->p,
- afi, safi);
+ rn = bgp_route_next(rn)) {
+ if (rn->info == NULL)
+ continue;
+
+ if ((safi == SAFI_MPLS_VPN)
+ || (safi == SAFI_ENCAP)
+ || (safi == SAFI_EVPN)) {
+ table = rn->info;
+
+ for (rm = bgp_table_top(table); rm;
+ rm = bgp_route_next(rm)) {
+ bgp_static = rm->info;
+ bgp_static_withdraw_safi(
+ bgp, &rm->p, AFI_IP,
+ safi,
+ (struct prefix_rd *)&rn
+ ->p);
bgp_static_free(bgp_static);
rn->info = NULL;
bgp_unlock_node(rn);
}
+ } else {
+ bgp_static = rn->info;
+ bgp_static_withdraw(bgp, &rn->p, afi,
+ safi);
+ bgp_static_free(bgp_static);
+ rn->info = NULL;
+ bgp_unlock_node(rn);
}
+ }
}
void bgp_static_redo_import_check(struct bgp *bgp)
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
for (rn = bgp_table_top(bgp->route[afi][safi]); rn;
- rn = bgp_route_next(rn))
- if (rn->info != NULL) {
- if ((safi == SAFI_MPLS_VPN)
- || (safi == SAFI_ENCAP)
- || (safi == SAFI_EVPN)) {
- table = rn->info;
-
- for (rm = bgp_table_top(table);
- rm;
- rm = bgp_route_next(rm)) {
- bgp_static = rm->info;
- bgp_static_update_safi(
- bgp, &rm->p,
- bgp_static, afi,
- safi);
- }
- } else {
- bgp_static = rn->info;
- bgp_static_update(bgp, &rn->p,
- bgp_static,
- afi, safi);
+ rn = bgp_route_next(rn)) {
+ if (rn->info == NULL)
+ continue;
+
+ if ((safi == SAFI_MPLS_VPN)
+ || (safi == SAFI_ENCAP)
+ || (safi == SAFI_EVPN)) {
+ table = rn->info;
+
+ for (rm = bgp_table_top(table); rm;
+ rm = bgp_route_next(rm)) {
+ bgp_static = rm->info;
+ bgp_static_update_safi(
+ bgp, &rm->p, bgp_static,
+ afi, safi);
}
+ } else {
+ bgp_static = rn->info;
+ bgp_static_update(bgp, &rn->p,
+ bgp_static, afi,
+ safi);
}
+ }
bgp_flag_unset(bgp, BGP_FLAG_FORCE_STATIC_PROCESS);
}
return CMD_SUCCESS;
}
-int bgp_config_write_table_map(struct vty *vty, struct bgp *bgp, afi_t afi,
- safi_t safi, int *write)
+void bgp_config_write_table_map(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi)
{
if (bgp->table_map[afi][safi].name) {
- bgp_config_write_family_header(vty, afi, safi, write);
vty_out(vty, " table-map %s\n",
bgp->table_map[afi][safi].name);
}
-
- return 0;
}
DEFUN (bgp_table_map,
/* If routes exists below this node, generate aggregate routes. */
top = bgp_node_get(table, p);
for (rn = bgp_node_get(table, p); rn;
- rn = bgp_route_next_until(rn, top))
- if (rn->p.prefixlen > p->prefixlen) {
- match = 0;
+ rn = bgp_route_next_until(rn, top)) {
+ if (rn->p.prefixlen <= p->prefixlen)
+ continue;
- for (ri = rn->info; ri; ri = ri->next) {
- if (BGP_INFO_HOLDDOWN(ri))
- continue;
+ match = 0;
- if (ri->attr->flag
- & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))
- atomic_aggregate = 1;
+ for (ri = rn->info; ri; ri = ri->next) {
+ if (BGP_INFO_HOLDDOWN(ri))
+ continue;
- if (ri->sub_type != BGP_ROUTE_AGGREGATE) {
- /* summary-only aggregate route suppress
- aggregated
- route announcement. */
- if (aggregate->summary_only) {
- (bgp_info_extra_get(ri))
- ->suppress++;
- bgp_info_set_flag(
- rn, ri,
- BGP_INFO_ATTR_CHANGED);
- match++;
- }
+ if (ri->attr->flag
+ & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))
+ atomic_aggregate = 1;
- /* If at least one route among routes
- * that are aggregated has
- * ORIGIN with the value INCOMPLETE,
- * then the aggregated route
- * MUST have the ORIGIN attribute with
- * the value INCOMPLETE.
- * Otherwise, if at least one route
- * among routes that are
- * aggregated has ORIGIN with the value
- * EGP, then the aggregated
- * route MUST have the ORIGIN attribute
- * with the value EGP.
- */
- if (origin < ri->attr->origin)
- origin = ri->attr->origin;
+ if (ri->sub_type == BGP_ROUTE_AGGREGATE)
+ continue;
- /* as-set aggregate route generate
- origin, as path,
- community aggregation. */
- if (aggregate->as_set) {
- if (aspath) {
- asmerge = aspath_aggregate(
- aspath,
- ri->attr->aspath);
- aspath_free(aspath);
- aspath = asmerge;
- } else
- aspath = aspath_dup(
- ri->attr->aspath);
+ /* summary-only aggregate route suppress
+ * aggregated route announcement. */
+ if (aggregate->summary_only) {
+ (bgp_info_extra_get(ri))->suppress++;
+ bgp_info_set_flag(rn, ri,
+ BGP_INFO_ATTR_CHANGED);
+ match++;
+ }
- if (ri->attr->community) {
- if (community) {
- commerge = community_merge(
- community,
- ri->attr->community);
- community = community_uniq_sort(
- commerge);
- community_free(
- commerge);
- } else
- community = community_dup(
- ri->attr->community);
- }
- }
- aggregate->count++;
+ /* If at least one route among routes that are
+ * aggregated has ORIGIN with the value INCOMPLETE,
+ * then the aggregated route MUST have the ORIGIN
+ * attribute with the value INCOMPLETE. Otherwise, if
+ * at least one route among routes that are aggregated
+ * has ORIGIN with the value EGP, then the aggregated
+ * route MUST have the ORIGIN attribute with the value
+ * EGP.
+ */
+ if (origin < ri->attr->origin)
+ origin = ri->attr->origin;
+
+ /* as-set aggregate route generate origin, as path,
+ * community aggregation. */
+ if (aggregate->as_set) {
+ if (aspath) {
+ asmerge = aspath_aggregate(
+ aspath, ri->attr->aspath);
+ aspath_free(aspath);
+ aspath = asmerge;
+ } else
+ aspath = aspath_dup(ri->attr->aspath);
+
+ if (ri->attr->community) {
+ if (community) {
+ commerge = community_merge(
+ community,
+ ri->attr->community);
+ community = community_uniq_sort(
+ commerge);
+ community_free(commerge);
+ } else
+ community = community_dup(
+ ri->attr->community);
}
}
-
- /* If this node is suppressed, process the change. */
- if (match)
- bgp_process(bgp, rn, afi, safi);
+ aggregate->count++;
}
+
+ /* If this node is suppressed, process the change. */
+ if (match)
+ bgp_process(bgp, rn, afi, safi);
+ }
bgp_unlock_node(top);
/* Add aggregate route to BGP table. */
/* If routes exists below this node, generate aggregate routes. */
top = bgp_node_get(table, p);
for (rn = bgp_node_get(table, p); rn;
- rn = bgp_route_next_until(rn, top))
- if (rn->p.prefixlen > p->prefixlen) {
- match = 0;
+ rn = bgp_route_next_until(rn, top)) {
+ if (rn->p.prefixlen <= p->prefixlen)
+ continue;
+ match = 0;
- for (ri = rn->info; ri; ri = ri->next) {
- if (BGP_INFO_HOLDDOWN(ri))
- continue;
+ for (ri = rn->info; ri; ri = ri->next) {
+ if (BGP_INFO_HOLDDOWN(ri))
+ continue;
- if (ri->sub_type != BGP_ROUTE_AGGREGATE) {
- if (aggregate->summary_only
- && ri->extra) {
- ri->extra->suppress--;
-
- if (ri->extra->suppress == 0) {
- bgp_info_set_flag(
- rn, ri,
- BGP_INFO_ATTR_CHANGED);
- match++;
- }
- }
- aggregate->count--;
+ if (ri->sub_type == BGP_ROUTE_AGGREGATE)
+ continue;
+
+ if (aggregate->summary_only && ri->extra) {
+ ri->extra->suppress--;
+
+ if (ri->extra->suppress == 0) {
+ bgp_info_set_flag(
+ rn, ri, BGP_INFO_ATTR_CHANGED);
+ match++;
}
}
-
- /* If this node was suppressed, process the change. */
- if (match)
- bgp_process(bgp, rn, afi, safi);
+ aggregate->count--;
}
+
+ /* If this node was suppressed, process the change. */
+ if (match)
+ bgp_process(bgp, rn, afi, safi);
+ }
bgp_unlock_node(top);
/* Delete aggregate route from BGP table. */
}
/* Static function to display route. */
-static void route_vty_out_route(struct prefix *p, struct vty *vty)
+static void route_vty_out_route(struct prefix *p, struct vty *vty,
+ json_object *json)
{
int len;
u_int32_t destination;
char buf[BUFSIZ];
if (p->family == AF_INET) {
- len = vty_out(vty, "%s",
- inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ));
- destination = ntohl(p->u.prefix4.s_addr);
-
- if ((IN_CLASSC(destination) && p->prefixlen == 24)
- || (IN_CLASSB(destination) && p->prefixlen == 16)
- || (IN_CLASSA(destination) && p->prefixlen == 8)
- || p->u.prefix4.s_addr == 0) {
- /* When mask is natural, mask is not displayed. */
- } else
- len += vty_out(vty, "/%d", p->prefixlen);
+ if (!json) {
+ len = vty_out(vty, "%s",
+ inet_ntop(p->family, &p->u.prefix, buf,
+ BUFSIZ));
+ destination = ntohl(p->u.prefix4.s_addr);
+
+ if ((IN_CLASSC(destination) && p->prefixlen == 24)
+ || (IN_CLASSB(destination) && p->prefixlen == 16)
+ || (IN_CLASSA(destination) && p->prefixlen == 8)
+ || p->u.prefix4.s_addr == 0) {
+ /* When mask is natural,
+ mask is not displayed. */
+ } else
+ len += vty_out(vty, "/%d", p->prefixlen);
+ } else {
+ json_object_string_add(json, "prefix",
+ inet_ntop(p->family,
+ &p->u.prefix, buf,
+ BUFSIZ));
+ json_object_int_add(json, "prefixLen", p->prefixlen);
+ }
} else if (p->family == AF_ETHERNET) {
prefix2str(p, buf, PREFIX_STRLEN);
len = vty_out(vty, "%s", buf);
} else if (p->family == AF_EVPN) {
#if defined(HAVE_CUMULUS)
- len = vty_out(vty, "%s",
- bgp_evpn_route2str((struct prefix_evpn *)p, buf,
- BUFSIZ));
+ if (!json)
+ len = vty_out(
+ vty, "%s",
+ bgp_evpn_route2str((struct prefix_evpn *)p, buf,
+ BUFSIZ));
+ else
+ bgp_evpn_route2json((struct prefix_evpn *)p, json);
#else
prefix2str(p, buf, PREFIX_STRLEN);
len = vty_out(vty, "%s", buf);
#endif
- } else
- len = vty_out(vty, "%s/%d",
- inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
- p->prefixlen);
+ } else {
+ if (!json)
+ len = vty_out(
+ vty, "%s/%d",
+ inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
+ p->prefixlen);
+ }
- len = 17 - len;
- if (len < 1)
- vty_out(vty, "\n%*s", 20, " ");
- else
- vty_out(vty, "%*s", len, " ");
+ if (!json) {
+ len = 17 - len;
+ if (len < 1)
+ vty_out(vty, "\n%*s", 20, " ");
+ else
+ vty_out(vty, "%*s", len, " ");
+ }
}
enum bgp_display_type {
if (!json_paths) {
/* print prefix and mask */
if (!display)
- route_vty_out_route(p, vty);
+ route_vty_out_route(p, vty, json_path);
else
vty_out(vty, "%*s", 17, " ");
+ } else {
+ route_vty_out_route(p, vty, json_path);
}
/* Print attribute */
json_net, "addrPrefix",
inet_ntop(p->family, &p->u.prefix, buff, BUFSIZ));
else
- route_vty_out_route(p, vty);
+ route_vty_out_route(p, vty, NULL);
/* Print attribute */
if (attr) {
/* print prefix and mask */
if (json == NULL) {
if (!display)
- route_vty_out_route(p, vty);
+ route_vty_out_route(p, vty, NULL);
else
vty_out(vty, "%*s", 17, " ");
}
/* print prefix and mask */
if (!display)
- route_vty_out_route(p, vty);
+ route_vty_out_route(p, vty, NULL);
else
vty_out(vty, "%*s", 17, " ");
/* print prefix and mask */
if (!use_json) {
if (!display)
- route_vty_out_route(p, vty);
+ route_vty_out_route(p, vty, NULL);
else
vty_out(vty, "%*s", 17, " ");
}
/* print prefix and mask */
if (!use_json) {
if (!display)
- route_vty_out_route(p, vty);
+ route_vty_out_route(p, vty, NULL);
else
vty_out(vty, "%*s", 17, " ");
}
#if defined(HAVE_CUMULUS)
char buf3[EVPN_ROUTE_STRLEN];
#endif
+ char prefix_str[BUFSIZ];
int count = 0;
int best = 0;
int suppress = 0;
if (has_valid_label)
json_object_int_add(json, "localLabel", label);
- json_object_string_add(json, "prefix",
- inet_ntop(p->family, &p->u.prefix, buf2,
- INET6_ADDRSTRLEN));
- json_object_int_add(json, "prefixlen", p->prefixlen);
+ json_object_string_add(
+ json, "prefix",
+ prefix2str(p, prefix_str, sizeof(prefix_str)));
} else {
#if defined(HAVE_CUMULUS)
if (safi == SAFI_EVPN)
if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
continue;
- if ((table = rn->info) != NULL) {
- header = 1;
-
- if ((rm = bgp_node_match(table, &match))
- != NULL) {
- if (prefix_check
- && rm->p.prefixlen
- != match.prefixlen) {
- bgp_unlock_node(rm);
- continue;
- }
+ if ((table = rn->info) == NULL)
+ continue;
- for (ri = rm->info; ri; ri = ri->next) {
- if (header) {
- route_vty_out_detail_header(
- vty, bgp, rm,
- (struct
- prefix_rd *)&rn
- ->p,
- AFI_IP, safi,
- json);
- header = 0;
- }
- display++;
-
- if (pathtype == BGP_PATH_ALL
- || (pathtype
- == BGP_PATH_BESTPATH
- && CHECK_FLAG(
- ri->flags,
- BGP_INFO_SELECTED))
- || (pathtype
- == BGP_PATH_MULTIPATH
- && (CHECK_FLAG(
- ri->flags,
- BGP_INFO_MULTIPATH)
- || CHECK_FLAG(
- ri->flags,
- BGP_INFO_SELECTED))))
- route_vty_out_detail(
- vty, bgp,
- &rm->p, ri,
- AFI_IP, safi,
- json_paths);
- }
+ header = 1;
+
+ if ((rm = bgp_node_match(table, &match)) == NULL)
+ continue;
+
+ if (prefix_check
+ && rm->p.prefixlen != match.prefixlen) {
+ bgp_unlock_node(rm);
+ continue;
+ }
- bgp_unlock_node(rm);
+ for (ri = rm->info; ri; ri = ri->next) {
+ if (header) {
+ route_vty_out_detail_header(
+ vty, bgp, rm,
+ (struct prefix_rd *)&rn->p,
+ AFI_IP, safi, json);
+ header = 0;
}
+ display++;
+
+ if (pathtype == BGP_PATH_ALL
+ || (pathtype == BGP_PATH_BESTPATH
+ && CHECK_FLAG(ri->flags,
+ BGP_INFO_SELECTED))
+ || (pathtype == BGP_PATH_MULTIPATH
+ && (CHECK_FLAG(ri->flags,
+ BGP_INFO_MULTIPATH)
+ || CHECK_FLAG(ri->flags,
+ BGP_INFO_SELECTED))))
+ route_vty_out_detail(vty, bgp, &rm->p,
+ ri, AFI_IP, safi,
+ json_paths);
}
+
+ bgp_unlock_node(rm);
}
} else {
header = 1;
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
if (in) {
for (ain = rn->adj_in; ain; ain = ain->next) {
- if (ain->peer == peer) {
- if (header1) {
- if (use_json) {
- json_object_int_add(
- json,
- "bgpTableVersion",
- 0);
- json_object_string_add(
- json,
- "bgpLocalRouterId",
- inet_ntoa(
- bgp->router_id));
- json_object_object_add(
- json,
- "bgpStatusCodes",
- json_scode);
- json_object_object_add(
- json,
- "bgpOriginCodes",
- json_ocode);
- } else {
- vty_out(vty,
- "BGP table version is 0, local router ID is %s\n",
- inet_ntoa(
- bgp->router_id));
- vty_out(vty,
- BGP_SHOW_SCODE_HEADER);
- vty_out(vty,
- BGP_SHOW_OCODE_HEADER);
- }
- header1 = 0;
- }
- if (header2) {
- if (!use_json)
- vty_out(vty,
- BGP_SHOW_HEADER);
- header2 = 0;
- }
- if (ain->attr) {
- bgp_attr_dup(&attr, ain->attr);
- if (bgp_input_modifier(
- peer, &rn->p, &attr,
- afi, safi,
- rmap_name)
- != RMAP_DENY) {
- route_vty_out_tmp(
- vty, &rn->p,
- &attr, safi,
- use_json,
- json_ar);
- output_count++;
- } else
- filtered_count++;
+ if (ain->peer != peer)
+ continue;
+ if (header1) {
+ if (use_json) {
+ json_object_int_add(
+ json, "bgpTableVersion",
+ 0);
+ json_object_string_add(
+ json,
+ "bgpLocalRouterId",
+ inet_ntoa(
+ bgp->router_id));
+ json_object_object_add(
+ json, "bgpStatusCodes",
+ json_scode);
+ json_object_object_add(
+ json, "bgpOriginCodes",
+ json_ocode);
+ } else {
+ vty_out(vty,
+ "BGP table version is 0, local router ID is %s\n",
+ inet_ntoa(
+ bgp->router_id));
+ vty_out(vty,
+ BGP_SHOW_SCODE_HEADER);
+ vty_out(vty,
+ BGP_SHOW_OCODE_HEADER);
}
+ header1 = 0;
+ }
+ if (header2) {
+ if (!use_json)
+ vty_out(vty, BGP_SHOW_HEADER);
+ header2 = 0;
+ }
+ if (ain->attr) {
+ bgp_attr_dup(&attr, ain->attr);
+ if (bgp_input_modifier(peer, &rn->p,
+ &attr, afi, safi,
+ rmap_name)
+ != RMAP_DENY) {
+ route_vty_out_tmp(vty, &rn->p,
+ &attr, safi,
+ use_json,
+ json_ar);
+ output_count++;
+ } else
+ filtered_count++;
}
}
} else {
return CMD_WARNING;
}
- /* labeled-unicast routes live in the unicast table */
- if (safi == SAFI_LABELED_UNICAST)
- safi = SAFI_UNICAST;
-
return bgp_show(vty, peer->bgp, afi, safi, type, &peer->su, use_json);
}
rn = bgp_route_next(rn)) {
if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
continue;
+ if ((table = rn->info) == NULL)
+ continue;
+ if ((rm = bgp_node_match(table, &match)) == NULL)
+ continue;
- if ((table = rn->info) != NULL)
- if ((rm = bgp_node_match(table, &match))
- != NULL) {
- if (!prefix_check
- || rm->p.prefixlen
- == match.prefixlen) {
- ri = rm->info;
- while (ri) {
- if (ri->extra
- && ri->extra
- ->damp_info) {
- ri_temp =
- ri->next;
- bgp_damp_info_free(
- ri->extra
- ->damp_info,
- 1);
- ri = ri_temp;
- } else
- ri = ri->next;
- }
- }
-
- bgp_unlock_node(rm);
+ if (!prefix_check
+ || rm->p.prefixlen == match.prefixlen) {
+ ri = rm->info;
+ while (ri) {
+ if (ri->extra && ri->extra->damp_info) {
+ ri_temp = ri->next;
+ bgp_damp_info_free(
+ ri->extra->damp_info,
+ 1);
+ ri = ri_temp;
+ } else
+ ri = ri->next;
}
+ }
+
+ bgp_unlock_node(rm);
}
} else {
if ((rn = bgp_node_match(bgp->rib[afi][safi], &match))
}
/* also used for encap safi */
-static int bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp,
- afi_t afi, safi_t safi, int *write)
+static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp,
+ afi_t afi, safi_t safi)
{
struct bgp_node *prn;
struct bgp_node *rn;
/* Network configuration. */
for (prn = bgp_table_top(bgp->route[afi][safi]); prn;
- prn = bgp_route_next(prn))
- if ((table = prn->info) != NULL)
- for (rn = bgp_table_top(table); rn;
- rn = bgp_route_next(rn))
- if ((bgp_static = rn->info) != NULL) {
- p = &rn->p;
- prd = (struct prefix_rd *)&prn->p;
+ prn = bgp_route_next(prn)) {
+ if ((table = prn->info) == NULL)
+ continue;
- /* "address-family" display. */
- bgp_config_write_family_header(
- vty, afi, safi, write);
+ for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+ if ((bgp_static = rn->info) == NULL)
+ continue;
- /* "network" configuration display. */
- prefix_rd2str(prd, rdbuf,
- RD_ADDRSTRLEN);
- label = decode_label(
- &bgp_static->label);
+ p = &rn->p;
+ prd = (struct prefix_rd *)&prn->p;
- vty_out(vty, " network %s/%d rd %s",
- inet_ntop(p->family,
- &p->u.prefix, buf,
- SU_ADDRSTRLEN),
- p->prefixlen, rdbuf);
- if (safi == SAFI_MPLS_VPN)
- vty_out(vty, " label %u",
- label);
-
- if (bgp_static->rmap.name)
- vty_out(vty, " route-map %s",
- bgp_static->rmap.name);
- else {
- if (bgp_static->backdoor)
- vty_out(vty,
- " backdoor");
- }
- vty_out(vty, "\n");
- }
- return 0;
+ /* "network" configuration display. */
+ prefix_rd2str(prd, rdbuf, RD_ADDRSTRLEN);
+ label = decode_label(&bgp_static->label);
+
+ vty_out(vty, " network %s/%d rd %s",
+ inet_ntop(p->family, &p->u.prefix, buf,
+ SU_ADDRSTRLEN),
+ p->prefixlen, rdbuf);
+ if (safi == SAFI_MPLS_VPN)
+ vty_out(vty, " label %u", label);
+
+ if (bgp_static->rmap.name)
+ vty_out(vty, " route-map %s",
+ bgp_static->rmap.name);
+ else {
+ if (bgp_static->backdoor)
+ vty_out(vty, " backdoor");
+ }
+ vty_out(vty, "\n");
+ }
+ }
}
-static int bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
- afi_t afi, safi_t safi, int *write)
+static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
+ afi_t afi, safi_t safi)
{
struct bgp_node *prn;
struct bgp_node *rn;
/* Network configuration. */
for (prn = bgp_table_top(bgp->route[afi][safi]); prn;
- prn = bgp_route_next(prn))
- if ((table = prn->info) != NULL)
- for (rn = bgp_table_top(table); rn;
- rn = bgp_route_next(rn))
- if ((bgp_static = rn->info) != NULL) {
- char *macrouter = NULL;
- char *esi = NULL;
-
- if (bgp_static->router_mac)
- macrouter = prefix_mac2str(
- bgp_static->router_mac,
- NULL, 0);
- if (bgp_static->eth_s_id)
- esi = esi2str(
- bgp_static->eth_s_id);
- p = &rn->p;
- prd = (struct prefix_rd *)&prn->p;
+ prn = bgp_route_next(prn)) {
+ if ((table = prn->info) == NULL)
+ continue;
- /* "address-family" display. */
- bgp_config_write_family_header(
- vty, afi, safi, write);
+ for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+ if ((bgp_static = rn->info) == NULL)
+ continue;
- /* "network" configuration display. */
- prefix_rd2str(prd, rdbuf,
- RD_ADDRSTRLEN);
+ char *macrouter = NULL;
+ char *esi = NULL;
- inet_ntop(AF_INET,
- &bgp_static->igpnexthop, buf2,
- SU_ADDRSTRLEN);
+ if (bgp_static->router_mac)
+ macrouter = prefix_mac2str(
+ bgp_static->router_mac, NULL, 0);
+ if (bgp_static->eth_s_id)
+ esi = esi2str(bgp_static->eth_s_id);
+ p = &rn->p;
+ prd = (struct prefix_rd *)&prn->p;
- prefix2str(p, buf, sizeof(buf)),
- vty_out(vty,
- " network %s rd %s ethtag %u tag %u esi %s gwip %s routermac %s",
- buf, rdbuf,
- p->u.prefix_evpn
- .eth_tag,
- decode_label(
- &bgp_static
- ->label),
- esi, buf2, macrouter);
- vty_out(vty, "\n");
- if (macrouter)
- XFREE(MTYPE_TMP, macrouter);
- if (esi)
- XFREE(MTYPE_TMP, esi);
- }
- return 0;
+ /* "network" configuration display. */
+ prefix_rd2str(prd, rdbuf, RD_ADDRSTRLEN);
+
+ inet_ntop(AF_INET, &bgp_static->igpnexthop, buf2,
+ SU_ADDRSTRLEN);
+
+ prefix2str(p, buf, sizeof(buf));
+ vty_out(vty,
+ " network %s rd %s ethtag %u tag %u esi %s gwip %s routermac %s\n",
+ buf, rdbuf, p->u.prefix_evpn.eth_tag,
+ decode_label(&bgp_static->label), esi, buf2,
+ macrouter);
+
+ if (macrouter)
+ XFREE(MTYPE_TMP, macrouter);
+ if (esi)
+ XFREE(MTYPE_TMP, esi);
+ }
+ }
}
/* Configuration of static route announcement and aggregate
information. */
-int bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
- safi_t safi, int *write)
+void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi)
{
struct bgp_node *rn;
struct prefix *p;
struct bgp_aggregate *bgp_aggregate;
char buf[SU_ADDRSTRLEN];
- if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
- return bgp_config_write_network_vpn(vty, bgp, afi, safi, write);
+ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) {
+ bgp_config_write_network_vpn(vty, bgp, afi, safi);
+ return;
+ }
- if (afi == AFI_L2VPN && safi == SAFI_EVPN)
- return bgp_config_write_network_evpn(vty, bgp, afi, safi,
- write);
+ if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
+ bgp_config_write_network_evpn(vty, bgp, afi, safi);
+ return;
+ }
/* Network configuration. */
for (rn = bgp_table_top(bgp->route[afi][safi]); rn;
- rn = bgp_route_next(rn))
- if ((bgp_static = rn->info) != NULL) {
- p = &rn->p;
+ rn = bgp_route_next(rn)) {
+ if ((bgp_static = rn->info) == NULL)
+ continue;
- /* "address-family" display. */
- bgp_config_write_family_header(vty, afi, safi, write);
+ p = &rn->p;
- /* "network" configuration display. */
- if (bgp_option_check(BGP_OPT_CONFIG_CISCO)
- && afi == AFI_IP) {
- u_int32_t destination;
- struct in_addr netmask;
-
- destination = ntohl(p->u.prefix4.s_addr);
- masklen2ip(p->prefixlen, &netmask);
- vty_out(vty, " network %s",
- inet_ntop(p->family, &p->u.prefix, buf,
- SU_ADDRSTRLEN));
-
- if ((IN_CLASSC(destination)
- && p->prefixlen == 24)
- || (IN_CLASSB(destination)
- && p->prefixlen == 16)
- || (IN_CLASSA(destination)
- && p->prefixlen == 8)
- || p->u.prefix4.s_addr == 0) {
- /* Natural mask is not display. */
- } else
- vty_out(vty, " mask %s",
- inet_ntoa(netmask));
- } else {
- vty_out(vty, " network %s/%d",
- inet_ntop(p->family, &p->u.prefix, buf,
- SU_ADDRSTRLEN),
- p->prefixlen);
- }
+ /* "network" configuration display. */
+ if (bgp_option_check(BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) {
+ u_int32_t destination;
+ struct in_addr netmask;
- if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX)
- vty_out(vty, " label-index %u",
- bgp_static->label_index);
+ destination = ntohl(p->u.prefix4.s_addr);
+ masklen2ip(p->prefixlen, &netmask);
+ vty_out(vty, " network %s",
+ inet_ntop(p->family, &p->u.prefix, buf,
+ SU_ADDRSTRLEN));
- if (bgp_static->rmap.name)
- vty_out(vty, " route-map %s",
- bgp_static->rmap.name);
- else {
- if (bgp_static->backdoor)
- vty_out(vty, " backdoor");
- }
+ if ((IN_CLASSC(destination) && p->prefixlen == 24)
+ || (IN_CLASSB(destination) && p->prefixlen == 16)
+ || (IN_CLASSA(destination) && p->prefixlen == 8)
+ || p->u.prefix4.s_addr == 0) {
+ /* Natural mask is not display. */
+ } else
+ vty_out(vty, " mask %s", inet_ntoa(netmask));
+ } else {
+ vty_out(vty, " network %s/%d",
+ inet_ntop(p->family, &p->u.prefix, buf,
+ SU_ADDRSTRLEN),
+ p->prefixlen);
+ }
- vty_out(vty, "\n");
+ 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 {
+ if (bgp_static->backdoor)
+ vty_out(vty, " backdoor");
}
+ vty_out(vty, "\n");
+ }
+
/* Aggregate-address configuration. */
for (rn = bgp_table_top(bgp->aggregate[afi][safi]); rn;
- rn = bgp_route_next(rn))
- if ((bgp_aggregate = rn->info) != NULL) {
- p = &rn->p;
+ rn = bgp_route_next(rn)) {
+ if ((bgp_aggregate = rn->info) == NULL)
+ continue;
- /* "address-family" display. */
- bgp_config_write_family_header(vty, afi, safi, write);
+ p = &rn->p;
- if (bgp_option_check(BGP_OPT_CONFIG_CISCO)
- && afi == AFI_IP) {
- struct in_addr netmask;
+ if (bgp_option_check(BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) {
+ struct in_addr netmask;
- masklen2ip(p->prefixlen, &netmask);
- vty_out(vty, " aggregate-address %s %s",
- inet_ntop(p->family, &p->u.prefix, buf,
- SU_ADDRSTRLEN),
- inet_ntoa(netmask));
- } else {
- vty_out(vty, " aggregate-address %s/%d",
- inet_ntop(p->family, &p->u.prefix, buf,
- SU_ADDRSTRLEN),
- p->prefixlen);
- }
-
- if (bgp_aggregate->as_set)
- vty_out(vty, " as-set");
+ masklen2ip(p->prefixlen, &netmask);
+ vty_out(vty, " aggregate-address %s %s",
+ inet_ntop(p->family, &p->u.prefix, buf,
+ SU_ADDRSTRLEN),
+ inet_ntoa(netmask));
+ } else {
+ vty_out(vty, " aggregate-address %s/%d",
+ inet_ntop(p->family, &p->u.prefix, buf,
+ SU_ADDRSTRLEN),
+ p->prefixlen);
+ }
- if (bgp_aggregate->summary_only)
- vty_out(vty, " summary-only");
+ if (bgp_aggregate->as_set)
+ vty_out(vty, " as-set");
- vty_out(vty, "\n");
- }
+ if (bgp_aggregate->summary_only)
+ vty_out(vty, " summary-only");
- return 0;
+ vty_out(vty, "\n");
+ }
}
-int bgp_config_write_distance(struct vty *vty, struct bgp *bgp, afi_t afi,
- safi_t safi, int *write)
+void bgp_config_write_distance(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi)
{
struct bgp_node *rn;
struct bgp_distance *bdistance;
|| bgp->distance_ibgp[afi][safi] != ZEBRA_IBGP_DISTANCE_DEFAULT
|| bgp->distance_local[afi][safi]
!= ZEBRA_IBGP_DISTANCE_DEFAULT)) {
- bgp_config_write_family_header(vty, afi, safi, write);
vty_out(vty, " distance bgp %d %d %d\n",
bgp->distance_ebgp[afi][safi],
bgp->distance_ibgp[afi][safi],
if ((bdistance = rn->info) != NULL) {
char buf[PREFIX_STRLEN];
- bgp_config_write_family_header(vty, afi, safi, write);
vty_out(vty, " distance %d %s %s\n",
bdistance->distance,
prefix2str(&rn->p, buf, sizeof(buf)),
bdistance->access_list ? bdistance->access_list
: "");
}
-
- return *write;
}
/* Allocate routing table structure and install commands. */
}
/* Prototypes. */
+extern void bgp_rib_remove(struct bgp_node *rn, struct bgp_info *ri,
+ struct peer *peer, afi_t afi, safi_t safi);
extern void bgp_process_queue_init(void);
extern void bgp_route_init(void);
extern void bgp_route_finish(void);
* queue element with NULL bgp node.
*/
extern void bgp_add_eoiu_mark(struct bgp *);
-extern int bgp_config_write_table_map(struct vty *, struct bgp *, afi_t, safi_t,
- int *);
-extern int bgp_config_write_network(struct vty *, struct bgp *, afi_t, safi_t,
- int *);
-extern int bgp_config_write_distance(struct vty *, struct bgp *, afi_t, safi_t,
- int *);
+extern void bgp_config_write_table_map(struct vty *, struct bgp *, afi_t,
+ safi_t);
+extern void bgp_config_write_network(struct vty *, struct bgp *, afi_t, safi_t);
+extern void bgp_config_write_distance(struct vty *, struct bgp *, afi_t,
+ safi_t);
extern void bgp_aggregate_increment(struct bgp *, struct prefix *,
struct bgp_info *, afi_t, safi_t);
return NULL;
*vni = strtoul(arg, &end, 10);
- if (*end != '\0')
+ if (*end != '\0') {
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, vni);
return NULL;
+ }
return vni;
}
const char *arg, route_map_event_t type)
{
VTY_DECLVAR_CONTEXT(route_map_index, index);
+ int retval = CMD_SUCCESS;
int ret;
ret = route_map_add_match(index, command, arg);
- if (ret) {
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% BGP Can't find rule.\n");
- return CMD_WARNING_CONFIG_FAILED;
- case RMAP_COMPILE_ERROR:
- vty_out(vty, "%% BGP Argument is malformed.\n");
- return CMD_WARNING_CONFIG_FAILED;
+ switch (ret) {
+ case RMAP_RULE_MISSING:
+ vty_out(vty, "%% BGP Can't find rule.\n");
+ retval = CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out(vty, "%% BGP Argument is malformed.\n");
+ retval = CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_SUCCESS:
+ if (type != RMAP_EVENT_MATCH_ADDED) {
+ route_map_upd8_dependency(type, arg, index->map->name);
}
+ break;
}
- if (type != RMAP_EVENT_MATCH_ADDED) {
- route_map_upd8_dependency(type, arg, index->map->name);
- }
-
- return CMD_SUCCESS;
+ return retval;
}
/* Delete bgp route map rule. */
{
VTY_DECLVAR_CONTEXT(route_map_index, index);
int ret;
+ int retval = CMD_SUCCESS;
char *dep_name = NULL;
const char *tmpstr;
char *rmap_name = NULL;
}
ret = route_map_delete_match(index, command, dep_name);
- if (ret) {
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% BGP Can't find rule.\n");
- break;
- case RMAP_COMPILE_ERROR:
- vty_out(vty, "%% BGP Argument is malformed.\n");
- break;
- }
- if (dep_name)
- XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
- if (rmap_name)
- XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
- return CMD_WARNING_CONFIG_FAILED;
+ switch (ret) {
+ case RMAP_RULE_MISSING:
+ vty_out(vty, "%% BGP Can't find rule.\n");
+ retval = CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out(vty, "%% BGP Argument is malformed.\n");
+ retval = CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_SUCCESS:
+ if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
+ route_map_upd8_dependency(type, dep_name, rmap_name);
+ break;
}
- if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
- route_map_upd8_dependency(type, dep_name, rmap_name);
-
if (dep_name)
XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
if (rmap_name)
XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
- return CMD_SUCCESS;
+ return retval;
}
/*
return CMD_SUCCESS;
}
-int bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp)
+void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp)
{
if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF) {
vty_out(vty, " update-delay %d", bgp->v_update_delay);
vty_out(vty, " %d", bgp->v_establish_wait);
vty_out(vty, "\n");
}
-
- return 0;
}
return CMD_SUCCESS;
}
-int bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp)
+void bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp)
{
if (bgp->wpkt_quanta != BGP_WRITE_PACKET_MAX)
vty_out(vty, " write-quanta %d\n", bgp->wpkt_quanta);
-
- return 0;
}
return bgp_wpkt_quanta_config_vty(vty, argv[idx_number]->arg, 0);
}
-int bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp)
+void bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp)
{
if (bgp->coalesce_time != BGP_DEFAULT_SUBGROUP_COALESCE_TIME)
vty_out(vty, " coalesce-time %u\n", bgp->coalesce_time);
-
- return 0;
}
"Number of paths\n"
"Match the cluster length\n")
-int bgp_config_write_maxpaths(struct vty *vty, struct bgp *bgp, afi_t afi,
- safi_t safi, int *write)
+void bgp_config_write_maxpaths(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi)
{
if (bgp->maxpaths[afi][safi].maxpaths_ebgp != MULTIPATH_NUM) {
- bgp_config_write_family_header(vty, afi, safi, write);
vty_out(vty, " maximum-paths %d\n",
bgp->maxpaths[afi][safi].maxpaths_ebgp);
}
if (bgp->maxpaths[afi][safi].maxpaths_ibgp != MULTIPATH_NUM) {
- bgp_config_write_family_header(vty, afi, safi, write);
vty_out(vty, " maximum-paths ibgp %d",
bgp->maxpaths[afi][safi].maxpaths_ibgp);
if (CHECK_FLAG(bgp->maxpaths[afi][safi].ibgp_flags,
vty_out(vty, " equal-cluster-length");
vty_out(vty, "\n");
}
-
- return 0;
}
/* BGP timers. */
return bgp_vty_return(vty, ret);
}
-int bgp_config_write_listen(struct vty *vty, struct bgp *bgp)
+void bgp_config_write_listen(struct vty *vty, struct bgp *bgp)
{
struct peer_group *group;
struct listnode *node, *nnode, *rnode, *nrnode;
}
}
}
-
- return 0;
}
return CMD_SUCCESS;
}
+static void show_address_entry(struct hash_backet *backet, void *args)
+{
+ struct vty *vty = (struct vty *)args;
+ struct bgp_addr *addr = (struct bgp_addr *)backet->data;
+
+ vty_out(vty, "addr: %s, count: %d\n", inet_ntoa(addr->addr),
+ addr->refcnt);
+}
+
+static void show_tip_entry(struct hash_backet *backet, void *args)
+{
+ struct vty *vty = (struct vty *)args;
+ struct tip_addr *tip = (struct tip_addr *)backet->data;
+
+ vty_out(vty, "addr: %s, count: %d\n", inet_ntoa(tip->addr),
+ tip->refcnt);
+}
+
+static void bgp_show_martian_nexthops(struct vty *vty, struct bgp *bgp)
+{
+ vty_out(vty, "self nexthop database:\n");
+ hash_iterate(bgp->address_hash,
+ (void (*)(struct hash_backet *, void *))show_address_entry,
+ vty);
+
+ vty_out(vty, "Tunnel-ip database:\n");
+ hash_iterate(bgp->tip_hash,
+ (void (*)(struct hash_backet *, void *))show_tip_entry,
+ vty);
+}
+
+DEFUN(show_bgp_martian_nexthop_db,
+ show_bgp_martian_nexthop_db_cmd,
+ "show bgp martian next-hop",
+ SHOW_STR
+ BGP_STR
+ "martian next-hops\n"
+ "martian next-hop database\n")
+{
+ struct bgp *bgp = NULL;
+
+ bgp = bgp_get_default();
+ if (!bgp) {
+ vty_out(vty, "%% No BGP process is configured\n");
+ return CMD_WARNING;
+ }
+ bgp_show_martian_nexthops(vty, bgp);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (show_bgp_memory,
show_bgp_memory_cmd,
"show [ip] bgp memory",
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
continue;
- if (peer->afc[afi][safi]) {
- if (!count) {
- unsigned long ents;
- char memstrbuf[MTYPE_MEMSTR_LEN];
- int vrf_id_ui;
+ if (!peer->afc[afi][safi])
+ continue;
- vrf_id_ui = (bgp->vrf_id == VRF_UNKNOWN)
- ? -1
- : bgp->vrf_id;
+ if (!count) {
+ unsigned long ents;
+ char memstrbuf[MTYPE_MEMSTR_LEN];
+ int vrf_id_ui;
+
+ vrf_id_ui =
+ (bgp->vrf_id == VRF_UNKNOWN) ? -1 : bgp->vrf_id;
+
+ /* Usage summary and header */
+ if (use_json) {
+ json_object_string_add(
+ json, "routerId",
+ inet_ntoa(bgp->router_id));
+ json_object_int_add(json, "as", bgp->as);
+ json_object_int_add(json, "vrfId", vrf_id_ui);
+ json_object_string_add(
+ json, "vrfName",
+ (bgp->inst_type
+ == BGP_INSTANCE_TYPE_DEFAULT)
+ ? "Default"
+ : bgp->name);
+ } else {
+ vty_out(vty,
+ "BGP router identifier %s, local AS number %u vrf-id %d",
+ inet_ntoa(bgp->router_id), bgp->as,
+ vrf_id_ui);
+ vty_out(vty, "\n");
+ }
- /* Usage summary and header */
+ if (bgp_update_delay_configured(bgp)) {
if (use_json) {
- json_object_string_add(
- json, "routerId",
- inet_ntoa(bgp->router_id));
- json_object_int_add(json, "as",
- bgp->as);
- json_object_int_add(json, "vrfId",
- vrf_id_ui);
- json_object_string_add(
- json, "vrfName",
- (bgp->inst_type
- == BGP_INSTANCE_TYPE_DEFAULT)
- ? "Default"
- : bgp->name);
- } else {
- vty_out(vty,
- "BGP router identifier %s, local AS number %u vrf-id %d",
- inet_ntoa(bgp->router_id),
- bgp->as, vrf_id_ui);
- vty_out(vty, "\n");
- }
+ json_object_int_add(
+ json, "updateDelayLimit",
+ bgp->v_update_delay);
- if (bgp_update_delay_configured(bgp)) {
- if (use_json) {
+ if (bgp->v_update_delay
+ != bgp->v_establish_wait)
json_object_int_add(
json,
- "updateDelayLimit",
- bgp->v_update_delay);
+ "updateDelayEstablishWait",
+ bgp->v_establish_wait);
- if (bgp->v_update_delay
- != bgp->v_establish_wait)
- json_object_int_add(
- json,
- "updateDelayEstablishWait",
- bgp->v_establish_wait);
-
- if (bgp_update_delay_active(
- bgp)) {
+ if (bgp_update_delay_active(bgp)) {
+ json_object_string_add(
+ json,
+ "updateDelayFirstNeighbor",
+ bgp->update_delay_begin_time);
+ json_object_boolean_true_add(
+ json,
+ "updateDelayInProgress");
+ } else {
+ if (bgp->update_delay_over) {
json_object_string_add(
json,
"updateDelayFirstNeighbor",
bgp->update_delay_begin_time);
- json_object_boolean_true_add(
+ json_object_string_add(
json,
- "updateDelayInProgress");
- } else {
- if (bgp->update_delay_over) {
- json_object_string_add(
- json,
- "updateDelayFirstNeighbor",
- bgp->update_delay_begin_time);
- json_object_string_add(
- json,
- "updateDelayBestpathResumed",
- bgp->update_delay_end_time);
- json_object_string_add(
- json,
- "updateDelayZebraUpdateResume",
- bgp->update_delay_zebra_resume_time);
- json_object_string_add(
- json,
- "updateDelayPeerUpdateResume",
- bgp->update_delay_peers_resume_time);
- }
+ "updateDelayBestpathResumed",
+ bgp->update_delay_end_time);
+ json_object_string_add(
+ json,
+ "updateDelayZebraUpdateResume",
+ bgp->update_delay_zebra_resume_time);
+ json_object_string_add(
+ json,
+ "updateDelayPeerUpdateResume",
+ bgp->update_delay_peers_resume_time);
}
- } else {
+ }
+ } else {
+ vty_out(vty,
+ "Read-only mode update-delay limit: %d seconds\n",
+ bgp->v_update_delay);
+ if (bgp->v_update_delay
+ != bgp->v_establish_wait)
vty_out(vty,
- "Read-only mode update-delay limit: %d seconds\n",
- bgp->v_update_delay);
- if (bgp->v_update_delay
- != bgp->v_establish_wait)
- vty_out(vty,
- " Establish wait: %d seconds\n",
- bgp->v_establish_wait);
+ " Establish wait: %d seconds\n",
+ bgp->v_establish_wait);
- if (bgp_update_delay_active(
- bgp)) {
+ if (bgp_update_delay_active(bgp)) {
+ vty_out(vty,
+ " First neighbor established: %s\n",
+ bgp->update_delay_begin_time);
+ vty_out(vty,
+ " Delay in progress\n");
+ } else {
+ if (bgp->update_delay_over) {
vty_out(vty,
" First neighbor established: %s\n",
bgp->update_delay_begin_time);
vty_out(vty,
- " Delay in progress\n");
- } else {
- if (bgp->update_delay_over) {
- vty_out(vty,
- " First neighbor established: %s\n",
- bgp->update_delay_begin_time);
- vty_out(vty,
- " Best-paths resumed: %s\n",
- bgp->update_delay_end_time);
- vty_out(vty,
- " zebra update resumed: %s\n",
- bgp->update_delay_zebra_resume_time);
- vty_out(vty,
- " peers update resumed: %s\n",
- bgp->update_delay_peers_resume_time);
- }
+ " Best-paths resumed: %s\n",
+ bgp->update_delay_end_time);
+ vty_out(vty,
+ " zebra update resumed: %s\n",
+ bgp->update_delay_zebra_resume_time);
+ vty_out(vty,
+ " peers update resumed: %s\n",
+ bgp->update_delay_peers_resume_time);
}
}
}
+ }
- if (use_json) {
- if (bgp_maxmed_onstartup_configured(bgp)
- && bgp->maxmed_active)
- json_object_boolean_true_add(
- json,
- "maxMedOnStartup");
- if (bgp->v_maxmed_admin)
- json_object_boolean_true_add(
- json,
- "maxMedAdministrative");
+ if (use_json) {
+ if (bgp_maxmed_onstartup_configured(bgp)
+ && bgp->maxmed_active)
+ json_object_boolean_true_add(
+ json, "maxMedOnStartup");
+ if (bgp->v_maxmed_admin)
+ json_object_boolean_true_add(
+ json, "maxMedAdministrative");
- json_object_int_add(
- json, "tableVersion",
- bgp_table_version(
- bgp->rib[afi][safi]));
-
- ents = bgp_table_count(
- bgp->rib[afi][safi]);
- json_object_int_add(json, "ribCount",
- ents);
- json_object_int_add(
- json, "ribMemory",
- ents * sizeof(struct bgp_node));
+ json_object_int_add(
+ json, "tableVersion",
+ bgp_table_version(bgp->rib[afi][safi]));
- ents = listcount(bgp->peer);
- json_object_int_add(json, "peerCount",
- ents);
- json_object_int_add(
- json, "peerMemory",
- ents * sizeof(struct peer));
+ ents = bgp_table_count(bgp->rib[afi][safi]);
+ json_object_int_add(json, "ribCount", ents);
+ json_object_int_add(
+ json, "ribMemory",
+ ents * sizeof(struct bgp_node));
- if ((ents = listcount(bgp->group))) {
- json_object_int_add(
- json, "peerGroupCount",
- ents);
- json_object_int_add(
- json, "peerGroupMemory",
- ents * sizeof(struct
- peer_group));
- }
+ ents = listcount(bgp->peer);
+ json_object_int_add(json, "peerCount", ents);
+ json_object_int_add(json, "peerMemory",
+ ents * sizeof(struct peer));
- if (CHECK_FLAG(bgp->af_flags[afi][safi],
- BGP_CONFIG_DAMPENING))
- json_object_boolean_true_add(
- json,
- "dampeningEnabled");
- } else {
- if (bgp_maxmed_onstartup_configured(bgp)
- && bgp->maxmed_active)
- vty_out(vty,
- "Max-med on-startup active\n");
- if (bgp->v_maxmed_admin)
- vty_out(vty,
- "Max-med administrative active\n");
+ if ((ents = listcount(bgp->group))) {
+ json_object_int_add(
+ json, "peerGroupCount", ents);
+ json_object_int_add(
+ json, "peerGroupMemory",
+ ents * sizeof(struct
+ peer_group));
+ }
+ if (CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_CONFIG_DAMPENING))
+ json_object_boolean_true_add(
+ json, "dampeningEnabled");
+ } else {
+ if (bgp_maxmed_onstartup_configured(bgp)
+ && bgp->maxmed_active)
vty_out(vty,
- "BGP table version %" PRIu64
- "\n",
- bgp_table_version(
- bgp->rib[afi][safi]));
-
- ents = bgp_table_count(
- bgp->rib[afi][safi]);
+ "Max-med on-startup active\n");
+ if (bgp->v_maxmed_admin)
vty_out(vty,
- "RIB entries %ld, using %s of memory\n",
- ents,
- mtype_memstr(
- memstrbuf,
- sizeof(memstrbuf),
- ents * sizeof(struct
- bgp_node)));
+ "Max-med administrative active\n");
+
+ vty_out(vty, "BGP table version %" PRIu64 "\n",
+ bgp_table_version(bgp->rib[afi][safi]));
- /* Peer related usage */
- ents = listcount(bgp->peer);
+ ents = bgp_table_count(bgp->rib[afi][safi]);
+ vty_out(vty,
+ "RIB entries %ld, using %s of memory\n",
+ ents,
+ mtype_memstr(memstrbuf,
+ sizeof(memstrbuf),
+ ents * sizeof(struct
+ bgp_node)));
+
+ /* Peer related usage */
+ ents = listcount(bgp->peer);
+ vty_out(vty, "Peers %ld, using %s of memory\n",
+ ents,
+ mtype_memstr(
+ memstrbuf, sizeof(memstrbuf),
+ ents * sizeof(struct peer)));
+
+ if ((ents = listcount(bgp->group)))
vty_out(vty,
- "Peers %ld, using %s of memory\n",
+ "Peer groups %ld, using %s of memory\n",
ents,
mtype_memstr(
memstrbuf,
sizeof(memstrbuf),
ents * sizeof(struct
- peer)));
+ peer_group)));
- if ((ents = listcount(bgp->group)))
- vty_out(vty,
- "Peer groups %ld, using %s of memory\n",
- ents,
- mtype_memstr(
- memstrbuf,
- sizeof(memstrbuf),
- ents * sizeof(struct
- peer_group)));
-
- if (CHECK_FLAG(bgp->af_flags[afi][safi],
- BGP_CONFIG_DAMPENING))
- vty_out(vty,
- "Dampening enabled.\n");
- vty_out(vty, "\n");
+ if (CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_CONFIG_DAMPENING))
+ vty_out(vty, "Dampening enabled.\n");
+ vty_out(vty, "\n");
- /* Subtract 8 here because 'Neighbor' is
- * 8 characters */
- vty_out(vty, "Neighbor");
- vty_out(vty, "%*s",
- max_neighbor_width - 8, " ");
- vty_out(vty,
- "V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd\n");
- }
+ /* Subtract 8 here because 'Neighbor' is
+ * 8 characters */
+ vty_out(vty, "Neighbor");
+ vty_out(vty, "%*s", max_neighbor_width - 8,
+ " ");
+ vty_out(vty,
+ "V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd\n");
}
+ }
- count++;
-
- if (use_json) {
- json_peer = json_object_new_object();
-
- if (peer_dynamic_neighbor(peer))
- json_object_boolean_true_add(
- json_peer, "dynamicPeer");
+ count++;
- if (peer->hostname)
- json_object_string_add(json_peer,
- "hostname",
- peer->hostname);
+ if (use_json) {
+ json_peer = json_object_new_object();
+
+ if (peer_dynamic_neighbor(peer))
+ json_object_boolean_true_add(json_peer,
+ "dynamicPeer");
+
+ if (peer->hostname)
+ json_object_string_add(json_peer, "hostname",
+ peer->hostname);
+
+ if (peer->domainname)
+ json_object_string_add(json_peer, "domainname",
+ peer->domainname);
+
+ json_object_int_add(json_peer, "remoteAs", peer->as);
+ json_object_int_add(json_peer, "version", 4);
+ json_object_int_add(json_peer, "msgRcvd",
+ peer->open_in + peer->update_in
+ + peer->keepalive_in
+ + peer->notify_in
+ + peer->refresh_in
+ + peer->dynamic_cap_in);
+ json_object_int_add(json_peer, "msgSent",
+ peer->open_out + peer->update_out
+ + peer->keepalive_out
+ + peer->notify_out
+ + peer->refresh_out
+ + peer->dynamic_cap_out);
+
+ json_object_int_add(json_peer, "tableVersion",
+ peer->version[afi][safi]);
+ json_object_int_add(json_peer, "outq",
+ peer->obuf->count);
+ json_object_int_add(json_peer, "inq", 0);
+ peer_uptime(peer->uptime, timebuf, BGP_UPTIME_LEN,
+ use_json, json_peer);
+ json_object_int_add(json_peer, "prefixReceivedCount",
+ peer->pcount[afi][pfx_rcd_safi]);
- if (peer->domainname)
- json_object_string_add(
- json_peer, "domainname",
- peer->domainname);
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
+ json_object_string_add(json_peer, "state",
+ "Idle (Admin)");
+ else if (CHECK_FLAG(peer->sflags,
+ PEER_STATUS_PREFIX_OVERFLOW))
+ json_object_string_add(json_peer, "state",
+ "Idle (PfxCt)");
+ else
+ json_object_string_add(
+ json_peer, "state",
+ lookup_msg(bgp_status_msg, peer->status,
+ NULL));
+
+ if (peer->conf_if)
+ json_object_string_add(json_peer, "idType",
+ "interface");
+ else if (peer->su.sa.sa_family == AF_INET)
+ json_object_string_add(json_peer, "idType",
+ "ipv4");
+ else if (peer->su.sa.sa_family == AF_INET6)
+ json_object_string_add(json_peer, "idType",
+ "ipv6");
+
+ json_object_object_add(json_peers, peer->host,
+ json_peer);
+ } else {
+ memset(dn_flag, '\0', sizeof(dn_flag));
+ if (peer_dynamic_neighbor(peer)) {
+ dn_count++;
+ dn_flag[0] = '*';
+ }
- json_object_int_add(json_peer, "remoteAs",
- peer->as);
- json_object_int_add(json_peer, "version", 4);
- json_object_int_add(
- json_peer, "msgRcvd",
- peer->open_in + peer->update_in
- + peer->keepalive_in
- + peer->notify_in
- + peer->refresh_in
- + peer->dynamic_cap_in);
- json_object_int_add(
- json_peer, "msgSent",
- peer->open_out + peer->update_out
- + peer->keepalive_out
- + peer->notify_out
- + peer->refresh_out
- + peer->dynamic_cap_out);
-
- json_object_int_add(json_peer, "tableVersion",
- peer->version[afi][safi]);
- json_object_int_add(json_peer, "outq",
- peer->obuf->count);
- json_object_int_add(json_peer, "inq", 0);
+ if (peer->hostname
+ && bgp_flag_check(bgp, BGP_FLAG_SHOW_HOSTNAME))
+ len = vty_out(vty, "%s%s(%s)", dn_flag,
+ peer->hostname, peer->host);
+ else
+ len = vty_out(vty, "%s%s", dn_flag, peer->host);
+
+ /* pad the neighbor column with spaces */
+ if (len < max_neighbor_width)
+ vty_out(vty, "%*s", max_neighbor_width - len,
+ " ");
+
+ vty_out(vty, "4 %10u %7d %7d %8" PRIu64 " %4d %4zd %8s",
+ peer->as,
+ peer->open_in + peer->update_in
+ + peer->keepalive_in + peer->notify_in
+ + peer->refresh_in
+ + peer->dynamic_cap_in,
+ peer->open_out + peer->update_out
+ + peer->keepalive_out + peer->notify_out
+ + peer->refresh_out
+ + peer->dynamic_cap_out,
+ peer->version[afi][safi], 0, peer->obuf->count,
peer_uptime(peer->uptime, timebuf,
- BGP_UPTIME_LEN, use_json,
- json_peer);
- json_object_int_add(
- json_peer, "prefixReceivedCount",
- peer->pcount[afi][pfx_rcd_safi]);
+ BGP_UPTIME_LEN, 0, NULL));
+ if (peer->status == Established)
+ vty_out(vty, " %12ld",
+ peer->pcount[afi][pfx_rcd_safi]);
+ else {
if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
- json_object_string_add(json_peer,
- "state",
- "Idle (Admin)");
+ vty_out(vty, " Idle (Admin)");
else if (CHECK_FLAG(
peer->sflags,
PEER_STATUS_PREFIX_OVERFLOW))
- json_object_string_add(json_peer,
- "state",
- "Idle (PfxCt)");
+ vty_out(vty, " Idle (PfxCt)");
else
- json_object_string_add(
- json_peer, "state",
+ vty_out(vty, " %12s",
lookup_msg(bgp_status_msg,
peer->status, NULL));
-
- if (peer->conf_if)
- json_object_string_add(json_peer,
- "idType",
- "interface");
- else if (peer->su.sa.sa_family == AF_INET)
- json_object_string_add(
- json_peer, "idType", "ipv4");
- else if (peer->su.sa.sa_family == AF_INET6)
- json_object_string_add(
- json_peer, "idType", "ipv6");
-
- json_object_object_add(json_peers, peer->host,
- json_peer);
- } else {
- memset(dn_flag, '\0', sizeof(dn_flag));
- if (peer_dynamic_neighbor(peer)) {
- dn_count++;
- dn_flag[0] = '*';
- }
-
- if (peer->hostname
- && bgp_flag_check(bgp,
- BGP_FLAG_SHOW_HOSTNAME))
- len = vty_out(vty, "%s%s(%s)", dn_flag,
- peer->hostname,
- peer->host);
- else
- len = vty_out(vty, "%s%s", dn_flag,
- peer->host);
-
- /* pad the neighbor column with spaces */
- if (len < max_neighbor_width)
- vty_out(vty, "%*s",
- max_neighbor_width - len, " ");
-
- vty_out(vty, "4 %10u %7d %7d %8" PRIu64
- " %4d %4zd %8s",
- peer->as,
- peer->open_in + peer->update_in
- + peer->keepalive_in
- + peer->notify_in
- + peer->refresh_in
- + peer->dynamic_cap_in,
- peer->open_out + peer->update_out
- + peer->keepalive_out
- + peer->notify_out
- + peer->refresh_out
- + peer->dynamic_cap_out,
- peer->version[afi][safi], 0,
- peer->obuf->count,
- peer_uptime(peer->uptime, timebuf,
- BGP_UPTIME_LEN, 0, NULL));
-
- if (peer->status == Established)
- vty_out(vty, " %12ld",
- peer->pcount[afi]
- [pfx_rcd_safi]);
- else {
- if (CHECK_FLAG(peer->flags,
- PEER_FLAG_SHUTDOWN))
- vty_out(vty, " Idle (Admin)");
- else if (
- CHECK_FLAG(
- peer->sflags,
- PEER_STATUS_PREFIX_OVERFLOW))
- vty_out(vty, " Idle (PfxCt)");
- else
- vty_out(vty, " %12s",
- lookup_msg(
- bgp_status_msg,
- peer->status,
- NULL));
- }
- vty_out(vty, "\n");
}
+ vty_out(vty, "\n");
}
}
"defaultNotSent");
}
+ if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
+ if (p->bgp->advertise_all_vni)
+ json_object_boolean_true_add(
+ json_addr, "advertiseAllVnis");
+ }
+
if (filter->plist[FILTER_IN].name
|| filter->dlist[FILTER_IN].name
|| filter->aslist[FILTER_IN].name
vty_out(vty, " default not sent\n");
}
+ /* advertise-vni-all */
+ if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
+ if (p->bgp->advertise_all_vni)
+ vty_out(vty, " advertise-all-vni\n");
+ }
+
if (filter->plist[FILTER_IN].name
|| filter->dlist[FILTER_IN].name
|| filter->aslist[FILTER_IN].name
json_cap, "multiprotocolExtensions",
json_multi);
+ /* Hostname capabilities */
+ json_object *json_hname = NULL;
+
+ json_hname = json_object_new_object();
+
+ if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)) {
+ json_object_string_add(
+ json_hname, "advHostName",
+ bgp->peer_self->hostname
+ ? bgp->peer_self
+ ->hostname
+ : "n/a");
+ json_object_string_add(
+ json_hname, "advDomainName",
+ bgp->peer_self->domainname
+ ? bgp->peer_self
+ ->domainname
+ : "n/a");
+ }
+
+
+ if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) {
+ json_object_string_add(
+ json_hname, "rcvHostName",
+ p->hostname ? p->hostname
+ : "n/a");
+ json_object_string_add(
+ json_hname, "rcvDomainName",
+ p->domainname ? p->domainname
+ : "n/a");
+ }
+
+ json_object_object_add(json_cap, "hostName",
+ json_hname);
+
/* Gracefull Restart */
if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)
|| CHECK_FLAG(p->cap,
}
/* Hostname capability */
- if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)
- || CHECK_FLAG(p->cap,
- PEER_CAP_HOSTNAME_RCV)) {
+ vty_out(vty, " Hostname Capability:");
+
+ if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)) {
vty_out(vty,
- " Hostname Capability:");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_HOSTNAME_ADV))
- vty_out(vty, " advertised");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_HOSTNAME_RCV))
- vty_out(vty, " %sreceived",
- CHECK_FLAG(
- p->cap,
- PEER_CAP_HOSTNAME_ADV)
- ? "and "
- : "");
- vty_out(vty, "\n");
+ " advertised (name: %s,domain name: %s)",
+ bgp->peer_self->hostname
+ ? bgp->peer_self
+ ->hostname
+ : "n/a",
+ bgp->peer_self->domainname
+ ? bgp->peer_self
+ ->domainname
+ : "n/a");
+ } else {
+ vty_out(vty, " not advertised");
}
+ if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) {
+ vty_out(vty,
+ " received (name: %s,domain name: %s)",
+ p->hostname ? p->hostname
+ : "n/a",
+ p->domainname ? p->domainname
+ : "n/a");
+ } else {
+ vty_out(vty, " not received");
+ }
+
+ vty_out(vty, "\n");
+
/* Gracefull Restart */
if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)
|| CHECK_FLAG(p->cap,
return bgp_redistribute_unset(bgp, AFI_IP6, type, 0);
}
-int bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp, afi_t afi,
- safi_t safi, int *write)
+void bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi)
{
int i;
/* Unicast redistribution only. */
if (safi != SAFI_UNICAST)
- return 0;
+ return;
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
/* Redistribute BGP does not make sense. */
continue;
for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
- /* Display "address-family" when it is not yet
- * diplayed. */
- bgp_config_write_family_header(vty, afi, safi,
- write);
-
/* "redistribute" configuration. */
vty_out(vty, " redistribute %s",
zebra_route_string(i));
}
}
}
- return *write;
}
/* BGP node structure. */
/* "show [ip] bgp memory" commands. */
install_element(VIEW_NODE, &show_bgp_memory_cmd);
+ /* "show bgp martian next-hop" */
+ install_element(VIEW_NODE, &show_bgp_martian_nexthop_db_cmd);
+
/* "show [ip] bgp views" commands. */
install_element(VIEW_NODE, &show_bgp_views_cmd);
extern void bgp_vty_init(void);
extern const char *afi_safi_print(afi_t, safi_t);
extern const char *afi_safi_json(afi_t, safi_t);
-extern int bgp_config_write_update_delay(struct vty *, struct bgp *);
-extern int bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp);
-extern int bgp_config_write_listen(struct vty *vty, struct bgp *bgp);
-extern int bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp);
+extern void bgp_config_write_update_delay(struct vty *, struct bgp *);
+extern void bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp);
+extern void bgp_config_write_listen(struct vty *vty, struct bgp *bgp);
+extern void bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp);
extern int bgp_vty_return(struct vty *vty, int ret);
extern struct peer *peer_and_group_lookup_vty(struct vty *vty,
const char *peer_str);
* in
* the RIB */
if (info->sub_type == BGP_ROUTE_AGGREGATE)
- SET_FLAG(api.flags, ZEBRA_FLAG_BLACKHOLE);
+ zapi_route_set_blackhole(&api, BLACKHOLE_NULL);
if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED
|| info->sub_type == BGP_ROUTE_AGGREGATE) {
if (has_valid_label)
SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
- if (!CHECK_FLAG(api.flags, ZEBRA_FLAG_BLACKHOLE))
+ if (info->sub_type != BGP_ROUTE_AGGREGATE)
api.nexthop_num = valid_nh_count;
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
extern void bgp_zebra_init(struct thread_master *master);
extern void bgp_zebra_destroy(void);
extern int bgp_if_update_all(void);
-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_config_write_maxpaths(struct vty *, struct bgp *, afi_t,
+ safi_t);
+extern void bgp_config_write_redistribute(struct vty *, 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);
XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->host);
bgp->peer_self->host =
XSTRDUP(MTYPE_BGP_PEER_HOST, "Static announcement");
+ if (bgp->peer_self->hostname != NULL) {
+ XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->hostname);
+ bgp->peer_self->hostname = NULL;
+ }
+ if (cmd_hostname_get())
+ bgp->peer_self->hostname =
+ XSTRDUP(MTYPE_BGP_PEER_HOST, cmd_hostname_get());
+
+ if (bgp->peer_self->domainname != NULL) {
+ XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->domainname);
+ bgp->peer_self->domainname = NULL;
+ }
+ if (cmd_domainname_get())
+ bgp->peer_self->domainname =
+ XSTRDUP(MTYPE_BGP_PEER_HOST, cmd_domainname_get());
bgp->peer = list_new();
bgp->peer->cmp = (int (*)(void *, void *))peer_cmp;
bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_same, NULL);
bgp = bgp_create(as, name, inst_type);
bgp_router_id_set(bgp, &bgp->router_id_zebra);
bgp_address_init(bgp);
+ bgp_tip_hash_init(bgp);
bgp_scan_init(bgp);
*bgp_val = bgp;
/* Purge network and redistributed routes. */
bgp_purge_static_redist_routes(bgp);
+
+ /* Cleanup registered nexthops (flags) */
+ bgp_cleanup_nexthops(bgp);
}
/* Delete BGP instance. */
bgp_scan_finish(bgp);
bgp_address_destroy(bgp);
+ bgp_tip_hash_destroy(bgp);
bgp_evpn_cleanup(bgp);
return buf;
}
-#define afi_header_vty_out(vty, afi, safi, write, format, ...) \
- do { \
- bgp_config_write_family_header(vty, afi, safi, write); \
- vty_out(vty, format, ## __VA_ARGS__); \
- } while (0)
-
static void bgp_config_write_filter(struct vty *vty, struct peer *peer,
- afi_t afi, safi_t safi, int *write)
+ afi_t afi, safi_t safi)
{
struct bgp_filter *filter;
struct bgp_filter *gfilter = NULL;
if (!gfilter || !gfilter->dlist[in].name
|| strcmp(filter->dlist[in].name, gfilter->dlist[in].name)
!= 0) {
- afi_header_vty_out(
- vty, afi, safi, write,
- " neighbor %s distribute-list %s in\n", addr,
- filter->dlist[in].name);
+ vty_out(vty, " neighbor %s distribute-list %s in\n",
+ addr, filter->dlist[in].name);
}
if (filter->dlist[out].name && !gfilter) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s distribute-list %s out\n",
- addr, filter->dlist[out].name);
+ vty_out(vty, " neighbor %s distribute-list %s out\n", addr,
+ filter->dlist[out].name);
}
/* prefix-list. */
if (!gfilter || !gfilter->plist[in].name
|| strcmp(filter->plist[in].name, gfilter->plist[in].name)
!= 0) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s prefix-list %s in\n",
- addr, filter->plist[in].name);
+ vty_out(vty, " neighbor %s prefix-list %s in\n", addr,
+ filter->plist[in].name);
}
- if (filter->plist[out].name)
- if (!gfilter || !gfilter->plist[out].name
- || strcmp(filter->plist[out].name, gfilter->plist[out].name)
- != 0) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s prefix-list %s out\n",
- addr, filter->plist[out].name);
- }
+ if (filter->plist[out].name)
+ if (!gfilter || !gfilter->plist[out].name
+ || strcmp(filter->plist[out].name, gfilter->plist[out].name)
+ != 0) {
+ vty_out(vty, " neighbor %s prefix-list %s out\n", addr,
+ filter->plist[out].name);
+ }
/* route-map. */
if (filter->map[RMAP_IN].name)
|| strcmp(filter->map[RMAP_IN].name,
gfilter->map[RMAP_IN].name)
!= 0) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s route-map %s in\n",
- addr, filter->map[RMAP_IN].name);
+ vty_out(vty, " neighbor %s route-map %s in\n", addr,
+ filter->map[RMAP_IN].name);
}
if (filter->map[RMAP_OUT].name)
|| strcmp(filter->map[RMAP_OUT].name,
gfilter->map[RMAP_OUT].name)
!= 0) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s route-map %s out\n",
- addr, filter->map[RMAP_OUT].name);
+ vty_out(vty, " neighbor %s route-map %s out\n", addr,
+ filter->map[RMAP_OUT].name);
}
/* unsuppress-map */
if (filter->usmap.name && !gfilter) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s unsuppress-map %s\n", addr,
- filter->usmap.name);
+ vty_out(vty, " neighbor %s unsuppress-map %s\n", addr,
+ filter->usmap.name);
}
/* filter-list. */
if (!gfilter || !gfilter->aslist[in].name
|| strcmp(filter->aslist[in].name, gfilter->aslist[in].name)
!= 0) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s filter-list %s in\n",
- addr, filter->aslist[in].name);
+ vty_out(vty, " neighbor %s filter-list %s in\n", addr,
+ filter->aslist[in].name);
}
if (filter->aslist[out].name && !gfilter) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s filter-list %s out\n", addr,
- filter->aslist[out].name);
+ vty_out(vty, " neighbor %s filter-list %s out\n", addr,
+ filter->aslist[out].name);
}
}
/* BGP peer configuration display function. */
static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
- struct peer *peer, afi_t afi, safi_t safi,
- int *write)
+ struct peer *peer, afi_t afi, safi_t safi)
{
struct peer *g_peer = NULL;
char *addr;
/* If the peer-group is active but peer is not, print a 'no
* activate' */
if (g_peer->afc[afi][safi] && !peer->afc[afi][safi]) {
- afi_header_vty_out(vty, afi, safi, write,
- " no neighbor %s activate\n", addr);
+ vty_out(vty, " no neighbor %s activate\n", addr);
}
/* If the peer-group is not active but peer is, print an
'activate' */
else if (!g_peer->afc[afi][safi] && peer->afc[afi][safi]) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s activate\n", addr);
+ vty_out(vty, " neighbor %s activate\n", addr);
}
} else {
if (peer->afc[afi][safi]) {
if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) {
if (bgp_flag_check(bgp,
BGP_FLAG_NO_DEFAULT_IPV4)) {
- afi_header_vty_out(
- vty, afi, safi, write,
- " neighbor %s activate\n",
+ vty_out(vty, " neighbor %s activate\n",
addr);
}
} else
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s activate\n",
- addr);
+ vty_out(vty, " neighbor %s activate\n", addr);
} else {
if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) {
if (!bgp_flag_check(bgp,
BGP_FLAG_NO_DEFAULT_IPV4)) {
- afi_header_vty_out(
- vty, afi, safi, write,
+ vty_out(vty,
" no neighbor %s activate\n",
addr);
}
/* addpath TX knobs */
if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_ADDPATH_TX_ALL_PATHS)) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s addpath-tx-all-paths\n",
- addr);
+ vty_out(vty, " neighbor %s addpath-tx-all-paths\n", addr);
}
if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS)) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s addpath-tx-bestpath-per-AS\n",
- addr);
+ vty_out(vty, " neighbor %s addpath-tx-bestpath-per-AS\n",
+ addr);
}
/* ORF capability. */
if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM)
|| peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_ORF_PREFIX_RM)) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s capability orf prefix-list",
- addr);
+ vty_out(vty, " neighbor %s capability orf prefix-list", addr);
if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_ORF_PREFIX_SM)
/* Route reflector client. */
if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_REFLECTOR_CLIENT)) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s route-reflector-client\n",
- addr);
+ vty_out(vty, " neighbor %s route-reflector-client\n", addr);
}
/* next-hop-self force */
if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_FORCE_NEXTHOP_SELF)) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s next-hop-self force\n", addr);
+ vty_out(vty, " neighbor %s next-hop-self force\n", addr);
}
/* next-hop-self */
if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_NEXTHOP_SELF)) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s next-hop-self\n", addr);
+ vty_out(vty, " neighbor %s next-hop-self\n", addr);
}
/* remove-private-AS */
if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE)) {
- afi_header_vty_out(
- vty, afi, safi, write,
- " neighbor %s remove-private-AS all replace-AS\n",
+ vty_out(vty, " neighbor %s remove-private-AS all replace-AS\n",
addr);
}
else if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE)) {
- afi_header_vty_out(
- vty, afi, safi, write,
- " neighbor %s remove-private-AS replace-AS\n", addr);
+ vty_out(vty, " neighbor %s remove-private-AS replace-AS\n",
+ addr);
}
else if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_REMOVE_PRIVATE_AS_ALL)) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s remove-private-AS all\n",
- addr);
+ vty_out(vty, " neighbor %s remove-private-AS all\n", addr);
}
else if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_REMOVE_PRIVATE_AS)) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s remove-private-AS\n", addr);
+ vty_out(vty, " neighbor %s remove-private-AS\n", addr);
}
/* as-override */
if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_AS_OVERRIDE)) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s as-override\n", addr);
+ vty_out(vty, " neighbor %s as-override\n", addr);
}
/* send-community print. */
&& peergroup_af_flag_check(
peer, afi, safi,
PEER_FLAG_SEND_LARGE_COMMUNITY)) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s send-community all\n",
- addr);
+ vty_out(vty, " neighbor %s send-community all\n",
+ addr);
} else if (peergroup_af_flag_check(
peer, afi, safi,
PEER_FLAG_SEND_LARGE_COMMUNITY)) {
- afi_header_vty_out(
- vty, afi, safi, write,
- " neighbor %s send-community large\n", addr);
+ vty_out(vty, " neighbor %s send-community large\n",
+ addr);
} else if (peergroup_af_flag_check(
peer, afi, safi,
PEER_FLAG_SEND_EXT_COMMUNITY)) {
- afi_header_vty_out(
- vty, afi, safi, write,
- " neighbor %s send-community extended\n",
+ vty_out(vty, " neighbor %s send-community extended\n",
addr);
} else if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_SEND_COMMUNITY)) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s send-community\n",
- addr);
+ vty_out(vty, " neighbor %s send-community\n", addr);
}
} else {
if (!peer_af_flag_check(peer, afi, safi,
&& (!g_peer || peer_af_flag_check(
g_peer, afi, safi,
PEER_FLAG_SEND_LARGE_COMMUNITY))) {
- afi_header_vty_out(
- vty, afi, safi, write,
- " no neighbor %s send-community all\n", addr);
+ vty_out(vty, " no neighbor %s send-community all\n",
+ addr);
} else {
if (!peer_af_flag_check(peer, afi, safi,
PEER_FLAG_SEND_LARGE_COMMUNITY)
|| peer_af_flag_check(
g_peer, afi, safi,
PEER_FLAG_SEND_LARGE_COMMUNITY))) {
- afi_header_vty_out(
- vty, afi, safi, write,
+ vty_out(vty,
" no neighbor %s send-community large\n",
addr);
}
|| peer_af_flag_check(
g_peer, afi, safi,
PEER_FLAG_SEND_EXT_COMMUNITY))) {
- afi_header_vty_out(
- vty, afi, safi, write,
+ vty_out(vty,
" no neighbor %s send-community extended\n",
addr);
}
&& (!g_peer || peer_af_flag_check(
g_peer, afi, safi,
PEER_FLAG_SEND_COMMUNITY))) {
- afi_header_vty_out(
- vty, afi, safi, write,
+ vty_out(vty,
" no neighbor %s send-community\n",
addr);
}
|| (peer->default_rmap[afi][safi].name
&& strcmp(peer->default_rmap[afi][safi].name,
g_peer->default_rmap[afi][safi].name))))) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s default-originate", addr);
+ vty_out(vty, " neighbor %s default-originate", addr);
if (peer->default_rmap[afi][safi].name)
vty_out(vty, " route-map %s",
peer->default_rmap[afi][safi].name);
/* Soft reconfiguration inbound. */
if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_SOFT_RECONFIG)) {
- afi_header_vty_out(
- vty, afi, safi, write,
- " neighbor %s soft-reconfiguration inbound\n", addr);
+ vty_out(vty, " neighbor %s soft-reconfiguration inbound\n",
+ addr);
}
/* maximum-prefix. */
PEER_FLAG_MAX_PREFIX_WARNING)
!= CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_MAX_PREFIX_WARNING)) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s maximum-prefix %lu",
- addr, peer->pmax[afi][safi]);
+ vty_out(vty, " neighbor %s maximum-prefix %lu", addr,
+ peer->pmax[afi][safi]);
if (peer->pmax_threshold[afi][safi]
!= MAXIMUM_PREFIX_THRESHOLD_DEFAULT)
vty_out(vty, " %u",
/* Route server client. */
if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_RSERVER_CLIENT)) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s route-server-client\n", addr);
+ vty_out(vty, " neighbor %s route-server-client\n", addr);
}
/* Nexthop-local unchanged. */
if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s nexthop-local unchanged\n",
- addr);
+ vty_out(vty, " neighbor %s nexthop-local unchanged\n", addr);
}
/* allowas-in <1-10> */
|| peer->allowas_in[afi][safi]
!= g_peer->allowas_in[afi][safi]) {
if (peer->allowas_in[afi][safi] == 3) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s allowas-in\n",
- addr);
+ vty_out(vty, " neighbor %s allowas-in\n",
+ addr);
} else {
- afi_header_vty_out(
- vty, afi, safi, write,
- " neighbor %s allowas-in %d\n", addr,
- peer->allowas_in[afi][safi]);
+ vty_out(vty, " neighbor %s allowas-in %d\n",
+ addr, peer->allowas_in[afi][safi]);
}
}
}
if (!peer_group_active(peer)
|| !peer_af_flag_check(g_peer, afi, safi,
PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s allowas-in origin\n",
- addr);
+ vty_out(vty, " neighbor %s allowas-in origin\n", addr);
}
}
|| !peer_af_flag_check(g_peer, afi, safi, PEER_FLAG_WEIGHT)
|| peer->weight[afi][safi] != g_peer->weight[afi][safi]) {
if (peer->weight[afi][safi]) {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s weight %lu\n",
- addr,
- peer->weight[afi][safi]);
+ vty_out(vty, " neighbor %s weight %lu\n", addr,
+ peer->weight[afi][safi]);
}
}
/* Filter. */
- bgp_config_write_filter(vty, peer, afi, safi, write);
+ bgp_config_write_filter(vty, peer, afi, safi);
/* atribute-unchanged. */
if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_AS_PATH_UNCHANGED) ||
peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_MED_UNCHANGED)) {
- afi_header_vty_out(
- vty, afi, safi, write,
+ vty_out(vty,
" neighbor %s attribute-unchanged%s%s%s\n",
addr,
- peer_af_flag_check(
- peer, afi, safi,
- PEER_FLAG_AS_PATH_UNCHANGED)
+ peer_af_flag_check(peer, afi, safi,
+ PEER_FLAG_AS_PATH_UNCHANGED)
? " as-path"
: "",
- peer_af_flag_check(
- peer, afi, safi,
- PEER_FLAG_NEXTHOP_UNCHANGED)
+ peer_af_flag_check(peer, afi, safi,
+ PEER_FLAG_NEXTHOP_UNCHANGED)
? " next-hop"
: "",
peer_af_flag_check(peer, afi, safi,
}
}
-/* Display "address-family" configuration header. */
-void bgp_config_write_family_header(struct vty *vty, afi_t afi, safi_t safi,
- int *write)
+/* Address family based peer configuration display. */
+static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi)
{
- if (*write)
- return;
+ struct peer *peer;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
- vty_out(vty, " !\n address-family ");
+ vty_frame(vty, " !\n address-family ");
if (afi == AFI_IP) {
if (safi == SAFI_UNICAST)
- vty_out(vty, "ipv4 unicast");
+ vty_frame(vty, "ipv4 unicast");
else if (safi == SAFI_LABELED_UNICAST)
- vty_out(vty, "ipv4 labeled-unicast");
+ vty_frame(vty, "ipv4 labeled-unicast");
else if (safi == SAFI_MULTICAST)
- vty_out(vty, "ipv4 multicast");
+ vty_frame(vty, "ipv4 multicast");
else if (safi == SAFI_MPLS_VPN)
- vty_out(vty, "ipv4 vpn");
+ vty_frame(vty, "ipv4 vpn");
else if (safi == SAFI_ENCAP)
- vty_out(vty, "ipv4 encap");
+ vty_frame(vty, "ipv4 encap");
} else if (afi == AFI_IP6) {
if (safi == SAFI_UNICAST)
- vty_out(vty, "ipv6 unicast");
+ vty_frame(vty, "ipv6 unicast");
else if (safi == SAFI_LABELED_UNICAST)
- vty_out(vty, "ipv6 labeled-unicast");
+ vty_frame(vty, "ipv6 labeled-unicast");
else if (safi == SAFI_MULTICAST)
- vty_out(vty, "ipv6 multicast");
+ vty_frame(vty, "ipv6 multicast");
else if (safi == SAFI_MPLS_VPN)
- vty_out(vty, "ipv6 vpn");
+ vty_frame(vty, "ipv6 vpn");
else if (safi == SAFI_ENCAP)
- vty_out(vty, "ipv6 encap");
+ vty_frame(vty, "ipv6 encap");
} else if (afi == AFI_L2VPN) {
if (safi == SAFI_EVPN)
- vty_out(vty, "l2vpn evpn");
+ vty_frame(vty, "l2vpn evpn");
}
- vty_out(vty, "\n");
-
- *write = 1;
-}
-
-/* Address family based peer configuration display. */
-static int bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
- safi_t safi)
-{
- int write = 0;
- struct peer *peer;
- struct peer_group *group;
- struct listnode *node, *nnode;
+ vty_frame(vty, "\n");
- bgp_config_write_distance(vty, bgp, afi, safi, &write);
+ bgp_config_write_distance(vty, bgp, afi, safi);
- bgp_config_write_network(vty, bgp, afi, safi, &write);
+ bgp_config_write_network(vty, bgp, afi, safi);
- bgp_config_write_redistribute(vty, bgp, afi, safi, &write);
+ bgp_config_write_redistribute(vty, bgp, afi, safi);
for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group))
- bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi,
- &write);
+ bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi);
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
/* Skip dynamic neighbors. */
/* Do not display doppelganger peers */
if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
- bgp_config_write_peer_af(vty, bgp, peer, afi, safi,
- &write);
+ bgp_config_write_peer_af(vty, bgp, peer, afi, safi);
}
- bgp_config_write_maxpaths(vty, bgp, afi, safi, &write);
- bgp_config_write_table_map(vty, bgp, afi, safi, &write);
+ bgp_config_write_maxpaths(vty, bgp, afi, safi);
+ bgp_config_write_table_map(vty, bgp, afi, safi);
if (safi == SAFI_EVPN)
- bgp_config_write_evpn_info(vty, bgp, afi, safi, &write);
-
- if (write)
- vty_out(vty, " exit-address-family\n");
+ bgp_config_write_evpn_info(vty, bgp, afi, safi);
- return write;
+ vty_endframe(vty, " exit-address-family\n");
}
int bgp_config_write(struct vty *vty)
vty_out(vty, "bgp route-map delay-timer %u\n",
bm->rmap_update_timer);
+ if (write)
+ vty_out(vty, "!\n");
+
/* BGP configuration. */
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
- if (write)
- vty_out(vty, "!\n");
-
/* Router bgp ASN */
vty_out(vty, "router bgp %u", bgp->as);
vty_out(vty, " no auto-summary\n");
/* IPv4 unicast configuration. */
- write +=
- bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST);
+ bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST);
/* IPv4 multicast configuration. */
- write += bgp_config_write_family(vty, bgp, AFI_IP,
- SAFI_MULTICAST);
+ 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);
+ 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);
+ bgp_config_write_family(vty, bgp, AFI_IP, SAFI_MPLS_VPN);
/* ENCAPv4 configuration. */
- write += bgp_config_write_family(vty, bgp, AFI_IP, SAFI_ENCAP);
+ bgp_config_write_family(vty, bgp, AFI_IP, SAFI_ENCAP);
/* IPv6 unicast configuration. */
- write += bgp_config_write_family(vty, bgp, AFI_IP6,
- SAFI_UNICAST);
+ bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_UNICAST);
/* IPv6 multicast configuration. */
- write += bgp_config_write_family(vty, bgp, AFI_IP6,
- SAFI_MULTICAST);
+ 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);
+ 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);
+ bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_MPLS_VPN);
/* ENCAPv6 configuration. */
- write += bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_ENCAP);
+ bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_ENCAP);
/* EVPN configuration. */
- write +=
- bgp_config_write_family(vty, bgp, AFI_L2VPN, SAFI_EVPN);
+ bgp_config_write_family(vty, bgp, AFI_L2VPN, SAFI_EVPN);
#if ENABLE_BGP_VNC
- write += bgp_rfapi_cfg_write(vty, bgp);
+ bgp_rfapi_cfg_write(vty, bgp);
#endif
- write++;
+ vty_out(vty, "!\n");
}
- return write;
+ return 0;
}
void bgp_master_init(struct thread_master *master)
struct hash *address_hash;
+ /* DB for all local tunnel-ips - used mainly for martian checks
+ Currently it only has all VxLan tunnel IPs*/
+ struct hash *tip_hash;
+
/* Static route configuration. */
struct bgp_table *route[AFI_MAX][SAFI_MAX];
extern char *peer_uptime(time_t, char *, size_t, u_char, json_object *);
extern int bgp_config_write(struct vty *);
-extern void bgp_config_write_family_header(struct vty *, afi_t, safi_t, int *);
extern void bgp_master_init(struct thread_master *master);
struct rfapi_nve_group_cfg *rfg;
VTY_DECLVAR_CONTEXT(bgp, bgp);
- if (!bgp) {
- vty_out(vty, "No BGP process is configured\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
/* Search for name */
rfg = bgp_rfapi_cfg_match_byname(bgp, argv[1]->arg,
RFAPI_GROUP_CFG_VRF);
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- if (!bgp) {
- vty_out(vty, "No BGP process is configured\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
return bgp_rfapi_delete_named_nve_group(vty, bgp, argv[2]->arg,
RFAPI_GROUP_CFG_VRF);
}
uint32_t label;
VTY_DECLVAR_CONTEXT(bgp, bgp);
- if (!bgp) {
- vty_out(vty, "No BGP process is configured\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
/* make sure it's still in list */
if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) {
/* Not in list anymore */
int is_export_bgp = 0;
int is_export_zebra = 0;
- if (!bgp) {
- vty_out(vty, "No BGP process is configured\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
/* make sure it's still in list */
if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) {
/* Not in list anymore */
VTY_DECLVAR_CONTEXT(bgp, bgp);
int rc;
- if (!bgp) {
- vty_out(vty, "No BGP process is configured\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
/* make sure it's still in list */
if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) {
/* Not in list anymore */
struct listnode *node;
struct rfapi_rfg_name *rfgn;
- if (!bgp) {
- vty_out(vty, "No BGP process is configured\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
/* make sure it's still in list */
if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) {
/* Not in list anymore */
VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
VTY_DECLVAR_CONTEXT(bgp, bgp);
- if (!bgp) {
- vty_out(vty, "No BGP process is configured\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
/* make sure it's still in list */
if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) {
/* Not in list anymore */
struct rfapi_l2_group_cfg *rfg;
VTY_DECLVAR_CONTEXT(bgp, bgp);
- if (!bgp) {
- vty_out(vty, "No BGP process is configured\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
/* Search for name */
rfg = rfapi_l2_group_lookup_byname(bgp, argv[1]->arg);
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- if (!bgp) {
- vty_out(vty, "No BGP process is configured\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
return bgp_rfapi_delete_named_l2_group(vty, bgp, argv[3]->arg);
}
VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
VTY_DECLVAR_CONTEXT(bgp, bgp);
- if (!bgp) {
- vty_out(vty, "No BGP process is configured\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
/* make sure it's still in list */
if (!listnode_lookup(bgp->rfapi_cfg->l2_groups, rfg)) {
/* Not in list anymore */
VTY_DECLVAR_CONTEXT(bgp, bgp);
struct list *ll;
- if (!bgp) {
- vty_out(vty, "No BGP process is configured\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
/* make sure it's still in list */
if (!listnode_lookup(bgp->rfapi_cfg->l2_groups, rfg)) {
/* Not in list anymore */
VTY_DECLVAR_CONTEXT(bgp, bgp);
struct list *ll;
- if (!bgp) {
- vty_out(vty, "No BGP process is configured\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
/* make sure it's still in list */
if (!listnode_lookup(bgp->rfapi_cfg->l2_groups, rfg)) {
/* Not in list anymore */
vty_out(vty, "Unknown option, %s\n", argv[1]->arg);
return CMD_ERR_NO_MATCH;
}
- if (!bgp) {
- vty_out(vty, "No BGP process is configured\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
/* make sure it's still in list */
if (!listnode_lookup(bgp->rfapi_cfg->l2_groups, rfg)) {
default:
/* not expected */
+ zlog_err("%s: bad safi %d", __func__, safi);
return NULL;
}
- zlog_err("%s: bad safi %d", __func__, safi);
- return NULL;
}
void rfapiProcessUpdate(struct peer *peer,
dnl always want these CFLAGS
AC_C_FLAG([-fno-omit-frame-pointer])
+AC_C_FLAG([-funwind-tables])
AC_C_FLAG([-Wall])
AC_C_FLAG([-Wextra])
AC_C_FLAG([-Wmissing-prototypes])
AS_HELP_STRING([--with-rfp-path[=DIR]],[path to replaced stub RFP used with BGP VNC]))
AC_ARG_ENABLE(snmp,
AS_HELP_STRING([--enable-snmp=ARG], [enable SNMP support (smux or agentx)]))
+AC_ARG_ENABLE(zeromq,
+ AS_HELP_STRING([--enable-zeromq], [enable ZeroMQ handler (libfrrzmq)]))
AC_ARG_WITH(libpam,
AS_HELP_STRING([--with-libpam], [use libpam for PAM support in vtysh]))
AC_ARG_ENABLE(ospfapi,
)
], [], FRR_INCLUDES)
+dnl ------
+dnl ZeroMQ
+dnl ------
+if test "x$enable_zeromq" != "xno"; then
+ PKG_CHECK_MODULES(ZEROMQ, [libzmq >= 4.0.0], [
+ AC_DEFINE(HAVE_ZEROMQ, 1, [Enable ZeroMQ support])
+ ZEROMQ=true
+ ], [
+ if test "x$enable_zeromq" = "xyes"; then
+ AC_MSG_ERROR([configuration specifies --enable-zeromq but libzmq was not found])
+ fi
+ ])
+fi
+AM_CONDITIONAL([ZEROMQ], test "x$ZEROMQ" = "xtrue")
+
dnl ----------
dnl configure date
dnl ----------
doc/watchfrr.8
doc/zebra.8
doc/frr.1
+ doc/frr-args.8
pkgsrc/bgpd.sh pkgsrc/ospf6d.sh pkgsrc/ospfd.sh
pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh
pkgsrc/eigrpd.sh])
usr/share/man/man8/zebra.8
usr/share/man/man8/isisd.8
usr/share/man/man8/watchfrr.8
+usr/share/man/man8/frr-args.8
usr/share/snmp/mibs/
tools/etc/* etc/
tools/*.service lib/systemd/system
# because it cant just work from the png's directly it seems - contrary
# to the documentation...
frr.pdf: $(info_TEXINFOS) $(figures_pdf) $(frr_TEXINFOS) defines.texi
- $(TEXI2PDF) -o "$@" $<
+ $(TEXI2PDF) -o "$@" $< || true
# don't ask me why the info file is in srcdir
$(srcdir)/frr.info: $(frr_TEXINFOS) defines.texi
.dia.png:
$(DIATOPNG) "$@" $<
-man_MANS = frr.1
+man_MANS = frr.1 frr-args.8
if PIMD
man_MANS += pimd.8
use should be avoided.
@end deffn
-@c for some reason, using [all] here triggers a bug in texinfo...
-@deffn {BGP} {neighbor @var{peer} next-hop-self} {}
-@deffnx {BGP} {no neighbor @var{peer} next-hop-self} {}
-@deffnx {BGP} {neighbor @var{peer} next-hop-self all} {}
-@deffnx {BGP} {no neighbor @var{peer} next-hop-self all} {}
+@deffn {BGP} {neighbor @var{peer} next-hop-self [all]} {}
+@deffnx {BGP} {no neighbor @var{peer} next-hop-self [all]} {}
This command specifies an announced route's nexthop as being equivalent
to the address of the bgp router if it is learned via eBGP.
If the optional keyword @code{all} is specified the modifiation is done
--- /dev/null
+.TH frr-args 8 "28 August 2017" "@PACKAGE_FULLNAME@ general options" "Version @PACKAGE_VERSION@"
+.SH NAME
+frr-args \- common command line options for all @PACKAGE_FULLNAME@ daemons.
+.SH SYNOPSIS
+<\fBzebra\fR|\fBbgpd\fR|\fB...\fR>
+[\fB\-h\fR] [\fB\-v\fR]
+
+<\fBzebra\fR|\fBbgpd\fR|\fB...\fR>
+[\fB\-d\fR|\fB\-t\fR|\fB\-dt\fR]
+[\fB\-C\fR]
+[\fB\-f\fR \fIconfig-file\fR]
+[\fB\-i\fR \fIpid-file\fR]
+[\fB\-z\fR \fIzclient-path\fR]
+[\fB\-u\fR \fIuser\fR]
+[\fB\-g\fR \fIgroup\fR]
+[\fB\-A\fR \fIvty-addr\fR]
+[\fB\-P\fR \fIvty-port\fR]
+[\fB\-M\fR \fImodule\fR[\fB:\fIoptions\fR]]
+[\fB\-N\fR \fIpathspace\fR]
+[\fB\-\-vty_socket\fR \fIvty-path\fR]
+[\fB\-\-moduledir\fR \fImodule-path\fR]
+
+.SH DESCRIPTION
+@PACKAGE_NAME@ daemons share a large part of their command line options;
+this man page documents these. For options on specific daemons please refer
+to their respective man pages. Most of the common options are related to
+process control, configuration and common library functionality.
+
+.SH HELP AND VERSION
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+Print a short description of the daemon's command line options.
+.TP
+\fB\-v\fR, \fB\-\-version\fR
+Print version and build information for the daemon.
+.PP
+Both of these options inhibit normal operation and will immediately exit.
+
+.SH PROCESS CONTROL
+These options control background operation:
+.TP
+\fB\-d\fR, \fB\-\-daemon\fR
+Launches the process in background/daemon mode, forking and detaching from
+the terminal.
+
+The parent process will delay its exit until the daemon/child has finished
+its initialization and has entered its main loop. This is important for
+\fBzebra\fR startup because the other daemons will attempt to connect to
+\fBzebra\fR. A return from \fBzebra -d\fR guarantees its readiness to
+accept these connections.
+.TP
+\fB\-t\fR, \fB\-\-terminal\fR
+Opens an interactive VTY session on the terminal, allowing for both state
+and configuration operations. Note that the terminal starts operating after
+startup has completed and the configuration file has been loaded.
+
+The process will exit when end of file is detected on the terminal. It is
+possible to daemonize a process started with \fB-t\fR (but without \fB-d\fR)
+by sending \fISIGQUIT\fR to the process (normally mapped to a \fI^\\\fR
+keypress.)
+.TP
+\fB\-dt\fR, \fB\-\-daemon \-\-terminal\fR
+This combination of the previous two options will delay the daemon from
+going into background until the terminal session ends (by end of file.)
+
+If the process receives \fISIGINT\fR (e.g. a \fI^C\fR keypress) in this
+mode, it will exit instead of daemonizing.
+.PP
+It is safe to suspend (\fISIGTSTP\fR / \fI^Z\fR) the terminal session
+opened by the previous two options; this will only stop the terminal but
+not the protocol daemon itself (which runs in a separate second process.)
+
+.SH CONFIGURATION AND PATHS
+The following options control configuration and file system locations for
+@PACKAGE_NAME@ processes:
+.TP
+\fB\-f\fR, \fB\-\-config_file\fR \fIconfig-file\fR
+Specify a configuration file to be used instead of the default
+\fB\fI@CFG_SYSCONF@/<daemon>.conf\fR file.
+
+Note that the daemon will attempt to write to this file if the
+\fIwrite file\fR command is issued on its VTY interface or through
+\fBvtysh\fR.
+.TP
+\fB\-C\fR, \fB\-\-dryrun\fR
+Load the configuration file and check its validity, then exit.
+.TP
+\fB\-i\fR, \fB\-\-pid_file\fR \fIpid-file\fR
+Output a pid file to a location other than the default
+\fB\fI@CFG_STATE@/<daemon>.pid\fR.
+.TP
+\fB\-z\fR, \fB\-\-socket\fR \fIzclient-path\fR
+Override the path of the ZAPI socket used to communicate between \fBzebra\fR
+and the various protocol daemons. The default is
+\fB\fI@CFG_STATE@/zserv.api\fR. The value of this option must be the same
+across all daemons.
+.TP
+\fB\-N\fR, \fB\-\-pathspace\fR \fIpathspace\fR
+Insert \fIpathspace\fR into all default paths, changing the defaults to:
+.IP
+\fB@CFG_SYSCONF@/\fIpathspace\fB/<daemon>.conf\fR
+.br
+\fB@CFG_STATE@/\fIpathspace\fB/<daemon>.pid\fR
+.br
+\fB@CFG_STATE@/\fIpathspace\fB/<daemon>.vty\fR
+.br
+\fB@CFG_STATE@/\fIpathspace\fB/zserv.api\fR
+
+\'.\' and \'/\' characters will not be accepted in \fIpathspace\fR, but the
+empty string will be accepted.
+
+Note that this only changes the respective defaults, it has no effect on
+the respective path if the \fB\-f\fR, \fB\-i\fR, \fB\-z\fR or
+\fB\-\-vty_socket\fR options are used.
+
+The purpose of this option is to easily group all file system related
+bits together for running multiple fully-separate "logical routers" on a
+system, particularly with Linux network namespaces. Groups of daemons
+running with distinct \fIpathspace\fR values will be completely unaware
+of each other and not interact in any way.
+
+This option does not do any system setup (like network namespaces.) This
+must be done by the user, for example by running:
+.IP
+\fBip netns exec \fInamespace \fB<daemon> -N \fInamespace\fR
+
+.SH PROCESS CREDENTIALS
+.TP
+\fB\-u\fR, \fB\-\-user\fR \fIuser\fR
+(default: \fB@enable_user@\fR)
+.TP
+\fB\-g\fR, \fB\-\-group\fR \fIgroup\fR
+(default: \fB@enable_group@\fR)
+.IP
+Change the user/group which the daemon will switch to.
+.PP
+Note that there is an additional group, \fB@enable_vty_group@\fR, which
+controls group ownership of the VTY sockets. The name of this group cannot
+currently be changed, and \fIuser\fR must be a member of this group.
+
+.SH VTY SETUP
+These following options control the daemon's VTY (interactive command line)
+interface. The interface is available over TCP, using the telnet protocol,
+as well as through the \fBvtysh\fR frontend.
+.TP
+\fB\-A\fR, \fB--vty_addr\fR \fIvty-addr\fR
+Specify an IP/IPv6 address to bind the TCP VTY interface to. It is
+generally recommended to specify \fI::1\fR or \fI127.0.0.1\fR. For reasons
+of backwards compatibility, the default is to listen on all interfaces.
+.TP
+\fB\-P\fR, \fB--vty_port\fR \fIvty-port\fR
+Override the daemon's default TCP VTY port (each daemon has a different
+default value upwards of 2600, listed below.) Specifying \fI0\fR disables
+the TCP VTY interface.
+
+Default ports are:
+
+.ta 16m
+zebra 2601
+.br
+ripd 2602
+.br
+ripngd 2603
+.br
+ospfd 2604
+.br
+bgpd 2605
+.br
+ospf6d 2606
+.br
+isisd 2608
+.br
+babeld 2609
+.br
+nhrpd 2610
+.br
+pimd 2611
+.br
+ldpd 2612
+.br
+eigrpd 2613
+
+Port 2607 is used for ospfd's Opaque LSA API, while port 2600 is used for
+the (insecure) TCP-ZEBRA interface.
+.TP
+\fB\-\-vty_socket\fR \fIvty-path\fR
+Overrides the directory used for the \fB<daemon>.vty\fR sockets.
+\fBvtysh\fR connects to these sockets in order to access each daemon's
+VTY.
+.br
+Default: \fB\fI@CFG_STATE@\fR[\fB/\fI<pathspace>\fR]
+
+NB: Unlike the other options, this option specifies a \fBdirectory\fR,
+not a full path.
+
+This option is primarily used by the SNAP packaging system, its semantics
+may change. It should not be neccessary in most other scenarios.
+
+.SH MODULE LOADING
+@PACKAGE_NAME@ supports optional dynamically loadable modules, although
+these can only be loaded at startup. The set of available modules may vary
+across distributions and packages, and modules may be available for
+installation as separate packages.
+.TP
+\fB\-M\fR, \fB\-\-module\fR \fImodule\fR[\fB:\fIoptions\fR]
+Load a module named \fImodule\fR, optionally passing \fIoptions\fR to it.
+
+If there is a \'/\' character in \fImodule\fR, the value is assumed to be
+a pathname to a module.
+
+If there is no \'/\' character, the module directory (see next option)
+is searched first for a module named "\fI<daemon>\fB_\fI<module>\fB.so\fR",
+then for "\fI<module>\fB.so\fR".
+This allows for a module to exist in variations appropriate for particular
+daemons, e.g. \fIzebra_snmp\fR and \fIbgp_snmp\fR, with the correct one
+selected by \fI\-M snmp\fR.
+
+The meaning of \fIoptions\fR is specific to the module being loaded. Most
+modules currently ignore it.
+
+Modules are loaded in the order as listed on the command line. This is
+not generally relevant.
+.TP
+\fB\-\-moduledir\fR \fImodule-path\fR
+Look for modules in the \fImodule-path\fR directory instead of the default
+\fI@CFG_MODULE@\fR. (This path is \fBnot\fR affected by the \fB\-N\fR
+option.)
+.PP
+The list of loaded modules can be inspected at runtime with the
+\fBshow modules\fR VTY command.
+
+
+.SH "SEE ALSO"
+.BR zebra (8),
+.BR vtysh (1),
+.BR ripd (8),
+.BR ripngd (8),
+.BR ospfd (8),
+.BR ospf6d (8),
+.BR bgpd (8),
+.BR isisd (8),
+.BR babeld (8),
+.BR nhrpd (8),
+.BR pimd (8),
+.BR ldpd (8),
+.BR eigrpd (8)
+
+\fIhttps://frrouting.org/
Set the IPv4 or IPv6 address/prefix for the interface.
@end deffn
+@deffn {Interface Command} {ip address @var{local-addr} peer @var{peer-addr/prefix}} {}
+@deffnx {Interface Command} {no ip address @var{local-addr} peer @var{peer-addr/prefix}} {}
+Configure an IPv4 Pointopoint address on the interface.
+(The concept of PtP addressing does not exist for IPv6.)
+
+@var{local-addr} has no subnet mask since the local side in PtP
+addressing is always a single (/32) address. @var{peer-addr/prefix}
+can be an arbitrary subnet behind the other end of the link (or even on the
+link in Point-to-Multipoint setups), though generally /32s are used.
+@end deffn
+
@deffn {Interface Command} {ip address @var{address/prefix} secondary} {}
@deffnx {Interface Command} {no ip address @var{address/prefix} secondary} {}
Set the secondary flag for this address. This causes ospfd to not treat the
vty_out(vty, "%s, ",
prefix2str(tn->destination, buffer, PREFIX_STRLEN));
- vty_out(vty, "%u successors, ", successors->count);
+ vty_out(vty, "%u successors, ",
+ (successors) ? successors->count : 0);
vty_out(vty, "FD is %u, serno: %" PRIu64 " \n", tn->fdistance,
tn->serno);
- list_delete(successors);
+ if (successors)
+ list_delete(successors);
}
void show_ip_eigrp_neighbor_entry(struct vty *vty, struct eigrp *eigrp,
{
char ver_string[] = VERSION;
char *dash = strstr(ver_string, "-");
+ int ret;
if (dash)
dash[0] = '\0';
- sscanf(ver_string, "%d.%d", &FRR_MAJOR, &FRR_MINOR);
+ ret = sscanf(ver_string, "%d.%d", &FRR_MAJOR, &FRR_MINOR);
+ if (ret != 2)
+ zlog_err("Did not Properly parse %s, please fix VERSION string",
+ VERSION);
}
/**
struct eigrp_metrics metric;
struct eigrp_interface *ei2;
struct listnode *node, *nnode;
- struct eigrp *eigrp = eigrp_lookup();
+ struct eigrp *eigrp;
if (ei == NULL)
return 0;
- if (eigrp != NULL)
- eigrp_adjust_sndbuflen(eigrp, ei->ifp->mtu);
- else
- zlog_warn("%s: eigrp_lookup () returned NULL", __func__);
+ eigrp = ei->eigrp;
+ eigrp_adjust_sndbuflen(eigrp, ei->ifp->mtu);
+
eigrp_if_stream_set(ei);
/* Set multicast memberships appropriately for new state. */
if (keychain)
key = key_lookup_for_send(keychain);
+ if (!key) {
+ zlog_warn("Interface %s: Expected key value not found in config",
+ nbr->ei->ifp->name);
+ return 0;
+ }
+
memset(&ctx, 0, sizeof(ctx));
MD5Init(&ctx);
}
/* save neighbor's crypt_seqnum */
- if (nbr)
- nbr->crypt_seqnum = authTLV->key_sequence;
+ nbr->crypt_seqnum = authTLV->key_sequence;
return 1;
}
{
struct key *key = NULL;
struct keychain *keychain;
- char *source_ip;
+ char source_ip[PREFIX_STRLEN];
unsigned char digest[EIGRP_AUTH_TYPE_SHA256_LEN];
unsigned char buffer[1 + PLAINTEXT_LENGTH + 45 + 1] = {0};
+
HMAC_SHA256_CTX ctx;
void *ibuf;
size_t backup_get, backup_end;
if (keychain)
key = key_lookup_for_send(keychain);
- // saved_len[index] = strnzcpyn(saved_key[index], key,
- // PLAINTEXT_LENGTH + 1);
+ if (!key) {
+ zlog_warn("Interface %s: Expected key value not found in config",
+ ei->ifp->name);
+ return 0;
+ }
- source_ip = calloc(16, sizeof(char));
- inet_ntop(AF_INET, &ei->address->u.prefix4, source_ip, 16);
+ inet_ntop(AF_INET, &ei->address->u.prefix4, source_ip, PREFIX_STRLEN);
memset(&ctx, 0, sizeof(ctx));
buffer[0] = '\n';
stream_set_endp(s, backup_end);
eigrp_authTLV_SHA256_free(auth_TLV);
- free(source_ip);
return EIGRP_AUTH_TYPE_SHA256_LEN;
}
opcode = eigrph->opcode;
if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) {
- char src[100], dst[100];
+ char src[PREFIX_STRLEN], dst[PREFIX_STRLEN];
- strcpy(src, inet_ntoa(iph->ip_src));
- strcpy(dst, inet_ntoa(iph->ip_dst));
+ strncpy(src, inet_ntoa(iph->ip_src), PREFIX_STRLEN);
+ strncpy(dst, inet_ntoa(iph->ip_dst), PREFIX_STRLEN);
zlog_debug("Received [%s][%d/%d] length [%u] via [%s] src [%s] dst [%s]",
lookup_msg(eigrp_packet_type_str, opcode, NULL),
ntohl(eigrph->sequence), ntohl(eigrph->ack), length,
{
int ret;
ret = route_map_add_match(index, command, arg);
- if (ret) {
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% Can't find rule.\n");
- return CMD_WARNING_CONFIG_FAILED;
- case RMAP_COMPILE_ERROR:
- vty_out(vty, "%% Argument is malformed.\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
+ switch (ret) {
+ case RMAP_RULE_MISSING:
+ vty_out(vty, "%% Can't find rule.\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out(vty, "%% Argument is malformed.\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_SUCCESS:
+ break;
}
+
return CMD_SUCCESS;
}
{
int ret;
ret = route_map_delete_match(index, command, arg);
- if (ret) {
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% Can't find rule.\n");
- return CMD_WARNING_CONFIG_FAILED;
- case RMAP_COMPILE_ERROR:
- vty_out(vty, "%% Argument is malformed.\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
+ switch (ret) {
+ case RMAP_RULE_MISSING:
+ vty_out(vty, "%% Can't find rule.\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out(vty, "%% Argument is malformed.\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_SUCCESS:
+ break;
}
+
return CMD_SUCCESS;
}
int ret;
ret = route_map_add_set(index, command, arg);
- if (ret) {
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% Can't find rule.\n");
+ switch (ret) {
+ case RMAP_RULE_MISSING:
+ vty_out(vty, "%% Can't find rule.\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_ERROR:
+ /*
+ * rip, ripng and other protocols share the set metric command
+ * but only values from 0 to 16 are valid for rip and ripng
+ * if metric is out of range for rip and ripng, it is
+ * not for other protocols. Do not return an error
+ */
+ if (strcmp(command, "metric")) {
+ vty_out(vty, "%% Argument is malformed.\n");
return CMD_WARNING_CONFIG_FAILED;
- case RMAP_COMPILE_ERROR:
- /* rip, ripng and other protocols share the set metric
- command
- but only values from 0 to 16 are valid for rip and
- ripng
- if metric is out of range for rip and ripng, it is
- not for
- other protocols. Do not return an error */
- if (strcmp(command, "metric")) {
- vty_out(vty, "%% Argument is malformed.\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
}
+ break;
+ case RMAP_COMPILE_SUCCESS:
+ break;
}
+
return CMD_SUCCESS;
}
int ret;
ret = route_map_delete_set(index, command, arg);
- if (ret) {
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% Can't find rule.\n");
- return CMD_WARNING_CONFIG_FAILED;
- case RMAP_COMPILE_ERROR:
- vty_out(vty, "%% Argument is malformed.\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
+ switch (ret) {
+ case RMAP_RULE_MISSING:
+ vty_out(vty, "%% Can't find rule.\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out(vty, "%% Argument is malformed.\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_SUCCESS:
+ break;
}
+
return CMD_SUCCESS;
}
for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry)) {
if (((uint64_t)entry->distance
- <= (uint64_t)(dest->distance * eigrp->variance))
+ <= (uint64_t)dest->distance * (uint64_t)eigrp->variance)
&& entry->distance != EIGRP_MAX_METRIC) // is successor
{
entry->flags |= EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
eigrp_query_send_all(eigrp);
eigrp_update_send_all(eigrp, ei);
+
+ if (nbr_prefixes)
+ list_delete(nbr_prefixes);
}
/*send EIGRP Update packet*/
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) {
- vty_out(vty, "interface %s\n", ei->ifp->name);
+ vty_frame(vty, "interface %s\n", ei->ifp->name);
if ((IF_DEF_PARAMS(ei->ifp)->auth_type)
== EIGRP_AUTH_TYPE_MD5) {
}
/*Separate this EIGRP interface configuration from the others*/
- vty_out(vty, "!\n");
+ vty_endframe(vty, "!\n");
}
return 0;
struct interface *ifp;
for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
- vty_out(vty, "interface %s\n", ifp->name);
+ vty_frame(vty, "interface %s\n", ifp->name);
if (ifp->desc)
vty_out(vty, " description %s\n", ifp->desc);
vty_out(vty, " ip hold-time eigrp %u\n",
IF_DEF_PARAMS(ifp)->v_wait);
- vty_out(vty, "!\n");
+ vty_endframe(vty, "!\n");
}
return 0;
struct eigrp_neighbor *nbr;
struct in_addr nbr_addr;
- inet_aton(argv[4]->arg, &nbr_addr);
+ if (!inet_aton(argv[4]->arg, &nbr_addr)) {
+ vty_out(vty, "Unable to parse %s",
+ argv[4]->arg);
+ return CMD_WARNING;
+ }
/* Check if eigrp process is enabled */
eigrp = eigrp_lookup();
struct eigrp_neighbor *nbr;
struct in_addr nbr_addr;
- inet_aton(argv[4]->arg, &nbr_addr);
+ if (!inet_aton(argv[4]->arg, &nbr_addr)) {
+ vty_out(vty, "Unable to parse: %s",
+ argv[4]->arg);
+ return CMD_WARNING;
+ }
/* Check if eigrp process is enabled */
eigrp = eigrp_lookup();
continue;
/* IF name */
- vty_out(vty, "interface %s\n", ifp->name);
+ vty_frame(vty, "interface %s\n", ifp->name);
write++;
/* IF desc */
if (ifp->desc) {
}
write += circuit_write_mt_settings(circuit, vty);
}
- vty_out(vty, "!\n");
+ vty_endframe(vty, "!\n");
}
return write;
}
vty_out(vty, " * %s %s\n", sysid_print(isis->sysid),
- unix_hostname());
+ cmd_hostname_get());
return;
}
return LSP_OLDER;
}
-static void put_lsp_hdr(struct isis_lsp *lsp, size_t *len_pointer)
+static void put_lsp_hdr(struct isis_lsp *lsp, size_t *len_pointer, bool keep)
{
uint8_t pdu_type =
(lsp->level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE;
struct isis_lsp_hdr *hdr = &lsp->hdr;
struct stream *stream = lsp->pdu;
+ size_t orig_getp, orig_endp;
+
+ if (keep) {
+ orig_getp = stream_get_getp(lsp->pdu);
+ orig_endp = stream_get_endp(lsp->pdu);
+ }
+
+ stream_set_getp(lsp->pdu, 0);
+ stream_set_endp(lsp->pdu, 0);
fill_fixed_hdr(pdu_type, stream);
stream_putl(stream, hdr->seqno);
stream_putw(stream, hdr->checksum);
stream_putc(stream, hdr->lsp_bits);
+
+ if (keep) {
+ stream_set_endp(lsp->pdu, orig_endp);
+ stream_set_getp(lsp->pdu, orig_getp);
+ }
}
static void lsp_add_auth(struct isis_lsp *lsp)
lsp_add_auth(lsp);
size_t len_pointer;
- stream_reset(lsp->pdu);
- put_lsp_hdr(lsp, &len_pointer);
+ put_lsp_hdr(lsp, &len_pointer, false);
isis_pack_tlvs(lsp->tlvs, lsp->pdu, len_pointer, false, true);
lsp->hdr.pdu_len = stream_get_endp(lsp->pdu);
lsp->own_lsp = 0;
}
+ lsp_update_data(lsp, hdr, tlvs, stream, area, level);
if (confusion) {
- lsp_clear_data(lsp);
- if (lsp->pdu != NULL)
- stream_free(lsp->pdu);
- lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
- lsp->age_out = ZERO_AGE_LIFETIME;
- lsp->hdr.rem_lifetime = 0;
- lsp_pack_pdu(lsp);
- } else {
- lsp_update_data(lsp, hdr, tlvs, stream, area, level);
+ lsp->hdr.rem_lifetime = hdr->rem_lifetime = 0;
+ put_lsp_hdr(lsp, NULL, true);
}
/* insert the lsp back into the database */
lsp->level = level;
lsp->age_out = ZERO_AGE_LIFETIME;
lsp_link_fragment(lsp, lsp0);
- put_lsp_hdr(lsp, NULL);
+ put_lsp_hdr(lsp, NULL, false);
if (isis->debugs & DEBUG_EVENTS)
zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
if (dyn)
sprintf((char *)id, "%.14s", dyn->hostname);
else if (!memcmp(isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
- sprintf((char *)id, "%.14s", unix_hostname());
+ sprintf((char *)id, "%.14s", cmd_hostname_get());
else
memcpy(id, sysid_print(lsp_id), 15);
if (frag)
}
/* Dynamic Hostname */
if (area->dynhostname) {
- isis_tlvs_set_dynamic_hostname(lsp->tlvs, unix_hostname());
+ isis_tlvs_set_dynamic_hostname(lsp->tlvs, cmd_hostname_get());
lsp_debug("ISIS (%s): Adding dynamic hostname '%s'",
- area->area_tag, unix_hostname());
+ area->area_tag, cmd_hostname_get());
} else {
lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
area->area_tag);
return new_prefix;
}
-/*
- * Returns host.name if any, otherwise
- * it returns the system hostname.
- */
-const char *unix_hostname(void)
-{
- static struct utsname names;
- const char *hostname;
-
- hostname = host.name;
- if (!hostname) {
- uname(&names);
- hostname = names.nodename;
- }
-
- return hostname;
-}
-
/*
* Returns the dynamic hostname associated with the passed system ID.
* If no dynamic hostname found then returns formatted system ID.
/* For our system ID return our host name */
if (memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN) == 0)
- return unix_hostname();
+ return cmd_hostname_get();
dyn = dynhn_find_by_id(sysid);
if (dyn)
* misc functions
*/
unsigned long isis_jitter(unsigned long timer, unsigned long jitter);
-const char *unix_hostname(void);
/*
* macros
/*
* C.2.7 Step 2
*/
- if (isis_vertex_queue_count(&spftree->tents) == 0) {
+ if (!isis_vertex_queue_count(&spftree->tents)
+ && (isis->debugs & DEBUG_SPF_EVENTS)) {
zlog_warn("ISIS-Spf: TENT is empty SPF-root:%s",
print_sys_hostname(sysid));
- goto out;
}
while (isis_vertex_queue_count(&spftree->tents)) {
lsp = lsp_search(
lspid,
area->lspdb[level]);
- } else if (strncmp(unix_hostname(),
+ } else if (strncmp(cmd_hostname_get(),
sysid, 15)
== 0) {
memcpy(lspid, isis->sysid,
/* Host information structure. */
struct host host;
+/*
+ * Returns host.name if any, otherwise
+ * it returns the system hostname.
+ */
+const char *cmd_hostname_get(void)
+{
+ return host.name;
+}
+
+/*
+ * Returns unix domainname
+ */
+const char *cmd_domainname_get(void)
+{
+ return host.domainname;
+}
+
/* Standard command node structures. */
static struct cmd_node auth_node = {
AUTH_NODE, "Password: ",
/* This function write configuration of this host. */
static int config_write_host(struct vty *vty)
{
- if (host.name)
- vty_out(vty, "hostname %s\n", host.name);
+ if (cmd_hostname_get())
+ vty_out(vty, "hostname %s\n", cmd_hostname_get());
if (host.encrypt) {
if (host.password_encrypt)
"Displays zebra version\n")
{
vty_out(vty, "%s %s (%s).\n", FRR_FULL_NAME, FRR_VERSION,
- host.name ? host.name : "");
+ cmd_hostname_get() ? cmd_hostname_get() : "");
vty_out(vty, "%s%s\n", FRR_COPYRIGHT, GIT_INFO);
vty_out(vty, "configured with:\n %s\n", FRR_CONFIG_ARGS);
return CMD_SUCCESS;
}
+int cmd_domainname_set(const char *domainname)
+{
+ XFREE(MTYPE_HOST, host.domainname);
+ host.domainname = domainname ? XSTRDUP(MTYPE_HOST, domainname) : NULL;
+ return CMD_SUCCESS;
+}
+
+/* Hostname configuration */
+DEFUN(config_domainname,
+ domainname_cmd,
+ "domainname WORD",
+ "Set system's domain name\n"
+ "This system's domain name\n")
+{
+ struct cmd_token *word = argv[1];
+
+ if (!isalpha((int)word->arg[0])) {
+ vty_out(vty, "Please specify string starting with alphabet\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return cmd_domainname_set(word->arg);
+}
+
+DEFUN(config_no_domainname,
+ no_domainname_cmd,
+ "no domainname [DOMAINNAME]",
+ NO_STR
+ "Reset system's domain name\n"
+ "domain name of this router\n")
+{
+ return cmd_domainname_set(NULL);
+}
+
int cmd_hostname_set(const char *hostname)
{
XFREE(MTYPE_HOST, host.name);
* terminal = -1 -- watchfrr / no logging, but minimal config control */
void cmd_init(int terminal)
{
+ struct utsname names;
+
if (array_size(node_names) != NODE_TYPE_MAX)
assert(!"Update the CLI node description array!");
+ uname(&names);
qobj_init();
varhandlers = list_new();
cmdvec = vector_init(VECTOR_MIN_SIZE);
/* Default host value settings. */
- host.name = NULL;
+ host.name = XSTRDUP(MTYPE_HOST, names.nodename);
+#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME
+ if ((strcmp(names.domainname, "(none)") == 0))
+ host.domainname = NULL;
+ else
+ host.domainname = XSTRDUP(MTYPE_HOST, names.domainname);
+#else
+ host.domainname = NULL;
+#endif
host.password = NULL;
host.enable = NULL;
host.logfile = NULL;
install_element(CONFIG_NODE, &hostname_cmd);
install_element(CONFIG_NODE, &no_hostname_cmd);
+ install_element(CONFIG_NODE, &domainname_cmd);
+ install_element(CONFIG_NODE, &no_domainname_cmd);
install_element(CONFIG_NODE, &frr_version_defaults_cmd);
install_element(CONFIG_NODE, &debug_memstats_cmd);
if (host.name)
XFREE(MTYPE_HOST, host.name);
+ if (host.domainname)
+ XFREE(MTYPE_HOST, host.domainname);
if (host.password)
XFREE(MTYPE_HOST, host.password);
if (host.password_encrypt)
/* Host name of this router. */
char *name;
+ /* Domainname of this router */
+ char *domainname;
+
/* Password for vty interface. */
char *password;
char *password_encrypt;
extern void cmd_exit(struct vty *vty);
extern int cmd_list_cmds(struct vty *vty, int do_permute);
+extern int cmd_domainname_set(const char *domainname);
extern int cmd_hostname_set(const char *hostname);
+extern const char *cmd_hostname_get(void);
+extern const char *cmd_domainname_get(void);
/* NOT safe for general use; call this only if DEV_BUILD! */
extern void grammar_sandbox_init(void);
--- /dev/null
+/*
+ * libzebra ZeroMQ bindings
+ * Copyright (C) 2015 David Lamparter
+ *
+ * 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 <zmq.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "frr_zmq.h"
+#include "log.h"
+
+DEFINE_MTYPE_STATIC(LIB, ZEROMQ_CB, "ZeroMQ callback")
+
+/* libzmq's context */
+void *frrzmq_context = NULL;
+static unsigned frrzmq_initcount = 0;
+
+void frrzmq_init(void)
+{
+ if (frrzmq_initcount++ == 0) {
+ frrzmq_context = zmq_ctx_new();
+ zmq_ctx_set(frrzmq_context, ZMQ_IPV6, 1);
+ }
+}
+
+void frrzmq_finish(void)
+{
+ if (--frrzmq_initcount == 0) {
+ zmq_ctx_term(frrzmq_context);
+ frrzmq_context = NULL;
+ }
+}
+
+/* read callback integration */
+struct frrzmq_cb {
+ struct thread *thread;
+ void *zmqsock;
+ void *arg;
+ int fd;
+
+ bool cancelled;
+
+ void (*cb_msg)(void *arg, void *zmqsock);
+ void (*cb_part)(void *arg, void *zmqsock,
+ zmq_msg_t *msg, unsigned partnum);
+};
+
+
+static int frrzmq_read_msg(struct thread *t)
+{
+ struct frrzmq_cb *cb = THREAD_ARG(t);
+ zmq_msg_t msg;
+ unsigned partno;
+ int ret, more;
+ size_t moresz;
+
+ while (1) {
+ zmq_pollitem_t polli = {
+ .socket = cb->zmqsock,
+ .events = ZMQ_POLLIN
+ };
+ ret = zmq_poll(&polli, 1, 0);
+
+ if (ret < 0)
+ goto out_err;
+ if (!(polli.revents & ZMQ_POLLIN))
+ break;
+
+ if (cb->cb_msg) {
+ cb->cb_msg(cb->arg, cb->zmqsock);
+
+ if (cb->cancelled) {
+ XFREE(MTYPE_ZEROMQ_CB, cb);
+ return 0;
+ }
+ continue;
+ }
+
+ partno = 0;
+ if (zmq_msg_init(&msg))
+ goto out_err;
+ do {
+ ret = zmq_msg_recv(&msg, cb->zmqsock, ZMQ_NOBLOCK);
+ if (ret < 0) {
+ if (errno == EAGAIN)
+ break;
+
+ zmq_msg_close(&msg);
+ goto out_err;
+ }
+
+ cb->cb_part(cb->arg, cb->zmqsock, &msg, partno);
+ if (cb->cancelled) {
+ zmq_msg_close(&msg);
+ XFREE(MTYPE_ZEROMQ_CB, cb);
+ return 0;
+ }
+
+ /* cb_part may have read additional parts of the
+ * message; don't use zmq_msg_more here */
+ moresz = sizeof(more);
+ more = 0;
+ ret = zmq_getsockopt(cb->zmqsock, ZMQ_RCVMORE,
+ &more, &moresz);
+ if (ret < 0) {
+ zmq_msg_close(&msg);
+ goto out_err;
+ }
+
+ partno++;
+ } while (more);
+ zmq_msg_close(&msg);
+ }
+
+ funcname_thread_add_read_write(THREAD_READ, t->master, frrzmq_read_msg,
+ cb, cb->fd, &cb->thread, t->funcname, t->schedfrom,
+ t->schedfrom_line);
+ return 0;
+
+out_err:
+ zlog_err("ZeroMQ error: %s(%d)", strerror (errno), errno);
+ return 0;
+}
+
+struct frrzmq_cb *funcname_frrzmq_thread_add_read(
+ struct thread_master *master,
+ void (*msgfunc)(void *arg, void *zmqsock),
+ void (*partfunc)(void *arg, void *zmqsock,
+ zmq_msg_t *msg, unsigned partnum),
+ void *arg, void *zmqsock, debugargdef)
+{
+ int fd, events;
+ size_t len;
+ struct frrzmq_cb *cb;
+
+ if (!(msgfunc || partfunc) || (msgfunc && partfunc))
+ return NULL;
+ len = sizeof(fd);
+ if (zmq_getsockopt(zmqsock, ZMQ_FD, &fd, &len))
+ return NULL;
+ len = sizeof(events);
+ if (zmq_getsockopt(zmqsock, ZMQ_EVENTS, &events, &len))
+ return NULL;
+
+ cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
+ if (!cb)
+ return NULL;
+
+ cb->arg = arg;
+ cb->zmqsock = zmqsock;
+ cb->cb_msg = msgfunc;
+ cb->cb_part = partfunc;
+ cb->fd = fd;
+
+ if (events & ZMQ_POLLIN)
+ funcname_thread_add_event(master,
+ frrzmq_read_msg, cb, fd, &cb->thread,
+ funcname, schedfrom, fromln);
+ else
+ funcname_thread_add_read_write(THREAD_READ, master,
+ frrzmq_read_msg, cb, fd, &cb->thread,
+ funcname, schedfrom, fromln);
+ return cb;
+}
+
+void frrzmq_thread_cancel(struct frrzmq_cb *cb)
+{
+ if (!cb->thread) {
+ /* canceling from within callback */
+ cb->cancelled = 1;
+ return;
+ }
+ thread_cancel(cb->thread);
+ XFREE(MTYPE_ZEROMQ_CB, cb);
+}
--- /dev/null
+/*
+ * libzebra ZeroMQ bindings
+ * Copyright (C) 2015 David Lamparter
+ *
+ * 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 _FRRZMQ_H
+#define _FRRZMQ_H
+
+#include "thread.h"
+#include <zmq.h>
+
+/* linking/packaging note: this is a separate library that needs to be
+ * linked into any daemon/library/module that wishes to use its
+ * functionality. The purpose of this is to encapsulate the libzmq
+ * dependency and not make libfrr/FRR itself depend on libzmq.
+ *
+ * libfrrzmq should be put in LDFLAGS/LIBADD *before* either libfrr or
+ * libzmq, and both of these should always be listed, e.g.
+ * foo_LDFLAGS = libfrrzmq.la libfrr.la $(ZEROMQ_LIBS)
+ */
+
+/* libzmq's context
+ *
+ * this is mostly here as a convenience, it has IPv6 enabled but nothing
+ * else is tied to it; you can use a separate context without problems
+ */
+extern void *frrzmq_context;
+
+extern void frrzmq_init (void);
+extern void frrzmq_finish (void);
+
+#define debugargdef const char *funcname, const char *schedfrom, int fromln
+
+/* core event registration, one of these 2 macros should be used */
+#define frrzmq_thread_add_read_msg(m,f,a,z) funcname_frrzmq_thread_add_read( \
+ m,f,NULL,a,z,#f,__FILE__,__LINE__)
+#define frrzmq_thread_add_read_part(m,f,a,z) funcname_frrzmq_thread_add_read( \
+ m,NULL,f,a,z,#f,__FILE__,__LINE__)
+
+struct frrzmq_cb;
+
+/* Set up a POLLIN notification to be called from the libfrr main loop.
+ * This has the following properties:
+ *
+ * - since ZeroMQ works with edge triggered notifications, it will loop and
+ * dispatch as many events as ZeroMQ has pending at the time libfrr calls
+ * into this code
+ * - due to this looping (which means it non-single-issue), the callback is
+ * also persistent. Do _NOT_ re-register the event inside of your
+ * callback function.
+ * - either msgfunc or partfunc will be called (only one can be specified)
+ * - msgfunc is called once for each incoming message
+ * - if partfunc is specified, the message is read and partfunc is called
+ * for each ZeroMQ multi-part subpart. Note that you can't send replies
+ * before all parts have been read because that violates the ZeroMQ FSM.
+ * - you can safely cancel the callback from within itself
+ * - installing a callback will check for pending events (ZMQ_EVENTS) and
+ * may schedule the event to run as soon as libfrr is back in its main
+ * loop.
+ *
+ * TODO #1: add ZMQ_POLLERR / error callback
+ * TODO #2: add frrzmq_check_events() function to check for edge triggered
+ * things that may have happened after a zmq_send() call or so
+ */
+extern struct frrzmq_cb *funcname_frrzmq_thread_add_read(
+ struct thread_master *master,
+ void (*msgfunc)(void *arg, void *zmqsock),
+ void (*partfunc)(void *arg, void *zmqsock,
+ zmq_msg_t *msg, unsigned partnum),
+ void *arg, void *zmqsock, debugargdef);
+
+extern void frrzmq_thread_cancel(struct frrzmq_cb *cb);
+
+#endif /* _FRRZMQ_H */
/* Library inits. */
cmd_init(1);
host.name = strdup("test");
+ host.domainname = strdup("testdomainname");
vty_init(master);
memory_init();
static const struct option lo_cfg_pid_dry[] = {
{"pid_file", required_argument, NULL, 'i'},
{"config_file", required_argument, NULL, 'f'},
+ {"pathspace", required_argument, NULL, 'N'},
{"dryrun", no_argument, NULL, 'C'},
{"terminal", no_argument, NULL, 't'},
{NULL}};
static const struct optspec os_cfg_pid_dry = {
- "f:i:Ct",
+ "f:i:CtN:",
" -f, --config_file Set configuration file name\n"
" -i, --pid_file Set process identifier file name\n"
+ " -N, --pathspace Insert prefix into config & socket paths\n"
" -C, --dryrun Check configuration for validity and exit\n"
" -t, --terminal Open terminal session on stdio\n"
" -d -t Daemonize after terminal session ends\n",
return 1;
di->config_file = optarg;
break;
+ case 'N':
+ if (di->flags & FRR_NO_CFG_PID_DRY)
+ return 1;
+ if (di->pathspace) {
+ fprintf(stderr,
+ "-N/--pathspace option specified more than once!\n");
+ errors++;
+ break;
+ }
+ if (strchr(optarg, '/') || strchr(optarg, '.')) {
+ fprintf(stderr,
+ "slashes or dots are not permitted in the --pathspace option.\n");
+ errors++;
+ break;
+ }
+ di->pathspace = optarg;
+ break;
case 'C':
if (di->flags & FRR_NO_CFG_PID_DRY)
return 1;
struct option_chain *oc;
struct frrmod_runtime *module;
char moderr[256];
+ char p_instance[16] = "", p_pathspace[256] = "";
const char *dir;
dir = di->module_path ? di->module_path : frr_moduledir;
srandom(time(NULL));
- if (di->instance)
+ if (di->instance) {
snprintf(frr_protonameinst, sizeof(frr_protonameinst), "%s[%u]",
di->logname, di->instance);
+ snprintf(p_instance, sizeof(p_instance), "-%d", di->instance);
+ }
+ if (di->pathspace)
+ snprintf(p_pathspace, sizeof(p_pathspace), "/%s",
+ di->pathspace);
+
+ snprintf(config_default, sizeof(config_default), "%s%s/%s%s.conf",
+ frr_sysconfdir, p_pathspace, di->name, p_instance);
+ snprintf(pidfile_default, sizeof(pidfile_default), "%s%s/%s%s.pid",
+ frr_vtydir, p_pathspace, di->name, p_instance);
zprivs_preinit(di->privs);
{
hook_call(frr_late_init, master);
- if (di->instance) {
- snprintf(config_default, sizeof(config_default),
- "%s/%s-%d.conf", frr_sysconfdir, di->name,
- di->instance);
- snprintf(pidfile_default, sizeof(pidfile_default),
- "%s/%s-%d.pid", frr_vtydir, di->name, di->instance);
- }
-
vty_read_config(di->config_file, config_default);
/* Don't start execution if we are in dry-run mode */
* (not currently set anywhere) */
if (!di->vty_path) {
const char *dir;
- dir = di->vty_sock_path ? di->vty_sock_path : frr_vtydir;
+ char defvtydir[256];
+
+ snprintf(defvtydir, sizeof(defvtydir), "%s%s%s", frr_vtydir,
+ di->pathspace ? "/" : "",
+ di->pathspace ? di->pathspace : "");
+
+ dir = di->vty_sock_path ? di->vty_sock_path : defvtydir;
if (di->instance)
snprintf(vtypath_default, sizeof(vtypath_default),
const char *pid_file;
const char *vty_path;
const char *module_path;
+ const char *pathspace;
const char *proghelp;
void (*printhelp)(FILE *target);
DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label")
/* check if nexthops are same, non-recursive */
-int nexthop_same_no_recurse(struct nexthop *next1, struct nexthop *next2)
+int nexthop_same_no_recurse(const struct nexthop *next1,
+ const struct nexthop *next2)
{
if (next1->type != next2->type)
return 0;
NEXTHOP_TYPE_BLACKHOLE, /* Null0 nexthop. */
};
+enum blackhole_type {
+ BLACKHOLE_UNSPEC = 0,
+ BLACKHOLE_NULL,
+ BLACKHOLE_REJECT,
+ BLACKHOLE_ADMINPROHIB,
+};
+
/* Nexthop label structure. */
struct nexthop_label {
u_int8_t num_labels;
#define NEXTHOP_FLAG_FILTERED (1 << 5) /* rmap filtered, used by static only */
/* Nexthop address */
- union g_addr gate;
+ union {
+ union g_addr gate;
+ enum blackhole_type bh_type;
+ };
union g_addr src;
union g_addr rmap_src; /* Src is set via routemap */
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_same_no_recurse(const struct nexthop *next1,
+ const 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);
int ret;
ret = route_map_add_match(index, command, arg);
- if (ret) {
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% [%s] Can't find rule.\n",
- frr_protonameinst);
- return CMD_WARNING_CONFIG_FAILED;
- case RMAP_COMPILE_ERROR:
- vty_out(vty,
- "%% [%s] Argument form is unsupported or malformed.\n",
- frr_protonameinst);
- return CMD_WARNING_CONFIG_FAILED;
+ switch (ret) {
+ case RMAP_COMPILE_SUCCESS:
+ if (type != RMAP_EVENT_MATCH_ADDED) {
+ route_map_upd8_dependency(type, arg, index->map->name);
}
+ break;
+ case RMAP_RULE_MISSING:
+ vty_out(vty, "%% [%s] Can't find rule.\n",
+ frr_protonameinst);
+ return CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out(vty,
+ "%% [%s] Argument form is unsupported or malformed.\n",
+ frr_protonameinst);
+ return CMD_WARNING_CONFIG_FAILED;
+ break;
}
- if (type != RMAP_EVENT_MATCH_ADDED) {
- route_map_upd8_dependency(type, arg, index->map->name);
- }
return CMD_SUCCESS;
}
route_map_event_t type)
{
int ret;
+ int retval = CMD_SUCCESS;
char *dep_name = NULL;
const char *tmpstr;
char *rmap_name = NULL;
}
ret = route_map_delete_match(index, command, dep_name);
- if (ret) {
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% [%s] Can't find rule.\n",
- frr_protonameinst);
- break;
- case RMAP_COMPILE_ERROR:
- vty_out(vty,
- "%% [%s] Argument form is unsupported or malformed.\n",
- frr_protonameinst);
- break;
- }
- if (dep_name)
- XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
- if (rmap_name)
- XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
- return CMD_WARNING_CONFIG_FAILED;
+ switch (ret) {
+ case RMAP_RULE_MISSING:
+ vty_out(vty, "%% [%s] Can't find rule.\n",
+ frr_protonameinst);
+ retval = CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out(vty,
+ "%% [%s] Argument form is unsupported or malformed.\n",
+ frr_protonameinst);
+ retval = CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_SUCCESS:
+ if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
+ route_map_upd8_dependency(type, dep_name, rmap_name);
+ break;
}
- if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
- route_map_upd8_dependency(type, dep_name, rmap_name);
-
if (dep_name)
XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
if (rmap_name)
XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
- return CMD_SUCCESS;
+ return retval;
}
int generic_set_add(struct vty *vty, struct route_map_index *index,
int ret;
ret = route_map_add_set(index, command, arg);
- if (ret) {
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% [%s] Can't find rule.\n",
- frr_protonameinst);
- return CMD_WARNING_CONFIG_FAILED;
- case RMAP_COMPILE_ERROR:
- vty_out(vty,
- "%% [%s] Argument form is unsupported or malformed.\n",
- frr_protonameinst);
- return CMD_WARNING_CONFIG_FAILED;
- }
+ switch (ret) {
+ case RMAP_RULE_MISSING:
+ vty_out(vty, "%% [%s] Can't find rule.\n",
+ frr_protonameinst);
+ return CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out(vty,
+ "%% [%s] Argument form is unsupported or malformed.\n",
+ frr_protonameinst);
+ return CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_SUCCESS:
+ break;
}
+
return CMD_SUCCESS;
}
int ret;
ret = route_map_delete_set(index, command, arg);
- if (ret) {
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% [%s] Can't find rule.\n",
- frr_protonameinst);
- return CMD_WARNING_CONFIG_FAILED;
- case RMAP_COMPILE_ERROR:
- vty_out(vty,
- "%% [%s] Argument form is unsupported or malformed.\n",
- frr_protonameinst);
- return CMD_WARNING_CONFIG_FAILED;
- }
+ switch (ret) {
+ case RMAP_RULE_MISSING:
+ vty_out(vty, "%% [%s] Can't find rule.\n",
+ frr_protonameinst);
+ return CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out(vty,
+ "%% [%s] Argument form is unsupported or malformed.\n",
+ frr_protonameinst);
+ return CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_SUCCESS:
+ break;
}
+
return CMD_SUCCESS;
}
RMAP_EVENT_CALL_ADDED);
}
- return 0;
+ return RMAP_COMPILE_SUCCESS;
}
/* Delete specified route match rule. */
route_map_notify_dependencies(index->map->name,
RMAP_EVENT_CALL_ADDED);
}
- return 0;
+ return RMAP_COMPILE_SUCCESS;
}
/* Delete route map set rule. */
"Next hop address\n"
"IP address of next hop\n")
{
- int idx;
+ int idx = 0;
VTY_DECLVAR_CONTEXT(route_map_index, index);
const char *arg = NULL;
/* Route map apply error. */
enum {
+ RMAP_COMPILE_SUCCESS,
+
/* Route map rule is missing. */
- RMAP_RULE_MISSING = 1,
+ RMAP_RULE_MISSING,
/* Route map rule can't compile */
RMAP_COMPILE_ERROR
struct sockaddr_in6 sin6;
#ifdef __OpenBSD__
struct sockaddr_mpls smpls;
+ struct sockaddr_rtlabel rtlabel;
#endif
};
lib/snmp.c \
# end
+#
+# ZeroMQ support
+#
+if ZEROMQ
+lib_LTLIBRARIES += lib/libfrrzmq.la
+pkginclude_HEADERS += lib/frr_zmq.h
+endif
+
+lib_libfrrzmq_la_CFLAGS = $(WERROR) $(ZEROMQ_CFLAGS)
+lib_libfrrzmq_la_LDFLAGS = -version-info 0:0:0
+lib_libfrrzmq_la_LIBADD = lib/libfrr.la $(ZEROMQ_LIBS)
+lib_libfrrzmq_la_SOURCES = \
+ lib/frr_zmq.c \
+ #end
+
#
# CLI utilities
#
static int do_log_commands = 0;
+void vty_frame(struct vty *vty, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vsnprintf(vty->frame + vty->frame_pos,
+ sizeof(vty->frame) - vty->frame_pos, format, args);
+ vty->frame_pos = strlen(vty->frame);
+ va_end(args);
+}
+
+void vty_endframe(struct vty *vty, const char *endtext)
+{
+ if (vty->frame_pos == 0 && endtext)
+ vty_out(vty, "%s", endtext);
+ vty->frame_pos = 0;
+}
+
/* VTY standard output function. */
int vty_out(struct vty *vty, const char *format, ...)
{
char buf[1024];
char *p = NULL;
+ if (vty->frame_pos) {
+ vty->frame_pos = 0;
+ vty_out(vty, "%s", vty->frame);
+ }
+
if (vty_shell(vty)) {
va_start(args, format);
vprintf(format, args);
/* Put out prompt and wait input from user. */
static void vty_prompt(struct vty *vty)
{
- struct utsname names;
- const char *hostname;
-
if (vty->type == VTY_TERM) {
- hostname = host.name;
- if (!hostname) {
- uname(&names);
- hostname = names.nodename;
- }
- vty_out(vty, cmd_prompt(vty->node), hostname);
+ vty_out(vty, cmd_prompt(vty->node), cmd_hostname_get());
}
}
/* What address is this vty comming from. */
char address[SU_ADDRSTRLEN];
+
+ /* "frame" output. This is buffered and will be printed if some
+ * actual output follows, or will be discarded if the frame ends
+ * without any output. */
+ size_t frame_pos;
+ char frame[1024];
};
static inline void vty_push_context(struct vty *vty, int node, uint64_t id)
extern void vty_reset(void);
extern struct vty *vty_new(void);
extern struct vty *vty_stdio(void (*atclose)(int isexit));
+
+/* - vty_frame() output goes to a buffer (for context-begin markers)
+ * - vty_out() will first print this buffer, and clear it
+ * - vty_endframe() clears the buffer without printing it, and prints an
+ * extra string if the buffer was empty before (for context-end markers)
+ */
extern int vty_out(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
+extern void vty_frame(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
+extern void vty_endframe(struct vty *, const char *);
+
extern void vty_read_config(const char *, char *);
extern void vty_time_print(struct vty *, int);
extern void vty_serv_sock(const char *, unsigned short, const char *);
* | IPv4 Nexthop address or Interface Index number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
- * Alternatively, if the flags field has ZEBRA_FLAG_BLACKHOLE or
- * ZEBRA_FLAG_REJECT is set then Nexthop count is set to 1, then _no_
- * nexthop information is provided, and the message describes a prefix
- * to blackhole or reject route.
+ * Alternatively, if the route is a blackhole route, then Nexthop count
+ * is set to 1 and a nexthop of type NEXTHOP_TYPE_BLACKHOLE is the sole
+ * nexthop.
*
* The original struct zapi_ipv4, zapi_ipv4_route() and zread_ipv4_*()
* infrastructure was built around the traditional (32-bit "gate OR
/* 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)) {
- stream_putc(s, 1);
- stream_putc(s, NEXTHOP_TYPE_BLACKHOLE);
- /* XXX assert(api->nexthop_num == 0); */
- /* XXX assert(api->ifindex_num == 0); */
- } else
- stream_putc(s, api->nexthop_num + api->ifindex_num);
+ stream_putc(s, api->nexthop_num + api->ifindex_num);
for (i = 0; i < api->nexthop_num; i++) {
stream_putc(s, NEXTHOP_TYPE_IPV4);
/* Nexthop, ifindex, distance and metric information. */
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
- if (CHECK_FLAG(api->flags, ZEBRA_FLAG_BLACKHOLE)) {
- stream_putc(s, 1);
- stream_putc(s, NEXTHOP_TYPE_BLACKHOLE);
- /* XXX assert(api->nexthop_num == 0); */
- /* XXX assert(api->ifindex_num == 0); */
- } else
- stream_putc(s, api->nexthop_num + api->ifindex_num);
+ stream_putc(s, api->nexthop_num + api->ifindex_num);
for (i = 0; i < api->nexthop_num; i++) {
stream_putc(s, NEXTHOP_TYPE_IPV6);
/* Nexthop, ifindex, distance and metric information. */
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
- if (CHECK_FLAG(api->flags, ZEBRA_FLAG_BLACKHOLE)) {
- stream_putc(s, 1);
- stream_putc(s, NEXTHOP_TYPE_BLACKHOLE);
- /* XXX assert(api->nexthop_num == 0); */
- /* XXX assert(api->ifindex_num == 0); */
- } else
- stream_putc(s, api->nexthop_num + api->ifindex_num);
+ stream_putc(s, api->nexthop_num + api->ifindex_num);
for (i = 0; i < api->nexthop_num; i++) {
stream_putc(s, NEXTHOP_TYPE_IPV6);
stream_putc(s, api_nh->type);
switch (api_nh->type) {
case NEXTHOP_TYPE_BLACKHOLE:
+ stream_putc(s, api_nh->bh_type);
break;
case NEXTHOP_TYPE_IPV4:
stream_put_in_addr(s, &api_nh->gate.ipv4);
api_nh->type = stream_getc(s);
switch (api_nh->type) {
case NEXTHOP_TYPE_BLACKHOLE:
+ api_nh->bh_type = stream_getc(s);
break;
case NEXTHOP_TYPE_IPV4:
api_nh->gate.ipv4.s_addr = stream_get_ipv4(s);
struct zapi_nexthop {
enum nexthop_types_t type;
ifindex_t ifindex;
- union g_addr gate;
+ union {
+ union g_addr gate;
+ enum blackhole_type bh_type;
+ };
/* MPLS labels for BGP-LU or Segment Routing */
uint8_t label_num;
extern int zapi_route_encode(u_char, struct stream *, struct zapi_route *);
extern int zapi_route_decode(struct stream *, struct zapi_route *);
+static inline void zapi_route_set_blackhole(struct zapi_route *api,
+ enum blackhole_type bh_type)
+{
+ api->nexthop_num = 1;
+ api->nexthops[0].type = NEXTHOP_TYPE_BLACKHOLE;
+ api->nexthops[0].bh_type = bh_type;
+ SET_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP);
+};
+
+
#endif /* _ZEBRA_ZCLIENT_H */
/* Zebra message flags */
#define ZEBRA_FLAG_INTERNAL 0x01
#define ZEBRA_FLAG_SELFROUTE 0x02
-#define ZEBRA_FLAG_BLACKHOLE 0x04
#define ZEBRA_FLAG_IBGP 0x08
#define ZEBRA_FLAG_SELECTED 0x10
#define ZEBRA_FLAG_STATIC 0x40
-#define ZEBRA_FLAG_REJECT 0x80
#define ZEBRA_FLAG_SCOPE_LINK 0x100
#define ZEBRA_FLAG_FIB_OVERRIDE 0x200
+/* ZEBRA_FLAG_BLACKHOLE was 0x04 */
+/* ZEBRA_FLAG_REJECT was 0x80 */
/* Zebra FEC flags. */
#define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x1
switch (type) {
case NHRP_CACHE_NEGATIVE:
- SET_FLAG(api.flags, ZEBRA_FLAG_REJECT);
+ zapi_route_set_blackhole(&api, BLACKHOLE_REJECT);
+ ifp = NULL;
+ nexthop = NULL;
break;
case NHRP_CACHE_DYNAMIC:
case NHRP_CACHE_NHS:
" count %d dev %s",
add ? "add" : "del", buf[0],
nexthop ? inet_ntop(api.prefix.family, &api_nh->gate, buf[1], sizeof(buf[1])) : "<onlink>",
- api.metric, api.nexthop_num, ifp->name);
+ api.metric, api.nexthop_num, ifp ? ifp->name : "none");
}
zclient_route_send(add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, zclient,
int i;
for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
- vty_out (vty, "interface %s\n", ifp->name);
+ vty_frame(vty, "interface %s\n", ifp->name);
if (ifp->desc)
vty_out (vty, " description %s\n", ifp->desc);
}
}
- vty_out (vty, "!\n");
+ vty_endframe(vty, "!\n");
}
return 0;
const char *name = prefix_list_name(plist);
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, n, oa)) {
- if (!strcmp(PREFIX_NAME_IN(oa), name))
+ if (PREFIX_NAME_IN(oa) && !strcmp(PREFIX_NAME_IN(oa), name))
PREFIX_LIST_IN(oa) = add ? plist : NULL;
- if (!strcmp(PREFIX_NAME_OUT(oa), name))
+ if (PREFIX_NAME_OUT(oa) && !strcmp(PREFIX_NAME_OUT(oa), name))
PREFIX_LIST_OUT(oa) = add ? plist : NULL;
}
}
static int route_map_command_status(struct vty *vty, int ret)
{
- if (!ret)
- return CMD_SUCCESS;
-
switch (ret) {
case RMAP_RULE_MISSING:
vty_out(vty, "OSPF6 Can't find rule.\n");
+ return CMD_WARNING_CONFIG_FAILED;
break;
case RMAP_COMPILE_ERROR:
vty_out(vty, "OSPF6 Argument is malformed.\n");
+ return CMD_WARNING_CONFIG_FAILED;
break;
- default:
- vty_out(vty, "OSPF6 route-map add set failed.\n");
+ case RMAP_COMPILE_SUCCESS:
break;
}
- return CMD_WARNING_CONFIG_FAILED;
+
+ return CMD_SUCCESS;
}
/* add "set metric-type" */
if (oi == NULL)
continue;
- vty_out(vty, "interface %s\n", oi->interface->name);
+ vty_frame(vty, "interface %s\n", oi->interface->name);
if (ifp->desc)
vty_out(vty, " description %s\n", ifp->desc);
ospf6_bfd_write_config(vty, oi);
- vty_out(vty, "!\n");
+ vty_endframe(vty, "!\n");
}
return 0;
}
}
/* change Router_ID commands. */
-DEFUN (ospf6_router_id,
- ospf6_router_id_cmd,
- "router-id A.B.C.D",
- "Configure OSPF Router-ID\n"
- V4NOTATION_STR)
+DEFUN(ospf6_router_id,
+ ospf6_router_id_cmd,
+ "ospf6 router-id A.B.C.D",
+ OSPF6_STR
+ "Configure OSPF6 Router-ID\n"
+ V4NOTATION_STR)
{
VTY_DECLVAR_CONTEXT(ospf6, o);
- int idx_ipv4 = 1;
+ int idx = 0;
int ret;
+ const char *router_id_str;
u_int32_t router_id;
- ret = inet_pton(AF_INET, argv[idx_ipv4]->arg, &router_id);
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ router_id_str = argv[idx]->arg;
+
+ ret = inet_pton(AF_INET, router_id_str, &router_id);
if (ret == 0) {
- vty_out(vty, "malformed OSPF Router-ID: %s\n",
- argv[idx_ipv4]->arg);
+ vty_out(vty, "malformed OSPF Router-ID: %s\n", router_id_str);
return CMD_SUCCESS;
}
return CMD_SUCCESS;
}
+DEFUN(no_ospf6_router_id,
+ no_ospf6_router_id_cmd,
+ "no ospf6 router-id [A.B.C.D]",
+ NO_STR OSPF6_STR
+ "Configure OSPF6 Router-ID\n"
+ V4NOTATION_STR)
+{
+ VTY_DECLVAR_CONTEXT(ospf6, o);
+ o->router_id_static = 0;
+ o->router_id = 0;
+
+ return CMD_SUCCESS;
+}
+
+#if CONFDATE > 20180828
+CPP_NOTICE("ospf6: `router-id A.B.C.D` deprecated 2017/08/28")
+#endif
+ALIAS_HIDDEN(ospf6_router_id,
+ ospf6_router_id_hdn_cmd,
+ "router-id A.B.C.D",
+ "Configure OSPF6 Router-ID\n"
+ V4NOTATION_STR)
+
+#if CONFDATE > 20180828
+CPP_NOTICE("ospf6: `no router-id A.B.C.D` deprecated 2017/08/28")
+#endif
+ALIAS_HIDDEN(no_ospf6_router_id,
+ no_ospf6_router_id_hdn_cmd,
+ "no router-id [A.B.C.D]",
+ NO_STR
+ "Configure OSPF6 Router-ID\n"
+ V4NOTATION_STR)
+
DEFUN (ospf6_log_adjacency_changes,
ospf6_log_adjacency_changes_cmd,
"log-adjacency-changes",
sizeof(router_id));
vty_out(vty, "router ospf6\n");
if (ospf6->router_id_static != 0)
- vty_out(vty, " router-id %s\n", router_id);
+ vty_out(vty, " ospf6 router-id %s\n", router_id);
/* log-adjacency-changes flag print. */
if (CHECK_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) {
install_default(OSPF6_NODE);
install_element(OSPF6_NODE, &ospf6_router_id_cmd);
+ install_element(OSPF6_NODE, &no_ospf6_router_id_cmd);
+ install_element(OSPF6_NODE, &ospf6_router_id_hdn_cmd);
+ install_element(OSPF6_NODE, &no_ospf6_router_id_hdn_cmd);
install_element(OSPF6_NODE, &ospf6_log_adjacency_changes_cmd);
install_element(OSPF6_NODE, &ospf6_log_adjacency_changes_detail_cmd);
install_element(OSPF6_NODE, &no_ospf6_log_adjacency_changes_cmd);
char prefixstr[PREFIX2STR_BUFFER], nexthopstr[128];
prefix2str((struct prefix *)&api.prefix, prefixstr,
sizeof(prefixstr));
- if (nexthop)
- inet_ntop(AF_INET6, nexthop, nexthopstr,
- sizeof(nexthopstr));
- else
- snprintf(nexthopstr, sizeof(nexthopstr), "::");
+ inet_ntop(AF_INET6, nexthop, nexthopstr, sizeof(nexthopstr));
zlog_debug(
"Zebra Receive route %s: %s %s nexthop %s ifindex %ld tag %" ROUTE_TAG_PRI,
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_OSPF6;
- api.flags = ZEBRA_FLAG_BLACKHOLE;
api.safi = SAFI_UNICAST;
api.prefix = *dest;
+ zapi_route_set_blackhole(&api, BLACKHOLE_NULL);
zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_OSPF6;
- api.flags = ZEBRA_FLAG_BLACKHOLE;
api.safi = SAFI_UNICAST;
api.prefix = *dest;
+ zapi_route_set_blackhole(&api, BLACKHOLE_NULL);
zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
if (ntohs(OspfMplsTE.router_addr.header.type) != 0)
show_vty_router_addr(vty,
&OspfMplsTE.router_addr.header);
- else if (vty != NULL)
+ else
vty_out(vty, " N/A\n");
}
return CMD_SUCCESS;
return CMD_SUCCESS;
}
-/* Deprecated: 08/07/2017 */
+#if CONFDATE > 20180708
+CPP_NOTICE("ospf: `timers lsa arrival (0-1000)` deprecated 2017/07/08")
+#endif
ALIAS_HIDDEN (ospf_timers_lsa_min_arrival,
ospf_timers_lsa_arrival_cmd,
"timers lsa arrival (0-1000)",
"ospf minimum arrival interval delay\n"
"delay (msec) between accepted lsas\n");
-/* Deprecated: 08/07/2017 */
+#if CONFDATE > 20180708
+CPP_NOTICE("ospf: `no timers lsa arrival (0-1000)` deprecated 2017/07/08")
+#endif
ALIAS_HIDDEN (no_ospf_timers_lsa_min_arrival,
no_ospf_timers_lsa_arrival_cmd,
"no timers lsa arrival (0-1000)",
unsigned int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT;
unsigned int interval = OSPF_POLL_INTERVAL_DEFAULT;
- inet_aton(argv[idx_ipv4]->arg, &nbr_addr);
+ if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) {
+ vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
if (argc > 2)
priority = strtoul(argv[idx_pri]->arg, NULL, 10);
unsigned int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT;
unsigned int interval = OSPF_POLL_INTERVAL_DEFAULT;
- inet_aton(argv[idx_ipv4]->arg, &nbr_addr);
+ if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) {
+ vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
interval = strtoul(argv[idx_poll]->arg, NULL, 10);
int idx_ipv4 = 2;
struct in_addr nbr_addr;
- inet_aton(argv[idx_ipv4]->arg, &nbr_addr);
+ if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) {
+ vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
(void)ospf_nbr_nbma_unset(ospf, nbr_addr);
int idx_ipv4 = 2;
struct in_addr nbr_addr;
- inet_aton(argv[idx_ipv4]->arg, &nbr_addr);
+ if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) {
+ vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
(void)ospf_nbr_nbma_unset(ospf, nbr_addr);
// Check if we have an address arg and proccess it
if (argc == idx + 3) {
- inet_aton(argv[idx + 2]->arg, &addr);
+ if (!inet_aton(argv[idx + 2]->arg, &addr)) {
+ vty_out(vty, "Please specify Intf Address by A.B.C.D\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
// update/create address-level params
params = ospf_get_if_params((ifp), (addr));
if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) {
// Check if we have an address arg and proccess it
if (argc == idx + 3) {
- inet_aton(argv[idx + 2]->arg, &addr);
+ if (!inet_aton(argv[idx + 2]->arg, &addr)) {
+ vty_out(vty, "Please specify Intf Address by A.B.C.D\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
params = ospf_lookup_if_params(ifp, addr);
if ((params) == NULL)
return CMD_SUCCESS;
if (ifp->ifindex == IFINDEX_DELETED)
continue;
- vty_out(vty, "!\n");
- vty_out(vty, "interface %s\n", ifp->name);
+ vty_frame(vty, "!\n");
+ vty_frame(vty, "interface %s\n", ifp->name);
if (ifp->desc)
vty_out(vty, " description %s\n", ifp->desc);
} while (rn);
ospf_opaque_config_write_if(vty, ifp);
+
+ vty_endframe(vty, NULL);
}
return write;
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_OSPF;
api.instance = ospf->instance;
- api.flags = ZEBRA_FLAG_BLACKHOLE;
api.safi = SAFI_UNICAST;
memcpy(&api.prefix, p, sizeof(*p));
+ zapi_route_set_blackhole(&api, BLACKHOLE_NULL);
zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_OSPF;
api.instance = ospf->instance;
- api.flags = ZEBRA_FLAG_BLACKHOLE;
api.safi = SAFI_UNICAST;
memcpy(&api.prefix, p, sizeof(*p));
+ zapi_route_set_blackhole(&api, BLACKHOLE_NULL);
zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) {
/* XXX|HACK|TODO|FIXME:
- * Maybe we should ignore reject/blackhole routes? Testing shows
- * that
- * there is no problems though and this is only way to
- * "summarize"
- * routes in ASBR at the moment. Maybe we need just a better
- * generalised
- * solution for these types?
- *
- * if ( CHECK_FLAG (api.flags, ZEBRA_FLAG_BLACKHOLE)
- * || CHECK_FLAG (api.flags, ZEBRA_FLAG_REJECT))
- * return 0;
+ * Maybe we should ignore reject/blackhole routes? Testing
+ * shows that there is no problems though and this is only way
+ * to "summarize" routes in ASBR at the moment. Maybe we need
+ * just a better generalised solution for these types?
*/
/* Protocol tag overwrites all other tag value sent by zebra */
int idx = 2;
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+ if (!vrf)
+ return CMD_WARNING;
+
show_mroute_count(vrf->info, vty);
return CMD_SUCCESS;
}
RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
{
pim = vrf->info;
- if (!pim || vrf->vrf_id != VRF_DEFAULT) {
- vty_out(vty, "vrf %s\n", vrf->name);
- pim_global_config_write_worker(pim, vty);
- vty_out(vty, "!\n");
- }
+
+ if (!pim)
+ continue;
+
+ if (vrf->vrf_id == VRF_DEFAULT)
+ continue;
+
+ vty_out(vty, "vrf %s\n", vrf->name);
+ pim_global_config_write_worker(pim, vty);
+ vty_out(vty, "!\n");
}
return 0;
fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
+ if (fd < 0) {
+ zlog_warn("Could not create mroute socket: errno=%d: %s", errno,
+ safe_strerror(errno));
+ return -2;
+ }
+
#ifdef SO_BINDTODEVICE
- setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, pim->vrf->name,
- strlen(pim->vrf->name));
+ if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, pim->vrf->name,
+ strlen(pim->vrf->name))) {
+ zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
+ safe_strerror(errno));
+ close(fd);
+ return -3;
+ }
#endif
if (pimd_privs.change(ZPRIVS_LOWER))
zlog_err("pim_mroute_socket_enable: could not lower privs, %s",
safe_strerror(errno));
- if (fd < 0) {
- zlog_warn("Could not create mroute socket: errno=%d: %s", errno,
- safe_strerror(errno));
- return -2;
- }
-
pim->mroute_socket = fd;
if (pim_mroute_set(pim, 1)) {
zlog_warn(
if (!ifp) {
zlog_err("%s: Unable to lookup vrf interface: %s",
__PRETTY_FUNCTION__, pim->vrf->name);
+ close(sock);
+ return -1;
+ }
+ if (pim_socket_bind(sock, ifp)) {
+ zlog_err("%s: Unable to bind to socket: %s",
+ __PRETTY_FUNCTION__, safe_strerror(errno));
+ close(sock);
return -1;
}
- pim_socket_bind(sock, ifp);
}
if (pimd_privs.change(ZPRIVS_RAISE)) {
__PRETTY_FUNCTION__, mp->pim->vrf->name);
return -1;
}
- pim_socket_bind(mp->fd, ifp);
+ if (pim_socket_bind(mp->fd, ifp)) {
+ zlog_err("%s: Unable to bind to socket: %s",
+ __PRETTY_FUNCTION__, safe_strerror(errno));
+ close(mp->fd);
+ mp->fd = -1;
+ return -1;
+ }
}
set_nonblocking(mp->fd);
}
pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info);
- str2prefix("224.0.0.0/4", &g_all);
+ if (!str2prefix("224.0.0.0/4", &g_all))
+ return PIM_RP_BAD_ADDRESS;
+
rp_all = pim_rp_find_match_group(pim, &g_all);
if (rp_all == rp_info) {
return fd;
}
-int pim_socket_ip_hdr(int fd)
+void pim_socket_ip_hdr(int fd)
{
const int on = 1;
- int ret;
if (pimd_privs.change(ZPRIVS_RAISE))
zlog_err("%s: could not raise privs, %s", __PRETTY_FUNCTION__,
safe_strerror(errno));
- ret = setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));
+ if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)))
+ zlog_err("%s: Could not turn on IP_HDRINCL option: %s",
+ __PRETTY_FUNCTION__, safe_strerror(errno));
if (pimd_privs.change(ZPRIVS_LOWER))
zlog_err("%s: could not lower privs, %s", __PRETTY_FUNCTION__,
safe_strerror(errno));
-
- return ret;
}
/*
#define PIM_SOCK_ERR_BIND (-11) /* Can't bind to interface */
int pim_socket_bind(int fd, struct interface *ifp);
-int pim_socket_ip_hdr(int fd);
+void pim_socket_ip_hdr(int fd);
int pim_socket_raw(int protocol);
int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp,
u_char loop);
static struct prefix group_ssm;
if (first) {
- str2prefix(PIM_SSM_STANDARD_RANGE, &group_ssm);
+ if (!str2prefix(PIM_SSM_STANDARD_RANGE, &group_ssm))
+ zlog_err("%s: Failure to Read Group Address: %s",
+ __PRETTY_FUNCTION__, PIM_SSM_STANDARD_RANGE);
+
first = 0;
}
pim_upstream_start_register_stop_timer(up, 1);
if (((up->channel_oil->cc.lastused / 100)
- > PIM_KEEPALIVE_PERIOD)
+ > pim->keep_alive_time)
&& (I_am_RP(pim_ifp->pim, up->sg.grp))) {
if (PIM_DEBUG_TRACE)
zlog_debug(
/* IF name */
if (vrf->vrf_id == VRF_DEFAULT)
- vty_out(vty, "interface %s\n", ifp->name);
+ vty_frame(vty, "interface %s\n", ifp->name);
else
- vty_out(vty, "interface %s vrf %s\n", ifp->name,
- vrf->name);
+ vty_frame(vty, "interface %s vrf %s\n",
+ ifp->name, vrf->name);
++writes;
if (ifp->info) {
pim_static_write_mroute(pim, vty, ifp);
pim_bfd_write_config(vty, ifp);
}
- vty_out(vty, "!\n");
+ vty_endframe(vty, "!\n");
++writes;
}
}
&& (ifp->vrf_id != vrf->vrf_id)) {
struct interface *master = if_lookup_by_name(
vrf->name, vrf->vrf_id);
+
+ if (!master) {
+ zlog_debug("%s: Unable to find Master interface for %s",
+ __PRETTY_FUNCTION__,
+ vrf->name);
+ return 0;
+ }
zclient_interface_set_master(zclient, master,
ifp);
}
printf("%s: waiting...\n", prog_name);
if (getchar() == EOF)
- fprintf(stderr, "getchar failure\n");
+ fprintf(stderr, "getchar failure\n");
close(fd);
# install /etc sources
%if "%{initsystem}" == "systemd"
mkdir -p %{buildroot}%{_unitdir}
-install %{zeb_rh_src}/frr.service \
+install -m644 %{zeb_rh_src}/frr.service \
%{buildroot}%{_unitdir}/frr.service
install %{zeb_rh_src}/frr.init \
%{buildroot}%{_sbindir}/frr
&& (!ri->auth_str) && (!ri->key_chain))
continue;
- vty_out(vty, "interface %s\n", ifp->name);
+ vty_frame(vty, "interface %s\n", ifp->name);
if (ifp->desc)
vty_out(vty, " description %s\n", ifp->desc);
vty_out(vty, " ip rip authentication key-chain %s\n",
ri->key_chain);
- vty_out(vty, "!\n");
+ vty_endframe(vty, "!\n");
}
return 0;
}
struct cmsghdr *ptr;
char adata[1024];
+ memset(&msg, 0, sizeof(msg));
msg.msg_name = (void *)from;
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_iov = &iov;
&& (ri->split_horizon == ri->split_horizon_default))
continue;
- vty_out(vty, "interface %s\n", ifp->name);
+ vty_frame(vty, "interface %s\n", ifp->name);
if (ifp->desc)
vty_out(vty, " description %s\n", ifp->desc);
}
}
- vty_out(vty, "!\n");
+ vty_endframe(vty, "!\n");
write++;
}
addr.sin6_port = htons(RIPNG_PORT_DEFAULT);
}
+ memset(&msg, 0, sizeof(msg));
msg.msg_name = (void *)&addr;
msg.msg_namelen = sizeof(struct sockaddr_in6);
msg.msg_iov = &iov;
char adata[1024];
/* Fill in message and iovec. */
+ memset(&msg, 0, sizeof(msg));
msg.msg_name = (void *)from;
msg.msg_namelen = sizeof(struct sockaddr_in6);
msg.msg_iov = &iov;
/lib/test_timer_correctness
/lib/test_timer_performance
/lib/test_ttable
+/lib/test_zmq
/ospf6d/test_lsdb
$(TESTS_OSPF6D) \
# end
+if ZEROMQ
+check_PROGRAMS += \
+ lib/test_zmq \
+ # end
+endif
+
../vtysh/vtysh_cmd.c:
$(MAKE) -C ../vtysh vtysh_cmd.c
lib_test_timer_performance_SOURCES = lib/test_timer_performance.c \
helpers/c/prng.c
lib_test_ttable_SOURCES = lib/test_ttable.c
+lib_test_zmq_SOURCES = lib/test_zmq.c
+lib_test_zmq_CFLAGS = $(AM_CFLAGS) $(ZEROMQ_CFLAGS)
lib_cli_test_cli_SOURCES = lib/cli/test_cli.c lib/cli/common_cli.c
lib_cli_test_commands_SOURCES = lib/cli/test_commands_defun.c \
lib/cli/test_commands.c \
lib_test_timer_correctness_LDADD = $(ALL_TESTS_LDADD)
lib_test_timer_performance_LDADD = $(ALL_TESTS_LDADD)
lib_test_ttable_LDADD = $(ALL_TESTS_LDADD)
+lib_test_zmq_LDADD = ../lib/libfrrzmq.la $(ALL_TESTS_LDADD) $(ZEROMQ_LIBS)
lib_cli_test_cli_LDADD = $(ALL_TESTS_LDADD)
lib_cli_test_commands_LDADD = $(ALL_TESTS_LDADD)
bgpd_test_aspath_LDADD = $(BGP_TEST_LDADD)
@pytest.mark.skipif('QUAGGA_TEST_COMMANDS' not in os.environ,
reason='QUAGGA_TEST_COMMANDS not set')
def test_refout(self):
- return super(TestCommands, self).test_refout(self)
+ return super(TestCommands, self).test_refout()
--- /dev/null
+/*
+ * ZeroMQ event test
+ * Copyright (C) 2017 David Lamparter, for NetDEF, Inc.
+ *
+ * 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 "memory.h"
+#include "sigevent.h"
+#include "frr_zmq.h"
+
+DEFINE_MTYPE_STATIC(LIB, TESTBUF, "zmq test buffer")
+
+static struct thread_master *master;
+
+static void msg_buf_free(void *data, void *hint)
+{
+ XFREE(MTYPE_TESTBUF, data);
+}
+
+static void run_client(int syncfd)
+{
+ int i, j;
+ char buf[32];
+ char dummy;
+ void *zmqctx = NULL;
+ void *zmqsock;
+
+ read(syncfd, &dummy, 1);
+
+ zmqctx = zmq_ctx_new();
+ zmq_ctx_set(zmqctx, ZMQ_IPV6, 1);
+
+ zmqsock = zmq_socket(zmqctx, ZMQ_REQ);
+ if (zmq_connect(zmqsock, "tcp://127.0.0.1:17171")) {
+ perror("zmq_connect");
+ exit(1);
+ }
+
+ /* single-part */
+ for (i = 0; i < 8; i++) {
+ snprintf(buf, sizeof(buf), "msg #%d %c%c%c",
+ i, 'a' + i, 'b' + i, 'c' + i);
+ printf("client send: %s\n", buf);
+ fflush(stdout);
+ zmq_send(zmqsock, buf, strlen(buf) + 1, 0);
+ zmq_recv(zmqsock, buf, sizeof(buf), 0);
+ printf("client recv: %s\n", buf);
+ }
+
+ /* multipart */
+ for (i = 2; i < 5; i++) {
+ int more;
+
+ printf("---\n");
+ for (j = 1; j <= i; j++) {
+ zmq_msg_t part;
+ char *dyn = XMALLOC(MTYPE_TESTBUF, 32);
+
+ snprintf(dyn, 32, "part %d/%d", j, i);
+ printf("client send: %s\n", dyn);
+ fflush(stdout);
+
+ zmq_msg_init_data(&part, dyn, strlen(dyn) + 1,
+ msg_buf_free, NULL);
+ zmq_msg_send(&part, zmqsock, j < i ? ZMQ_SNDMORE : 0);
+ }
+
+ zmq_msg_t part;
+ do {
+ char *data;
+
+ zmq_msg_recv(&part, zmqsock, 0);
+ data = zmq_msg_data(&part);
+ more = zmq_msg_more(&part);
+ printf("client recv (more: %d): %s\n", more, data);
+ } while (more);
+ zmq_msg_close(&part);
+ }
+ zmq_close(zmqsock);
+ zmq_ctx_term(zmqctx);
+}
+
+static struct frrzmq_cb *cb;
+
+static void serverpartfn(void *arg, void *zmqsock, zmq_msg_t *msg,
+ unsigned partnum)
+{
+ int more = zmq_msg_more(msg);
+ char *in = zmq_msg_data(msg);
+ size_t i;
+ zmq_msg_t reply;
+ char *out;
+
+ printf("server recv part %u (more: %d): %s\n", partnum, more, in);
+ fflush(stdout);
+ /* REQ-REP doesn't allow sending a reply here */
+ if (more)
+ return;
+
+ out = XMALLOC(MTYPE_TESTBUF, strlen(in) + 1);
+ for (i = 0; i < strlen(in); i++)
+ out[i] = toupper(in[i]);
+ out[i] = '\0';
+ zmq_msg_init_data(&reply, out, strlen(out) + 1, msg_buf_free, NULL);
+ zmq_msg_send(&reply, zmqsock, ZMQ_SNDMORE);
+
+ out = XMALLOC(MTYPE_TESTBUF, 32);
+ snprintf(out, 32, "msg# was %u", partnum);
+ zmq_msg_init_data(&reply, out, strlen(out) + 1, msg_buf_free, NULL);
+ zmq_msg_send(&reply, zmqsock, 0);
+}
+
+static void serverfn(void *arg, void *zmqsock)
+{
+ static int num = 0;
+
+ char buf[32];
+ size_t i;
+ zmq_recv(zmqsock, buf, sizeof(buf), 0);
+
+ printf("server recv: %s\n", buf);
+ fflush(stdout);
+ for (i = 0; i < strlen(buf); i++)
+ buf[i] = toupper(buf[i]);
+ zmq_send(zmqsock, buf, strlen(buf) + 1, 0);
+
+ if (++num < 4)
+ return;
+
+ /* change to multipart callback */
+ frrzmq_thread_cancel(cb);
+
+ cb = frrzmq_thread_add_read_part(master, serverpartfn, NULL, zmqsock);
+}
+
+static void sigchld(void)
+{
+ printf("child exited.\n");
+ frrzmq_thread_cancel(cb);
+}
+
+static struct quagga_signal_t sigs[] = {
+ {
+ .signal = SIGCHLD,
+ .handler = sigchld,
+ },
+};
+
+static void run_server(int syncfd)
+{
+ void *zmqsock;
+ char dummy = 0;
+ struct thread t;
+
+ master = thread_master_create(NULL);
+ signal_init(master, array_size(sigs), sigs);
+ frrzmq_init();
+
+ zmqsock = zmq_socket(frrzmq_context, ZMQ_REP);
+ if (zmq_bind(zmqsock, "tcp://*:17171")) {
+ perror("zmq_bind");
+ exit(1);
+ }
+
+ cb = frrzmq_thread_add_read_msg(master, serverfn, NULL, zmqsock);
+
+ write(syncfd, &dummy, sizeof(dummy));
+ while (thread_fetch(master, &t))
+ thread_call(&t);
+
+ zmq_close(zmqsock);
+ frrzmq_finish();
+ thread_master_free(master);
+ log_memstats_stderr("test");
+}
+
+int main(void)
+{
+ int syncpipe[2];
+ pid_t child;
+
+ if (pipe(syncpipe)) {
+ perror("pipe");
+ exit(1);
+ }
+
+ child = fork();
+ if (child < 0) {
+ perror("fork");
+ exit(1);
+ } else if (child == 0) {
+ run_client(syncpipe[0]);
+ exit(0);
+ }
+
+ run_server(syncpipe[1]);
+ exit(0);
+}
--- /dev/null
+import frrtest
+import pytest
+import os
+
+class TestZMQ(frrtest.TestRefOut):
+ program = './test_zmq'
+
+ @pytest.mark.skipif('S["ZEROMQ_TRUE"]=""\n' not in open('../config.status').readlines(),
+ reason='ZEROMQ not enabled')
+ def test_refout(self):
+ return super(TestZMQ, self).test_refout()
--- /dev/null
+client send: msg #0 abc
+server recv: msg #0 abc
+client recv: MSG #0 ABC
+client send: msg #1 bcd
+server recv: msg #1 bcd
+client recv: MSG #1 BCD
+client send: msg #2 cde
+server recv: msg #2 cde
+client recv: MSG #2 CDE
+client send: msg #3 def
+server recv: msg #3 def
+client recv: MSG #3 DEF
+client send: msg #4 efg
+server recv part 0 (more: 0): msg #4 efg
+client recv: MSG #4 EFG
+client send: msg #5 fgh
+client recv: msg# was 0
+client send: msg #6 ghi
+server recv part 0 (more: 0): msg #6 ghi
+client recv: MSG #6 GHI
+client send: msg #7 hij
+client recv: msg# was 0
+---
+client send: part 1/2
+client send: part 2/2
+server recv part 0 (more: 1): part 1/2
+server recv part 1 (more: 0): part 2/2
+client recv (more: 1): PART 2/2
+client recv (more: 0): msg# was 1
+---
+client send: part 1/3
+client send: part 2/3
+client send: part 3/3
+server recv part 0 (more: 1): part 1/3
+server recv part 1 (more: 1): part 2/3
+server recv part 2 (more: 0): part 3/3
+client recv (more: 1): PART 3/3
+client recv (more: 0): msg# was 2
+---
+client send: part 1/4
+client send: part 2/4
+client send: part 3/4
+client send: part 4/4
+server recv part 0 (more: 1): part 1/4
+server recv part 1 (more: 1): part 2/4
+server recv part 2 (more: 1): part 3/4
+server recv part 3 (more: 0): part 4/4
+client recv (more: 1): PART 4/4
+client recv (more: 0): msg# was 3
+child exited.
fprintf(stdout, "Building Configuration...\n");
- backup_config_file(quagga_config);
- fp = fopen(quagga_config, "w");
+ backup_config_file(frr_config);
+ fp = fopen(frr_config, "w");
if (fp == NULL) {
fprintf(stdout,
"%% Error: failed to open configuration file %s: %s\n",
- quagga_config, safe_strerror(errno));
+ frr_config, safe_strerror(errno));
return CMD_WARNING_CONFIG_FAILED;
}
fd = fileno(fp);
if (fchmod(fd, CONFIGFILE_MASK) != 0) {
printf("%% Warning: can't chmod configuration file %s: %s\n",
- quagga_config, safe_strerror(errno));
+ frr_config, safe_strerror(errno));
err++;
}
if ((uid != (uid_t)-1 || gid != (gid_t)-1)
&& fchown(fd, uid, gid)) {
printf("%% Warning: can't chown configuration file %s: %s\n",
- quagga_config, safe_strerror(errno));
+ frr_config, safe_strerror(errno));
err++;
}
} else {
- printf("%% Warning: stat() failed on %s: %s\n", quagga_config,
+ printf("%% Warning: stat() failed on %s: %s\n", frr_config,
safe_strerror(errno));
err++;
}
fclose(fp);
- printf("Integrated configuration saved to %s\n", quagga_config);
+ printf("Integrated configuration saved to %s\n", frr_config);
if (err)
return CMD_WARNING;
switch (vtysh_write_integrated) {
case WRITE_INTEGRATED_UNSPECIFIED:
- if (stat(quagga_config, &s) && errno == ENOENT)
+ if (stat(frr_config, &s) && errno == ENOENT)
return false;
return true;
case WRITE_INTEGRATED_NO:
if (!vclient->path[0])
snprintf(vclient->path, sizeof(vclient->path), "%s/%s.vty",
- vty_sock_path, vclient->name);
+ vtydir, vclient->name);
path = vclient->path;
/* Stat socket to see if we have permission to access it. */
return;
/* ls vty_sock_dir and look for all files ending in .vty */
- dir = opendir(vty_sock_path);
+ dir = opendir(vtydir);
if (dir) {
while ((file = readdir(dir)) != NULL) {
if (begins_with(file->d_name, "ospfd-")
if (n == MAXIMUM_INSTANCES) {
fprintf(stderr,
"Parsing %s, client limit(%d) reached!\n",
- vty_sock_path, n);
+ vtydir, n);
break;
}
client = (struct vtysh_client *)malloc(
client->name = "ospfd";
client->flag = VTYSH_OSPFD;
snprintf(client->path, sizeof(client->path),
- "%s/%s", vty_sock_path, file->d_name);
+ "%s/%s", vtydir, file->d_name);
client->next = NULL;
vtysh_client_sorted_insert(head_client, client);
n++;
char *vtysh_prompt(void)
{
- static struct utsname names;
static char buf[100];
- const char *hostname;
- extern struct host host;
-
- hostname = host.name;
-
- if (!hostname) {
- if (!names.nodename[0])
- uname(&names);
- hostname = names.nodename;
- }
-
- snprintf(buf, sizeof buf, cmd_prompt(vty->node), hostname);
+ snprintf(buf, sizeof buf, cmd_prompt(vty->node), cmd_hostname_get());
return buf;
}
#define VTYSH_NS VTYSH_ZEBRA
#define VTYSH_VRF VTYSH_ZEBRA|VTYSH_PIMD
-/* vtysh local configuration file. */
-#define VTYSH_DEFAULT_CONFIG "vtysh.conf"
-#define FRR_DEFAULT_CONFIG "frr.conf"
-
enum vtysh_write_integrated {
WRITE_INTEGRATED_UNSPECIFIED,
WRITE_INTEGRATED_NO,
extern enum vtysh_write_integrated vtysh_write_integrated;
-extern char *quagga_config;
+extern char frr_config[];
+extern char vtydir[];
void vtysh_init_vty(void);
void vtysh_init_cmd(void);
void vtysh_pager_init(void);
+void suid_on(void);
+void suid_off(void);
+
/* Child process execution flag. */
extern int execute_flag;
extern struct vty *vty;
-extern const char *vty_sock_path;
-
#endif /* VTYSH_H */
== 0
|| strncmp(line, "ip extcommunity-list",
strlen("ip extcommunity-list"))
- == 0)
+ == 0
+ || strncmp(line, "ip large-community-list",
+ strlen("ip large-community-list"))
+ == 0)
config = config_get(COMMUNITY_LIST_NODE, line);
else if (strncmp(line, "ip route", strlen("ip route")) == 0)
config = config_get(IP_NODE, line);
void vtysh_config_write()
{
char line[81];
- extern struct host host;
- if (host.name) {
- sprintf(line, "hostname %s", host.name);
+ if (cmd_hostname_get()) {
+ sprintf(line, "hostname %s", cmd_hostname_get());
vtysh_config_parse_line(NULL, line);
}
if (vtysh_write_integrated == WRITE_INTEGRATED_NO)
/* VTY shell program name. */
char *progname;
+/* SUID mode */
+static uid_t elevuid, realuid;
+static gid_t elevgid, realgid;
+
+#define VTYSH_CONFIG_NAME "vtysh.conf"
+#define FRR_CONFIG_NAME "frr.conf"
+
/* Configuration file name and directory. */
-static char vtysh_config_always[MAXPATHLEN] = SYSCONFDIR VTYSH_DEFAULT_CONFIG;
-static char quagga_config_default[MAXPATHLEN] = SYSCONFDIR FRR_DEFAULT_CONFIG;
-char *quagga_config = quagga_config_default;
-char history_file[MAXPATHLEN];
+static char vtysh_config[MAXPATHLEN];
+char frr_config[MAXPATHLEN];
+char vtydir[MAXPATHLEN];
+static char history_file[MAXPATHLEN];
/* Flag for indicate executing child command. */
int execute_flag = 0;
-/* VTY Socket prefix */
-const char *vty_sock_path = NULL;
-
/* For sigsetjmp() & siglongjmp(). */
static sigjmp_buf jmpbuf;
"-m, --markfile Mark input file with context end\n"
" --vty_socket Override vty socket path\n"
" --config_dir Override config directory path\n"
+ "-N --pathspace Insert prefix into config & socket paths\n"
"-w, --writeconfig Write integrated config (frr.conf) and exit\n"
"-h, --help Display this help and exit\n\n"
"Note that multiple commands may be executed from the command\n"
{"noerror", no_argument, NULL, 'n'},
{"mark", no_argument, NULL, 'm'},
{"writeconfig", no_argument, NULL, 'w'},
+ {"pathspace", no_argument, NULL, 'N'},
{0}};
/* Read a string, and return a pointer to it. Returns NULL on EOF. */
close(flock_fd);
}
+void suid_on(void)
+{
+ if (elevuid != realuid && seteuid(elevuid)) {
+ perror("seteuid(on)");
+ exit(1);
+ }
+ if (elevgid != realgid && setegid(elevgid)) {
+ perror("setegid(on)");
+ exit(1);
+ }
+}
+
+void suid_off(void)
+{
+ if (elevuid != realuid && seteuid(realuid)) {
+ perror("seteuid(off)");
+ exit(1);
+ }
+ if (elevgid != realgid && setegid(realgid)) {
+ perror("setegid(off)");
+ exit(1);
+ }
+}
+
/* VTY shell main routine. */
int main(int argc, char **argv, char **env)
{
int boot_flag = 0;
const char *daemon_name = NULL;
const char *inputfile = NULL;
- const char *vtysh_configfile_name;
struct cmd_rec {
char *line;
struct cmd_rec *next;
int writeconfig = 0;
int ret = 0;
char *homedir = NULL;
+ int ditch_suid = 0;
+ char sysconfdir[MAXPATHLEN];
+ char pathspace[MAXPATHLEN] = "";
- /* check for restricted functionality if vtysh is run setuid */
- int restricted = (getuid() != geteuid()) || (getgid() != getegid());
+ /* SUID: drop down to calling user & go back up when needed */
+ elevuid = geteuid();
+ elevgid = getegid();
+ realuid = getuid();
+ realgid = getgid();
+ suid_off();
/* Preserve name of myself. */
progname = ((p = strrchr(argv[0], '/')) ? ++p : argv[0]);
- /* if logging open now */
- if ((p = getenv("VTYSH_LOG")) != NULL)
- logfile = fopen(p, "a");
+ strlcpy(sysconfdir, frr_sysconfdir, sizeof(sysconfdir));
+ strlcpy(vtydir, frr_vtydir, sizeof(vtydir));
/* Option handling. */
while (1) {
tail = cr;
} break;
case OPTION_VTYSOCK:
- vty_sock_path = optarg;
+ ditch_suid = 1; /* option disables SUID */
+ strlcpy(vtydir, optarg, sizeof(vtydir));
break;
case OPTION_CONFDIR:
- /*
- * Skip option for Config Directory if setuid
- */
- if (restricted) {
+ ditch_suid = 1; /* option disables SUID */
+ strlcpy(sysconfdir, optarg, sizeof(sysconfdir));
+ break;
+ case 'N':
+ if (strchr(optarg, '/') || strchr(optarg, '.')) {
fprintf(stderr,
- "Overriding of Config Directory blocked for vtysh with setuid");
- return 1;
+ "slashes or dots are not permitted in the --pathspace option.\n");
+ exit(1);
}
- /*
- * Overwrite location for vtysh.conf
- */
- vtysh_configfile_name =
- strrchr(VTYSH_DEFAULT_CONFIG, '/');
- if (vtysh_configfile_name)
- /* skip '/' */
- vtysh_configfile_name++;
- else
- /*
- * VTYSH_DEFAULT_CONFIG configured with relative
- * path
- * during config? Should really never happen for
- * sensible config
- */
- vtysh_configfile_name =
- (char *)VTYSH_DEFAULT_CONFIG;
- strlcpy(vtysh_config_always, optarg,
- sizeof(vtysh_config_always));
- strlcat(vtysh_config_always, "/",
- sizeof(vtysh_config_always));
- strlcat(vtysh_config_always, vtysh_configfile_name,
- sizeof(vtysh_config_always));
- /*
- * Overwrite location for frr.conf
- */
- vtysh_configfile_name =
- strrchr(FRR_DEFAULT_CONFIG, '/');
- if (vtysh_configfile_name)
- /* skip '/' */
- vtysh_configfile_name++;
- else
- /*
- * FRR_DEFAULT_CONFIG configured with relative
- * path
- * during config? Should really never happen for
- * sensible config
- */
- vtysh_configfile_name =
- (char *)FRR_DEFAULT_CONFIG;
- strlcpy(quagga_config_default, optarg,
- sizeof(vtysh_config_always));
- strlcat(quagga_config_default, "/",
- sizeof(vtysh_config_always));
- strlcat(quagga_config_default, vtysh_configfile_name,
- sizeof(quagga_config_default));
+ snprintf(pathspace, sizeof(pathspace), "/%s", optarg);
break;
case 'd':
daemon_name = optarg;
}
}
- if (!vty_sock_path)
- vty_sock_path = frr_vtydir;
+ if (ditch_suid) {
+ elevuid = realuid;
+ elevgid = realgid;
+ }
if (markfile + writeconfig + dryrun + boot_flag > 1) {
fprintf(stderr,
"NOT SUPPORTED since its\nresults are inconsistent!\n");
}
+ snprintf(vtysh_config, sizeof(vtysh_config), "%s%s/%s", sysconfdir,
+ pathspace, VTYSH_CONFIG_NAME);
+ snprintf(frr_config, sizeof(frr_config), "%s%s/%s", sysconfdir,
+ pathspace, FRR_CONFIG_NAME);
+ strlcat(vtydir, pathspace, sizeof(vtydir));
+
/* Initialize user input buffer. */
line_read = NULL;
setlinebuf(stdout);
vty_init_vtysh();
- /* Read vtysh configuration file before connecting to daemons. */
- vtysh_read_config(vtysh_config_always);
+ /* Read vtysh configuration file before connecting to daemons.
+ * (file may not be readable to calling user in SUID mode) */
+ suid_on();
+ vtysh_read_config(vtysh_config);
+ suid_off();
if (markfile) {
if (!inputfile) {
if (inputfile) {
ret = vtysh_read_config(inputfile);
} else {
- ret = vtysh_read_config(quagga_config_default);
+ ret = vtysh_read_config(frr_config);
}
exit(ret);
}
}
+ /* SUID: go back up elevated privs */
+ suid_on();
+
/* Make sure we pass authentication before proceeding. */
vtysh_auth();
exit(1);
}
+ /* SUID: back down, don't need privs further on */
+ suid_off();
+
if (writeconfig) {
vtysh_execute("enable");
return vtysh_write_config_integrated();
}
}
+ if (getenv("VTYSH_LOG")) {
+ const char *logpath = getenv("VTYSH_LOG");
+
+ logfile = fopen(logpath, "a");
+ if (!logfile) {
+ fprintf(stderr, "Failed to open logfile (%s): %s\n",
+ logpath, strerror(errno));
+ exit(1);
+ }
+ }
+
/* If eval mode. */
if (cmd) {
/* Enter into enable node. */
/* Boot startup configuration file. */
if (boot_flag) {
- vtysh_flock_config(quagga_config);
- int ret = vtysh_read_config(quagga_config);
+ vtysh_flock_config(frr_config);
+ int ret = vtysh_read_config(frr_config);
vtysh_unflock_config();
if (ret) {
fprintf(stderr,
"Configuration file[%s] processing failure: %d\n",
- quagga_config, ret);
+ frr_config, ret);
if (no_error)
exit(0);
else
}
/* If same interface address is already exist... */
-struct connected *connected_check(struct interface *ifp, struct prefix *p)
+struct connected *connected_check(struct interface *ifp,
+ union prefixconstptr pu)
{
+ const struct prefix *p = pu.p;
struct connected *ifc;
struct listnode *node;
return NULL;
}
+/* same, but with peer address */
+struct connected *connected_check_ptp(struct interface *ifp,
+ union prefixconstptr pu,
+ union prefixconstptr du)
+{
+ const struct prefix *p = pu.p;
+ const struct prefix *d = du.p;
+ struct connected *ifc;
+ struct listnode *node;
+
+ /* ignore broadcast addresses */
+ if (p->prefixlen != IPV4_MAX_PREFIXLEN)
+ d = NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
+ if (!prefix_same(ifc->address, p))
+ continue;
+ if (!CONNECTED_PEER(ifc) && !d)
+ return ifc;
+ if (CONNECTED_PEER(ifc) && d
+ && prefix_same(ifc->destination, d))
+ return ifc;
+ }
+
+ return NULL;
+}
+
/* Check if two ifc's describe the same address in the same state */
static int connected_same(struct connected *ifc1, struct connected *ifc2)
{
struct connected *current;
/* Check same connected route. */
- if ((current = connected_check(ifp, (struct prefix *)ifc->address))) {
+ current = connected_check_ptp(ifp, ifc->address, ifc->destination);
+ if (current) {
if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
void connected_up_ipv4(struct interface *ifp, struct connected *ifc)
{
struct prefix p;
+ struct nexthop nh = {
+ .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex,
+ };
if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
return;
return;
rib_add(AFI_IP, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0,
- &p, NULL, NULL, NULL, ifp->ifindex, RT_TABLE_MAIN, ifp->metric,
- 0, 0);
+ &p, NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0);
rib_add(AFI_IP, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0,
- &p, NULL, NULL, NULL, ifp->ifindex, RT_TABLE_MAIN, ifp->metric,
- 0, 0);
+ &p, NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
p = prefix_ipv4_new();
p->family = AF_INET;
p->prefix = *addr;
- p->prefixlen = prefixlen;
+ p->prefixlen = CHECK_FLAG(flags, ZEBRA_IFA_PEER) ? IPV4_MAX_PREFIXLEN
+ : prefixlen;
ifc->address = (struct prefix *)p;
/* If there is broadcast or peer address. */
void connected_down_ipv4(struct interface *ifp, struct connected *ifc)
{
struct prefix p;
+ struct nexthop nh = {
+ .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex,
+ };
if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
return;
/* Same logic as for connected_up_ipv4(): push the changes into the
* head. */
rib_delete(AFI_IP, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0,
- &p, NULL, NULL, ifp->ifindex, 0, 0);
+ &p, NULL, &nh, 0, 0);
rib_delete(AFI_IP, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
- 0, &p, NULL, NULL, ifp->ifindex, 0, 0);
+ 0, &p, NULL, &nh, 0, 0);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
struct in_addr *addr, u_char prefixlen,
struct in_addr *broad)
{
- struct prefix_ipv4 p;
+ struct prefix_ipv4 p, d;
struct connected *ifc;
memset(&p, 0, sizeof(struct prefix_ipv4));
p.family = AF_INET;
p.prefix = *addr;
- p.prefixlen = prefixlen;
+ p.prefixlen = CHECK_FLAG(flags, ZEBRA_IFA_PEER) ? IPV4_MAX_PREFIXLEN
+ : prefixlen;
+
+ if (broad) {
+ memset(&d, 0, sizeof(struct prefix_ipv4));
+ d.family = AF_INET;
+ d.prefix = *broad;
+ d.prefixlen = prefixlen;
+ ifc = connected_check_ptp(ifp, (struct prefix *)&p,
+ (struct prefix *)&d);
+ } else
+ ifc = connected_check_ptp(ifp, (struct prefix *)&p, NULL);
- ifc = connected_check(ifp, (struct prefix *)&p);
if (!ifc)
return;
void connected_up_ipv6(struct interface *ifp, struct connected *ifc)
{
struct prefix p;
+ struct nexthop nh = {
+ .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex,
+ };
if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
return;
#endif
rib_add(AFI_IP6, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0,
- &p, NULL, NULL, NULL, ifp->ifindex, RT_TABLE_MAIN, ifp->metric,
- 0, 0);
+ &p, NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
/* Add connected IPv6 route to the interface. */
void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
- u_char prefixlen, struct in6_addr *broad,
- const char *label)
+ u_char prefixlen, const char *label)
{
struct prefix_ipv6 *p;
struct connected *ifc;
p->prefixlen = prefixlen;
ifc->address = (struct prefix *)p;
- /* If there is broadcast or peer address. */
- if (broad) {
- if (IN6_IS_ADDR_UNSPECIFIED(broad))
- zlog_warn(
- "warning: %s called for interface %s with unspecified "
- "destination address; ignoring!",
- __func__, ifp->name);
- else {
- p = prefix_ipv6_new();
- p->family = AF_INET6;
- IPV6_ADDR_COPY(&p->prefix, broad);
- p->prefixlen = prefixlen;
- ifc->destination = (struct prefix *)p;
- }
- }
- if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER) && !ifc->destination) {
- zlog_warn(
- "warning: %s called for interface %s "
- "with peer flag set, but no peer address supplied",
- __func__, ifp->name);
- UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
- }
-
/* Label of this address. */
if (label)
ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label);
void connected_down_ipv6(struct interface *ifp, struct connected *ifc)
{
struct prefix p;
+ struct nexthop nh = {
+ .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex,
+ };
if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
return;
return;
rib_delete(AFI_IP6, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
- 0, &p, NULL, NULL, ifp->ifindex, 0, 0);
+ 0, &p, NULL, &nh, 0, 0);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
}
void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address,
- u_char prefixlen, struct in6_addr *broad)
+ u_char prefixlen)
{
struct prefix_ipv6 p;
struct connected *ifc;
#define _ZEBRA_CONNECTED_H
extern struct connected *connected_check(struct interface *ifp,
- struct prefix *p);
+ union prefixconstptr p);
+extern struct connected *connected_check_ptp(struct interface *ifp,
+ union prefixconstptr p,
+ union prefixconstptr d);
extern void connected_add_ipv4(struct interface *ifp, int flags,
struct in_addr *addr, u_char prefixlen,
extern void connected_add_ipv6(struct interface *ifp, int flags,
struct in6_addr *address, u_char prefixlen,
- struct in6_addr *broad, const char *label);
+ const char *label);
extern void connected_delete_ipv6(struct interface *ifp,
- struct in6_addr *address, u_char prefixlen,
- struct in6_addr *broad);
+ struct in6_addr *address, u_char prefixlen);
extern void connected_up_ipv6(struct interface *, struct connected *);
extern void connected_down_ipv6(struct interface *ifp, struct connected *);
dest_pnt = NULL;
- if (ifap->ifa_dstaddr
+ if (if_is_pointopoint(ifp) && ifap->ifa_dstaddr
&& !IPV4_ADDR_SAME(&addr->sin_addr,
&((struct sockaddr_in *)
ifap->ifa_dstaddr)
if (ifap->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *addr;
struct sockaddr_in6 *mask;
- struct sockaddr_in6 *dest;
- struct in6_addr *dest_pnt;
int flags = 0;
addr = (struct sockaddr_in6 *)ifap->ifa_addr;
mask = (struct sockaddr_in6 *)ifap->ifa_netmask;
prefixlen = ip6_masklen(mask->sin6_addr);
- dest_pnt = NULL;
-
- if (ifap->ifa_dstaddr
- && !IPV6_ADDR_SAME(&addr->sin6_addr,
- &((struct sockaddr_in6 *)
- ifap->ifa_dstaddr)
- ->sin6_addr)) {
- dest = (struct sockaddr_in6 *)ifap->ifa_dstaddr;
- dest_pnt = &dest->sin6_addr;
- flags = ZEBRA_IFA_PEER;
- } else if (ifap->ifa_broadaddr
- && !IPV6_ADDR_SAME(
- &addr->sin6_addr,
- &((struct sockaddr_in6 *)
- ifap->ifa_broadaddr)
- ->sin6_addr)) {
- dest = (struct sockaddr_in6 *)
- ifap->ifa_broadaddr;
- dest_pnt = &dest->sin6_addr;
- }
-
#if defined(KAME)
if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
addr->sin6_scope_id =
#endif
connected_add_ipv6(ifp, flags, &addr->sin6_addr,
- prefixlen, dest_pnt, NULL);
+ prefixlen, NULL);
}
}
(struct in_addr *)dest_pnt, label);
else if (af == AF_INET6)
connected_add_ipv6(ifp, flags, &SIN6(addr)->sin6_addr,
- prefixlen, (struct in6_addr *)dest_pnt,
- label);
+ prefixlen, label);
return 0;
}
memset(&ifdata, 0, sizeof(ifdata));
/* set interface name */
- strcpy(ifdata.ifr_name, ifname);
+ strlcpy(ifdata.ifr_name, ifname, sizeof(ifdata.ifr_name));
/* initialize ethtool interface */
memset(&ecmd, 0, sizeof(ecmd));
req.ifa.ifa_family = family;
req.ifa.ifa_index = ifp->ifindex;
- req.ifa.ifa_prefixlen = p->prefixlen;
addattr_l(&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
- if (family == AF_INET && cmd == RTM_NEWADDR) {
- if (!CONNECTED_PEER(ifc) && ifc->destination) {
+ if (family == AF_INET) {
+ if (CONNECTED_PEER(ifc)) {
+ p = ifc->destination;
+ addattr_l(&req.n, sizeof req, IFA_ADDRESS, &p->u.prefix,
+ bytelen);
+ } else if (cmd == RTM_NEWADDR && ifc->destination) {
p = ifc->destination;
addattr_l(&req.n, sizeof req, IFA_BROADCAST,
&p->u.prefix, bytelen);
}
}
+ /* p is now either ifc->address or ifc->destination */
+ req.ifa.ifa_prefixlen = p->prefixlen;
+
if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
SET_FLAG(req.ifa.ifa_flags, IFA_F_SECONDARY);
*/
if (!(ifa->ifa_flags
& (IFA_F_DADFAILED | IFA_F_TENTATIVE)))
- connected_add_ipv6(
- ifp, flags, (struct in6_addr *)addr,
- ifa->ifa_prefixlen,
- (struct in6_addr *)broad, label);
+ connected_add_ipv6(ifp, flags,
+ (struct in6_addr *)addr,
+ ifa->ifa_prefixlen, label);
} else
connected_delete_ipv6(ifp, (struct in6_addr *)addr,
- ifa->ifa_prefixlen,
- (struct in6_addr *)broad);
+ ifa->ifa_prefixlen);
}
return 0;
/* Get address derived subnet node and associated address list, while
marking
address secondary attribute appropriately. */
- cp = *ifc->address;
+ cp = *CONNECTED_PREFIX(ifc);
apply_mask(&cp);
rn = route_node_get(zebra_if->ipv4_subnets, &cp);
struct route_node *rn;
struct zebra_if *zebra_if;
struct list *addr_list;
+ struct prefix cp;
assert(ifp && ifp->info && ifc);
zebra_if = ifp->info;
+ cp = *CONNECTED_PREFIX(ifc);
+ apply_mask(&cp);
+
/* Get address derived subnet node. */
- rn = route_node_lookup(zebra_if->ipv4_subnets, ifc->address);
+ rn = route_node_lookup(zebra_if->ipv4_subnets, &cp);
if (!(rn && rn->info)) {
zlog_warn(
"Trying to remove an address from an unknown subnet."
if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
SET_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE);
- if (if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON) {
+ if (if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
"interface %s vrf %u index %d is shutdown. "
static void if_delete_connected(struct interface *ifp)
{
struct connected *ifc;
- struct prefix *p;
+ struct prefix cp;
struct route_node *rn;
struct zebra_if *zebra_if;
while ((node = (last ? last->next
: listhead(ifp->connected)))) {
ifc = listgetdata(node);
- p = ifc->address;
- if (p->family == AF_INET
+ cp = *CONNECTED_PREFIX(ifc);
+ apply_mask(&cp);
+
+ if (cp.family == AF_INET
&& (rn = route_node_lookup(zebra_if->ipv4_subnets,
- p))) {
+ &cp))) {
struct listnode *anode;
struct listnode *next;
struct listnode *first;
list_delete(addr_list);
rn->info = NULL;
route_unlock_node(rn);
- } else if (p->family == AF_INET6) {
+ } else if (cp.family == AF_INET6) {
connected_down_ipv6(ifp, ifc);
zebra_interface_address_delete_update(ifp, ifc);
link_if = ifp;
zebra_vxlan_svi_up(ifp, link_if);
} else if (IS_ZEBRA_IF_VLAN(ifp)) {
- link_if = zif->link;
+ link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
+ zif->link_ifindex);
if (link_if)
zebra_vxlan_svi_up(ifp, link_if);
}
link_if = ifp;
zebra_vxlan_svi_down(ifp, link_if);
} else if (IS_ZEBRA_IF_VLAN(ifp)) {
- link_if = zif->link;
+ link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
+ zif->link_ifindex);
if (link_if)
zebra_vxlan_svi_down(ifp, link_if);
}
vty_out(vty,
(CONNECTED_PEER(connected) ? " peer " : " broadcast "));
prefix_vty_out(vty, connected->destination);
+ if (CONNECTED_PEER(connected))
+ vty_out(vty, "/%d", connected->destination->prefixlen);
}
if (CHECK_FLAG(connected->flags, ZEBRA_IFA_SECONDARY))
const char *label)
{
struct zebra_if *if_data;
- struct prefix_ipv4 cp;
+ struct prefix_ipv4 lp, pp;
struct connected *ifc;
struct prefix_ipv4 *p;
int ret;
if_data = ifp->info;
- ret = str2prefix_ipv4(addr_str, &cp);
+ ret = str2prefix_ipv4(addr_str, &lp);
if (ret <= 0) {
vty_out(vty, "%% Malformed address \n");
return CMD_WARNING_CONFIG_FAILED;
}
- if (ipv4_martian(&cp.prefix)) {
+ if (ipv4_martian(&lp.prefix)) {
vty_out(vty, "%% Invalid address\n");
return CMD_WARNING_CONFIG_FAILED;
}
- ifc = connected_check(ifp, (struct prefix *)&cp);
+ if (peer_str) {
+ if (lp.prefixlen != 32) {
+ vty_out(vty,
+ "%% Local prefix length for P-t-P address must be /32\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ ret = str2prefix_ipv4(peer_str, &pp);
+ if (ret <= 0) {
+ vty_out(vty, "%% Malformed peer address\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+
+ ifc = connected_check_ptp(ifp, &lp, peer_str ? &pp : NULL);
if (!ifc) {
ifc = connected_new();
ifc->ifp = ifp;
/* Address. */
p = prefix_ipv4_new();
- *p = cp;
+ *p = lp;
ifc->address = (struct prefix *)p;
- /* Broadcast. */
- if (p->prefixlen <= IPV4_MAX_PREFIXLEN - 2) {
+ if (peer_str) {
+ SET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
+ p = prefix_ipv4_new();
+ *p = pp;
+ ifc->destination = (struct prefix *)p;
+ } else if (p->prefixlen <= IPV4_MAX_PREFIXLEN - 2) {
p = prefix_ipv4_new();
- *p = cp;
+ *p = lp;
p->prefix.s_addr = ipv4_broadcast_addr(p->prefix.s_addr,
p->prefixlen);
ifc->destination = (struct prefix *)p;
const char *addr_str, const char *peer_str,
const char *label)
{
- struct prefix_ipv4 cp;
+ struct prefix_ipv4 lp, pp;
struct connected *ifc;
int ret;
/* Convert to prefix structure. */
- ret = str2prefix_ipv4(addr_str, &cp);
+ ret = str2prefix_ipv4(addr_str, &lp);
if (ret <= 0) {
vty_out(vty, "%% Malformed address \n");
return CMD_WARNING_CONFIG_FAILED;
}
+ if (peer_str) {
+ if (lp.prefixlen != 32) {
+ vty_out(vty,
+ "%% Local prefix length for P-t-P address must be /32\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ ret = str2prefix_ipv4(peer_str, &pp);
+ if (ret <= 0) {
+ vty_out(vty, "%% Malformed peer address\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+
/* Check current interface address. */
- ifc = connected_check(ifp, (struct prefix *)&cp);
+ ifc = connected_check_ptp(ifp, &lp, peer_str ? &pp : NULL);
if (!ifc) {
vty_out(vty, "%% Can't find address\n");
return CMD_WARNING_CONFIG_FAILED;
NULL, NULL);
}
+DEFUN(ip_address_peer,
+ ip_address_peer_cmd,
+ "ip address A.B.C.D peer A.B.C.D/M",
+ "Interface Internet Protocol config commands\n"
+ "Set the IP address of an interface\n"
+ "Local IP (e.g. 10.0.0.1) for P-t-P address\n"
+ "Specify P-t-P address\n"
+ "Peer IP address (e.g. 10.0.0.1/8)\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ return ip_address_install(vty, ifp, argv[2]->arg, argv[4]->arg, NULL);
+}
+
+DEFUN(no_ip_address_peer,
+ no_ip_address_peer_cmd,
+ "no ip address A.B.C.D peer A.B.C.D/M",
+ NO_STR
+ "Interface Internet Protocol config commands\n"
+ "Set the IP address of an interface\n"
+ "Local IP (e.g. 10.0.0.1) for P-t-P address\n"
+ "Specify P-t-P address\n"
+ "Peer IP address (e.g. 10.0.0.1/8)\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ return ip_address_uninstall(vty, ifp, argv[3]->arg, argv[5]->arg, NULL);
+}
#ifdef HAVE_NETLINK
DEFUN (ip_address_label,
vrf = vrf_lookup_by_id(ifp->vrf_id);
if (ifp->vrf_id == VRF_DEFAULT)
- vty_out(vty, "interface %s\n", ifp->name);
+ vty_frame(vty, "interface %s\n", ifp->name);
else
vty_out(vty, "interface %s vrf %s\n", ifp->name,
vrf->name);
p = ifc->address;
vty_out(vty, " ip%s address %s",
p->family == AF_INET ? "" : "v6",
- prefix2str(p, buf, sizeof(buf)));
+ inet_ntop(p->family, &p->u.prefix, buf,
+ sizeof(buf)));
+ if (CONNECTED_PEER(ifc)) {
+ p = ifc->destination;
+ vty_out(vty, " peer %s",
+ inet_ntop(p->family,
+ &p->u.prefix, buf,
+ sizeof(buf)));
+ }
+ vty_out(vty, "/%d", p->prefixlen);
if (ifc->label)
vty_out(vty, " label %s", ifc->label);
link_params_config_write(vty, ifp);
- vty_out(vty, "!\n");
+ vty_endframe(vty, "!\n");
}
return 0;
}
install_element(INTERFACE_NODE, &no_bandwidth_if_cmd);
install_element(INTERFACE_NODE, &ip_address_cmd);
install_element(INTERFACE_NODE, &no_ip_address_cmd);
+ install_element(INTERFACE_NODE, &ip_address_peer_cmd);
+ install_element(INTERFACE_NODE, &no_ip_address_peer_cmd);
install_element(INTERFACE_NODE, &ipv6_address_cmd);
install_element(INTERFACE_NODE, &no_ipv6_address_cmd);
#ifdef HAVE_NETLINK
/* Zebra interface type - ones of interest. */
typedef enum {
- ZEBRA_IF_VXLAN, /* VxLAN interface */
- ZEBRA_IF_VRF, /* VRF device */
- ZEBRA_IF_BRIDGE, /* bridge device */
- ZEBRA_IF_VLAN, /* VLAN sub-interface */
- ZEBRA_IF_MACVLAN, /* MAC VLAN interface*/
- ZEBRA_IF_OTHER, /* Anything else */
+ ZEBRA_IF_OTHER = 0, /* Anything else */
+ ZEBRA_IF_VXLAN, /* VxLAN interface */
+ ZEBRA_IF_VRF, /* VRF device */
+ ZEBRA_IF_BRIDGE, /* bridge device */
+ ZEBRA_IF_VLAN, /* VLAN sub-interface */
+ ZEBRA_IF_MACVLAN, /* MAC VLAN interface*/
} zebra_iftype_t;
/* Zebra "slave" interface type */
/* clear and set interface name string */
void ifreq_set_name(struct ifreq *ifreq, struct interface *ifp)
{
- strncpy(ifreq->ifr_name, ifp->name, IFNAMSIZ);
+ strlcpy(ifreq->ifr_name, ifp->name, sizeof(ifreq->ifr_name));
}
/* call ioctl system call */
{
int ret;
struct ifaliasreq addreq;
- struct sockaddr_in addr;
- struct sockaddr_in mask;
+ struct sockaddr_in addr, mask, peer;
struct prefix_ipv4 *p;
+ /* don't configure PtP addresses on broadcast ifs or reverse */
+ if (!(ifp->flags & IFF_POINTOPOINT) != !CONNECTED_PEER(ifc)) {
+ errno = EINVAL;
+ return -1;
+ }
+
p = (struct prefix_ipv4 *)ifc->address;
rib_lookup_and_pushup(p, ifp->vrf_id);
#endif
memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in));
+ if (CONNECTED_PEER(ifc)) {
+ p = (struct prefix_ipv4 *)ifc->destination;
+ memset(&mask, 0, sizeof(struct sockaddr_in));
+ peer.sin_addr = p->prefix;
+ peer.sin_family = p->family;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+ peer.sin_len = sizeof(struct sockaddr_in);
+#endif
+ memcpy(&addreq.ifra_broadaddr, &peer,
+ sizeof(struct sockaddr_in));
+ }
+
memset(&mask, 0, sizeof(struct sockaddr_in));
masklen2ip(p->prefixlen, &mask.sin_addr);
mask.sin_family = p->family;
{
int ret;
struct ifaliasreq addreq;
- struct sockaddr_in addr;
- struct sockaddr_in mask;
+ struct sockaddr_in addr, mask, peer;
struct prefix_ipv4 *p;
+ /* this would probably wreak havoc */
+ if (!(ifp->flags & IFF_POINTOPOINT) != !CONNECTED_PEER(ifc)) {
+ errno = EINVAL;
+ return -1;
+ }
+
p = (struct prefix_ipv4 *)ifc->address;
memset(&addreq, 0, sizeof addreq);
#endif
memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in));
+ if (CONNECTED_PEER(ifc)) {
+ p = (struct prefix_ipv4 *)ifc->destination;
+ memset(&mask, 0, sizeof(struct sockaddr_in));
+ peer.sin_addr = p->prefix;
+ peer.sin_family = p->family;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+ peer.sin_len = sizeof(struct sockaddr_in);
+#endif
+ memcpy(&addreq.ifra_broadaddr, &peer,
+ sizeof(struct sockaddr_in));
+ }
+
memset(&mask, 0, sizeof(struct sockaddr_in));
masklen2ip(p->prefixlen, &mask.sin_addr);
mask.sin_family = p->family;
char adata[CMSG_SPACE(SOPT_SIZE_CMSG_PKTINFO_IPV4())];
int ret;
+ memset(&msg, 0, sizeof(msg));
msg.msg_name = (void *)0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
RTA_ADDR_GET(NULL, RTA_IFA, ifm->ifm_addrs, cp);
RTA_ADDR_GET(NULL, RTA_AUTHOR, ifm->ifm_addrs, cp);
RTA_ADDR_GET(NULL, RTA_BRD, ifm->ifm_addrs, cp);
+#ifdef RTA_LABEL
+ RTA_ATTR_GET(NULL, RTA_LABEL, ifm->ifm_addrs, cp);
+#endif
+#ifdef RTA_SRC
+ RTA_ADDR_GET(NULL, RTA_SRC, ifm->ifm_addrs, cp);
+#endif
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: sdl ifname %s", __func__,
RTA_ADDR_GET(addr, RTA_IFA, ifm->ifam_addrs, pnt);
RTA_ADDR_GET(NULL, RTA_AUTHOR, ifm->ifam_addrs, pnt);
RTA_ADDR_GET(brd, RTA_BRD, ifm->ifam_addrs, pnt);
+#ifdef RTA_LABEL
+ RTA_ATTR_GET(NULL, RTA_LABEL, ifm->ifam_addrs, pnt);
+#endif
+#ifdef RTA_SRC
+ RTA_ADDR_GET(NULL, RTA_SRC, ifm->ifam_addrs, pnt);
+#endif
if (IS_ZEBRA_DEBUG_KERNEL) {
int family = sockunion_family(addr);
if (ifam->ifam_type == RTM_NEWADDR)
connected_add_ipv6(ifp, flags, &addr.sin6.sin6_addr,
ip6_masklen(mask.sin6.sin6_addr),
- &brd.sin6.sin6_addr,
(isalias ? ifname : NULL));
else
connected_delete_ipv6(ifp, &addr.sin6.sin6_addr,
- ip6_masklen(mask.sin6.sin6_addr),
- &brd.sin6.sin6_addr);
+ ip6_masklen(mask.sin6.sin6_addr));
break;
default:
/* Unsupported family silently ignore... */
RTA_ADDR_GET(NULL, RTA_IFA, rtm->rtm_addrs, pnt);
RTA_ADDR_GET(NULL, RTA_AUTHOR, rtm->rtm_addrs, pnt);
RTA_ADDR_GET(NULL, RTA_BRD, rtm->rtm_addrs, pnt);
+#ifdef RTA_LABEL
+#if 0
+ union sockunion label;
+ memset(&label, 0, sizeof(label));
+ RTA_ATTR_GET(&label, RTA_LABEL, rtm->rtm_addrs, pnt);
+#endif
+ RTA_ATTR_GET(NULL, RTA_LABEL, rtm->rtm_addrs, pnt);
+#endif
+#ifdef RTA_SRC
+ RTA_ADDR_GET(NULL, RTA_SRC, rtm->rtm_addrs, pnt);
+#endif
/* If there is netmask information set it's family same as
destination family*/
union sockunion dest, mask, gate;
char ifname[INTERFACE_NAMSIZ + 1];
short ifnlen = 0;
+ struct nexthop nh;
zebra_flags = 0;
if (flags & RTF_STATIC)
SET_FLAG(zebra_flags, ZEBRA_FLAG_STATIC);
+ memset(&nh, 0, sizeof(nh));
/* This is a reject or blackhole route */
- if (flags & RTF_REJECT)
- SET_FLAG(zebra_flags, ZEBRA_FLAG_REJECT);
- if (flags & RTF_BLACKHOLE)
- SET_FLAG(zebra_flags, ZEBRA_FLAG_BLACKHOLE);
+ if (flags & RTF_REJECT) {
+ nh.type = NEXTHOP_TYPE_BLACKHOLE;
+ nh.bh_type = BLACKHOLE_REJECT;
+ } else if (flags & RTF_BLACKHOLE) {
+ nh.type = NEXTHOP_TYPE_BLACKHOLE;
+ nh.bh_type = BLACKHOLE_NULL;
+ }
if (dest.sa.sa_family == AF_INET) {
struct prefix p;
if (rtm->rtm_type == RTM_CHANGE)
rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT,
ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
- NULL, 0, 0, 0);
+ NULL, 0, 0);
+
+ if (!nh.type) {
+ nh.type = NEXTHOP_TYPE_IPV4;
+ nh.gate.ipv4 = gate.sin.sin_addr;
+ }
- union g_addr ggate = {.ipv4 = gate.sin.sin_addr};
if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD
|| rtm->rtm_type == RTM_CHANGE)
rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT,
ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
- &ggate, NULL, 0, 0, 0, 0, 0);
+ &nh, 0, 0, 0, 0);
else
rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT,
ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
- &ggate, 0, 0, 0);
+ &nh, 0, 0);
}
if (dest.sa.sa_family == AF_INET6) {
/* One day we might have a debug section here like one in the
if (rtm->rtm_type == RTM_CHANGE)
rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT,
ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
- NULL, 0, 0, 0);
+ NULL, 0, 0);
+
+ if (!nh.type) {
+ nh.type = ifindex ? NEXTHOP_TYPE_IPV6_IFINDEX
+ : NEXTHOP_TYPE_IPV6;
+ nh.gate.ipv6 = gate.sin6.sin6_addr;
+ nh.ifindex = ifindex;
+ }
- union g_addr ggate = {.ipv6 = gate.sin6.sin6_addr};
if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD
|| rtm->rtm_type == RTM_CHANGE)
rib_add(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT,
ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
- &ggate, NULL, ifindex, 0, 0, 0, 0);
+ &nh, 0, 0, 0, 0);
else
rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT,
ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
- &ggate, ifindex, 0, 0);
+ &nh, 0, 0);
}
}
*/
int rtm_write(int message, union sockunion *dest, union sockunion *mask,
union sockunion *gate, union sockunion *mpls, unsigned int index,
- int zebra_flags, int metric)
+ enum blackhole_type bh_type, int metric)
{
int ret;
caddr_t pnt;
/* Tagging route with flags */
msg.rtm.rtm_flags |= (RTF_PROTO1);
- /* Additional flags. */
- if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
- msg.rtm.rtm_flags |= RTF_BLACKHOLE;
- if (zebra_flags & ZEBRA_FLAG_REJECT)
+ switch (bh_type) {
+ case BLACKHOLE_UNSPEC:
+ break;
+ case BLACKHOLE_REJECT:
msg.rtm.rtm_flags |= RTF_REJECT;
+ break;
+ default:
+ msg.rtm.rtm_flags |= RTF_BLACKHOLE;
+ break;
+ }
#define SOCKADDRSET(X, R) \
extern int ifam_read(struct ifa_msghdr *);
extern int ifm_read(struct if_msghdr *);
extern int rtm_write(int, union sockunion *, union sockunion *,
- union sockunion *, union sockunion *, unsigned int, int,
- int);
+ union sockunion *, union sockunion *, unsigned int,
+ enum blackhole_type, int);
extern const struct message rtm_type_str[];
#endif /* __ZEBRA_KERNEL_SOCKET_H */
int is_zebra_import_table_enabled(afi_t afi, u_int32_t table_id)
{
+ /*
+ * Make sure that what we are called with actualy makes sense
+ */
+ if (afi == AFI_MAX)
+ return 0;
+
if (is_zebra_valid_kernel_table(table_id))
return zebra_import_table_used[afi][table_id];
return 0;
struct route_entry *newre;
struct route_entry *same;
struct prefix p;
- struct nexthop *nhop;
- union g_addr *gate;
route_map_result_t ret = RMAP_MATCH;
if (rmap_name)
if (re->nexthop_num == 1) {
- nhop = re->nexthop;
- if (nhop->type == NEXTHOP_TYPE_IFINDEX)
- gate = NULL;
- else
- gate = (union g_addr *)&nhop->gate.ipv4;
-
rib_add(AFI_IP, SAFI_UNICAST, re->vrf_id,
ZEBRA_ROUTE_TABLE, re->table, 0, &p,
- NULL, gate,
- (union g_addr *)&nhop->src.ipv4,
- nhop->ifindex, zebrad.rtm_table_default,
- re->metric, re->mtu,
+ NULL, re->nexthop,
+ zebrad.rtm_table_default, re->metric,
+ re->mtu,
zebra_import_table_distance[AFI_IP]
[re->table]);
} else if (re->nexthop_num > 1) {
p.u.prefix4 = rn->p.u.prefix4;
rib_delete(AFI_IP, SAFI_UNICAST, re->vrf_id, ZEBRA_ROUTE_TABLE,
- re->table, re->flags, &p, NULL, NULL, 0,
+ re->table, re->flags, &p, NULL, NULL,
zebrad.rtm_table_default, re->metric);
}
/* DD: Add IPv6 code */
extern struct nexthop *route_entry_nexthop_ifindex_add(struct route_entry *,
ifindex_t);
-extern struct nexthop *route_entry_nexthop_blackhole_add(struct route_entry *);
+extern struct nexthop *route_entry_nexthop_blackhole_add(struct route_entry *,
+ enum blackhole_type);
extern struct nexthop *route_entry_nexthop_ipv4_add(struct route_entry *,
struct in_addr *,
struct in_addr *);
* also implicitly withdraw equal prefix of same type. */
extern int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
u_short instance, int flags, struct prefix *p,
- struct prefix_ipv6 *src_p, union g_addr *gate,
- union g_addr *src, ifindex_t ifindex, u_int32_t table_id,
- u_int32_t metric, u_int32_t mtu, u_char distance);
+ struct prefix_ipv6 *src_p, const struct nexthop *nh,
+ u_int32_t table_id, u_int32_t metric, u_int32_t mtu,
+ u_char distance);
extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *,
struct prefix_ipv6 *src_p, struct route_entry *);
extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
u_short instance, int flags, struct prefix *p,
- struct prefix_ipv6 *src_p, union g_addr *gate,
- ifindex_t ifindex, u_int32_t table_id,
- u_int32_t metric);
+ struct prefix_ipv6 *src_p, const struct nexthop *nh,
+ u_int32_t table_id, u_int32_t metric);
extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t,
union g_addr *,
void *gate = NULL;
void *prefsrc = NULL; /* IPv4 preferred source host address */
void *src = NULL; /* IPv6 srcdest source prefix */
+ enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
rtm = NLMSG_DATA(h);
if (startup && h->nlmsg_type != RTM_NEWROUTE)
return 0;
- if (startup && rtm->rtm_type != RTN_UNICAST)
+ switch (rtm->rtm_type) {
+ case RTN_UNICAST:
+ break;
+ case RTN_BLACKHOLE:
+ bh_type = BLACKHOLE_NULL;
+ break;
+ case RTN_UNREACHABLE:
+ bh_type = BLACKHOLE_REJECT;
+ break;
+ case RTN_PROHIBIT:
+ bh_type = BLACKHOLE_ADMINPROHIB;
+ break;
+ default:
return 0;
+ }
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
if (len < 0)
afi = AFI_IP6;
if (h->nlmsg_type == RTM_NEWROUTE) {
- if (!tb[RTA_MULTIPATH])
+ if (!tb[RTA_MULTIPATH]) {
+ struct nexthop nh;
+ size_t sz = (afi == AFI_IP) ? 4 : 16;
+
+ memset(&nh, 0, sizeof(nh));
+ if (index && !gate)
+ nh.type = NEXTHOP_TYPE_IFINDEX;
+ else if (index && gate)
+ nh.type = (afi == AFI_IP)
+ ? NEXTHOP_TYPE_IPV4_IFINDEX
+ : NEXTHOP_TYPE_IPV6_IFINDEX;
+ else if (!index && gate)
+ nh.type = (afi == AFI_IP) ? NEXTHOP_TYPE_IPV4
+ : NEXTHOP_TYPE_IPV6;
+ else {
+ nh.type = NEXTHOP_TYPE_BLACKHOLE;
+ nh.bh_type = bh_type;
+ }
+ nh.ifindex = index;
+ if (prefsrc)
+ memcpy(&nh.src, prefsrc, sz);
+ if (gate)
+ memcpy(&nh.gate, gate, sz);
rib_add(afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
- 0, flags, &p, NULL, gate, prefsrc, index, table,
- metric, mtu, 0);
- else {
+ 0, flags, &p, NULL, &nh, table, metric, mtu, 0);
+ } else {
/* This is a multipath route */
struct route_entry *re;
NULL, re);
}
} else {
- if (!tb[RTA_MULTIPATH])
+ if (!tb[RTA_MULTIPATH]) {
+ struct nexthop nh;
+ size_t sz = (afi == AFI_IP) ? 4 : 16;
+
+ memset(&nh, 0, sizeof(nh));
+ if (index && !gate)
+ nh.type = NEXTHOP_TYPE_IFINDEX;
+ else if (index && gate)
+ nh.type = (afi == AFI_IP)
+ ? NEXTHOP_TYPE_IPV4_IFINDEX
+ : NEXTHOP_TYPE_IPV6_IFINDEX;
+ else if (!index && gate)
+ nh.type = (afi == AFI_IP) ? NEXTHOP_TYPE_IPV4
+ : NEXTHOP_TYPE_IPV6;
+ else
+ nh.type = NEXTHOP_TYPE_BLACKHOLE;
+ nh.ifindex = index;
+ if (gate)
+ memcpy(&nh.gate, gate, sz);
rib_delete(afi, SAFI_UNICAST, vrf_id,
- ZEBRA_ROUTE_KERNEL, 0, flags, &p, NULL, gate,
- index, table, metric);
- else {
- struct rtnexthop *rtnh =
- (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]);
-
- len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
-
- for (;;) {
- if (len < (int)sizeof(*rtnh)
- || rtnh->rtnh_len > len)
- break;
-
- gate = NULL;
- if (rtnh->rtnh_len > sizeof(*rtnh)) {
- memset(tb, 0, sizeof(tb));
- netlink_parse_rtattr(
- tb, RTA_MAX, RTNH_DATA(rtnh),
- rtnh->rtnh_len - sizeof(*rtnh));
- if (tb[RTA_GATEWAY])
- gate = RTA_DATA(
- tb[RTA_GATEWAY]);
- }
-
- if (gate)
- rib_delete(afi, SAFI_UNICAST, vrf_id,
- ZEBRA_ROUTE_KERNEL, 0, flags,
- &p, NULL, gate, index,
- table, metric);
-
- len -= NLMSG_ALIGN(rtnh->rtnh_len);
- rtnh = RTNH_NEXT(rtnh);
- }
+ ZEBRA_ROUTE_KERNEL, 0, flags, &p, NULL, &nh,
+ table, metric);
+ } else {
+ /* XXX: need to compare the entire list of nexthops
+ * here for NLM_F_APPEND stupidity */
+ rib_delete(afi, SAFI_UNICAST, vrf_id,
+ ZEBRA_ROUTE_KERNEL, 0, flags, &p, NULL, NULL,
+ table, metric);
}
}
if (IS_ZEBRA_DEBUG_KERNEL) {
struct interface *ifp;
- strcpy(sbuf, inet_ntoa(m->sg.src));
- strcpy(gbuf, inet_ntoa(m->sg.grp));
+ strlcpy(sbuf, inet_ntoa(m->sg.src), sizeof(sbuf));
+ strlcpy(gbuf, inet_ntoa(m->sg.grp), sizeof(gbuf));
for (count = 0; count < oif_count; count++) {
ifp = if_lookup_by_index(oif[count], vrf);
char temp[256];
if (len < 0)
return -1;
- switch (rtm->rtm_type) {
- case RTN_UNICAST:
- netlink_route_change_read_unicast(snl, h, ns_id, startup);
- break;
- case RTN_MULTICAST:
+ if (rtm->rtm_type == RTN_MULTICAST)
netlink_route_change_read_multicast(snl, h, ns_id, startup);
- break;
- default:
- return 0;
- break;
- }
-
+ else
+ netlink_route_change_read_unicast(snl, h, ns_id, startup);
return 0;
}
struct sockaddr_nl snl;
struct nexthop *nexthop = NULL;
unsigned int nexthop_num;
- int discard;
+ int discard = 0;
int family = PREFIX_FAMILY(p);
const char *routedesc;
int setsrc = 0;
req.r.rtm_src_len = src_p ? src_p->prefixlen : 0;
req.r.rtm_protocol = get_rt_proto(re->type);
req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+ req.r.rtm_type = RTN_UNICAST;
- if ((re->flags & ZEBRA_FLAG_BLACKHOLE)
- || (re->flags & ZEBRA_FLAG_REJECT))
+ if (re->nexthop_num == 1
+ && re->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
discard = 1;
- else
- discard = 0;
-
- if (cmd == RTM_NEWROUTE) {
- if (discard) {
- if (re->flags & ZEBRA_FLAG_BLACKHOLE)
- req.r.rtm_type = RTN_BLACKHOLE;
- else if (re->flags & ZEBRA_FLAG_REJECT)
- req.r.rtm_type = RTN_UNREACHABLE;
- else
- assert(RTN_BLACKHOLE
- != RTN_UNREACHABLE); /* false */
- } else
- req.r.rtm_type = RTN_UNICAST;
+
+ switch (re->nexthop->bh_type) {
+ case BLACKHOLE_ADMINPROHIB:
+ req.r.rtm_type = RTN_PROHIBIT;
+ break;
+ case BLACKHOLE_REJECT:
+ req.r.rtm_type = RTN_UNREACHABLE;
+ break;
+ default:
+ req.r.rtm_type = RTN_BLACKHOLE;
+ break;
+ }
}
addattr_l(&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
addattr32(&req.n, sizeof req, RTA_TABLE, re->table);
}
+ if (discard)
+ goto skip;
+
if (re->mtu || re->nexthop_mtu) {
char buf[NL_PKT_BUF_SIZE];
struct rtattr *rta = (void *)buf;
RTA_PAYLOAD(rta));
}
- if (discard) {
- if (cmd == RTM_NEWROUTE)
- for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
- /* We shouldn't encounter recursive nexthops on
- * discard routes,
- * but it is probably better to handle that case
- * correctly anyway.
- */
- if (CHECK_FLAG(nexthop->flags,
- NEXTHOP_FLAG_RECURSIVE))
- continue;
- }
- goto skip;
- }
-
/* Count overall nexthops so we can decide whether to use singlepath
* or multipath case. */
nexthop_num = 0;
int kernel_route_rib(struct prefix *p, struct prefix *src_p,
struct route_entry *old, struct route_entry *new)
{
+ assert(old || new);
+
if (!old && new)
return netlink_route_multipath(RTM_NEWROUTE, p, src_p, new, 0);
if (old && !new)
* itself
*/
if (IS_ZEBRA_IF_VLAN(ifp)) {
- link_if = zif->link;
+ link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
+ zif->link_ifindex);
if (!link_if)
return 0;
} else if (IS_ZEBRA_IF_BRIDGE(ifp))
extern struct zebra_privs_t zserv_privs;
-/* kernel socket export */
-extern int rtm_write(int message, union sockunion *dest, union sockunion *mask,
- union sockunion *gate, union sockunion *mpls,
- unsigned int index, int zebra_flags, int metric);
-
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
/* Adjust netmask socket length. Return value is a adjusted sin_len
value. */
int gate = 0;
int error;
char prefix_buf[PREFIX_STRLEN];
+ enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
if (IS_ZEBRA_DEBUG_RIB)
prefix2str(p, prefix_buf, sizeof(prefix_buf));
struct in_addr loopback;
loopback.s_addr = htonl(INADDR_LOOPBACK);
sin_gate.sin_addr = loopback;
+ bh_type = nexthop->bh_type;
gate = 1;
}
smplsp = (union sockunion *)&smpls;
#endif
- error = rtm_write(
- cmd, (union sockunion *)&sin_dest,
- (union sockunion *)mask,
- gate ? (union sockunion *)&sin_gate : NULL,
- smplsp, ifindex, re->flags, re->metric);
+ error = rtm_write(cmd, (union sockunion *)&sin_dest,
+ (union sockunion *)mask,
+ gate ? (union sockunion *)&sin_gate
+ : NULL,
+ smplsp, ifindex, bh_type, re->metric);
if (IS_ZEBRA_DEBUG_RIB) {
if (!gate) {
ifindex_t ifindex = 0;
int gate = 0;
int error;
+ enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
memset(&sin_dest, 0, sizeof(struct sockaddr_in6));
sin_dest.sin6_family = AF_INET6;
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
ifindex = nexthop->ifindex;
+ if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
+ bh_type = nexthop->bh_type;
+
if (cmd == RTM_ADD)
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
}
error = rtm_write(cmd, (union sockunion *)&sin_dest,
(union sockunion *)mask,
gate ? (union sockunion *)&sin_gate : NULL,
- smplsp, ifindex, re->flags, re->metric);
+ smplsp, ifindex, bh_type, re->metric);
#if 0
if (error)
char adata[1024];
/* Fill in message and iovec. */
+ memset(&msg, 0, sizeof(msg));
msg.msg_name = (void *)from;
msg.msg_namelen = sizeof(struct sockaddr_in6);
msg.msg_iov = &iov;
safe_strerror(errno));
if (sock < 0) {
- close(sock);
return -1;
}
static void handle_route_entry(mib2_ipRouteEntry_t *routeEntry)
{
struct prefix prefix;
- struct in_addr tmpaddr, gateway;
- union g_addr *ggateway;
+ struct in_addr tmpaddr;
+ struct nexthop nh;
u_char zebra_flags = 0;
if (routeEntry->ipRouteInfo.re_ire_type & IRE_CACHETABLE)
tmpaddr.s_addr = routeEntry->ipRouteMask;
prefix.prefixlen = ip_masklen(tmpaddr);
- gateway.s_addr = routeEntry->ipRouteNextHop;
- ggateway = (union g_addr *)&gateway;
+ memset(&nh, 0, sizeof(nh));
+ nh.type = NEXTHOP_TYPE_IPV4;
+ nh.gate.ipv4.s_addr = routeEntry->ipRouteNextHop;
rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0,
- zebra_flags, &prefix, NULL, ggateway, NULL, 0, 0, 0, 0, 0);
+ zebra_flags, &prefix, NULL, &nh, 0, 0, 0, 0);
}
void route_read(struct zebra_ns *zns)
rib_dest_t *dest, struct route_entry *re)
{
struct nexthop *nexthop;
- int discard;
memset(ri, 0, sizeof(*ri));
}
ri->rtm_protocol = netlink_proto_from_route_type(re->type);
-
- if ((re->flags & ZEBRA_FLAG_BLACKHOLE)
- || (re->flags & ZEBRA_FLAG_REJECT))
- discard = 1;
- else
- discard = 0;
-
- if (cmd == RTM_NEWROUTE) {
- if (discard) {
- if (re->flags & ZEBRA_FLAG_BLACKHOLE)
- ri->rtm_type = RTN_BLACKHOLE;
- else if (re->flags & ZEBRA_FLAG_REJECT)
- ri->rtm_type = RTN_UNREACHABLE;
- else
- assert(0);
- } else
- ri->rtm_type = RTN_UNICAST;
- }
-
+ ri->rtm_type = RTN_UNICAST;
ri->metric = &re->metric;
- if (discard)
- return 1;
-
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
if (ri->num_nhs >= multipath_num)
break;
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
+ if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
+ switch (nexthop->bh_type) {
+ case BLACKHOLE_ADMINPROHIB:
+ ri->rtm_type = RTN_PROHIBIT;
+ break;
+ case BLACKHOLE_REJECT:
+ ri->rtm_type = RTN_UNREACHABLE;
+ break;
+ case BLACKHOLE_NULL:
+ default:
+ ri->rtm_type = RTN_BLACKHOLE;
+ break;
+ }
+ return 1;
+ }
+
if ((cmd == RTM_NEWROUTE
&& CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|| (cmd == RTM_DELROUTE
struct route_entry *re)
{
Fpm__AddRoute *msg;
- int discard;
struct nexthop *nexthop;
uint num_nhs, u;
struct nexthop *nexthops[MULTIPATH_NUM];
msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST;
msg->key = fpm_route_key_create(allocator, rib_dest_prefix(dest));
qpb_protocol_set(&msg->protocol, re->type);
-
- if ((re->flags & ZEBRA_FLAG_BLACKHOLE)
- || (re->flags & ZEBRA_FLAG_REJECT))
- discard = 1;
- else
- discard = 0;
-
- if (discard) {
- if (re->flags & ZEBRA_FLAG_BLACKHOLE) {
- msg->route_type = FPM__ROUTE_TYPE__BLACKHOLE;
- } else if (re->flags & ZEBRA_FLAG_REJECT) {
- msg->route_type = FPM__ROUTE_TYPE__UNREACHABLE;
- } else {
- assert(0);
- }
- return msg;
- } else {
- msg->route_type = FPM__ROUTE_TYPE__NORMAL;
- }
-
+ msg->route_type = FPM__ROUTE_TYPE__NORMAL;
msg->metric = re->metric;
/*
if (num_nhs >= ZEBRA_NUM_OF(nexthops))
break;
+ if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
+ switch (nexthop->bh_type) {
+ case BLACKHOLE_REJECT:
+ msg->route_type = FPM__ROUTE_TYPE__UNREACHABLE;
+ break;
+ case BLACKHOLE_NULL:
+ default:
+ msg->route_type = FPM__ROUTE_TYPE__BLACKHOLE;
+ break;
+ }
+ return msg;
+ }
+
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
zif->brslave_info.bridge_ifindex = bridge_ifindex;
/* Set up or remove link with master */
- if (bridge_ifindex != IFINDEX_INTERNAL)
+ if (bridge_ifindex != IFINDEX_INTERNAL) {
zebra_l2_map_slave_to_bridge(&zif->brslave_info);
- else if (old_bridge_ifindex != IFINDEX_INTERNAL)
+ /* In the case of VxLAN, invoke the handler for EVPN. */
+ if (zif->zif_type == ZEBRA_IF_VXLAN)
+ zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE);
+ } else if (old_bridge_ifindex != IFINDEX_INTERNAL) {
+ /*
+ * In the case of VxLAN, invoke the handler for EVPN.
+ * Note that this should be done *prior*
+ * to unmapping the interface from the bridge.
+ */
+ if (zif->zif_type == ZEBRA_IF_VXLAN)
+ zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE);
zebra_l2_unmap_slave_from_bridge(&zif->brslave_info);
-
- /* In the case of VxLAN, invoke the handler for EVPN. */
- if (zif->zif_type == ZEBRA_IF_VXLAN)
- zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE);
+ }
}
zebra_lsp_t *lsp;
lsp = (zebra_lsp_t *)backet->data;
- lsp_processq_add(lsp);
+ (void)lsp_processq_add(lsp);
}
/*
for (ALL_LIST_ELEMENTS_RO(slsp_list, node, slsp)) {
for (snhlfe = slsp->snhlfe_list; snhlfe;
snhlfe = snhlfe->next) {
- char buf[INET6_ADDRSTRLEN];
+ char buf[BUFSIZ];
char lstr[30];
- snhlfe2str(snhlfe, buf, BUFSIZ);
+ snhlfe2str(snhlfe, buf, sizeof(buf));
switch (snhlfe->out_label) {
case MPLS_V4_EXP_NULL_LABEL:
case MPLS_V6_EXP_NULL_LABEL:
char sbuf[40];
char gbuf[40];
- strcpy(sbuf, inet_ntoa(mroute.sg.src));
- strcpy(gbuf, inet_ntoa(mroute.sg.grp));
+ strlcpy(sbuf, inet_ntoa(mroute.sg.src), sizeof(sbuf));
+ strlcpy(gbuf, inet_ntoa(mroute.sg.grp), sizeof(gbuf));
zlog_debug("Asking for (%s,%s) mroute information", sbuf, gbuf);
}
if (ptm_cb.wb)
buffer_free(ptm_cb.wb);
- if (ptm_cb.ptm_sock != -1)
+ if (ptm_cb.ptm_sock >= 0)
close(ptm_cb.ptm_sock);
}
if (!pw)
return CMD_SUCCESS;
zebra_pw_del(zvrf, pw);
+ return CMD_SUCCESS;
}
if (!pw)
return nexthop;
}
-struct nexthop *route_entry_nexthop_blackhole_add(struct route_entry *re)
+struct nexthop *route_entry_nexthop_blackhole_add(struct route_entry *re,
+ enum blackhole_type bh_type)
{
struct nexthop *nexthop;
nexthop = nexthop_new();
nexthop->type = NEXTHOP_TYPE_BLACKHOLE;
- SET_FLAG(re->flags, ZEBRA_FLAG_BLACKHOLE);
+ nexthop->bh_type = bh_type;
route_entry_nexthop_add(re, nexthop);
continue;
}
- /* If the longest prefix match for the nexthop yields
- * a blackhole, mark it as inactive. */
- if (CHECK_FLAG(match->flags, ZEBRA_FLAG_BLACKHOLE)
- || CHECK_FLAG(match->flags, ZEBRA_FLAG_REJECT))
- return 0;
-
if (match->type == ZEBRA_ROUTE_CONNECT) {
/* Directly point connected route. */
newhop = match->nexthop;
return 1;
} else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_INTERNAL)) {
resolved = 0;
- for (ALL_NEXTHOPS(match->nexthop, newhop))
- if (CHECK_FLAG(newhop->flags, NEXTHOP_FLAG_FIB)
- && !CHECK_FLAG(newhop->flags,
- NEXTHOP_FLAG_RECURSIVE)) {
- if (set) {
- SET_FLAG(
- nexthop->flags,
- NEXTHOP_FLAG_RECURSIVE);
- SET_FLAG(
- re->status,
- ROUTE_ENTRY_NEXTHOPS_CHANGED);
-
- nexthop_set_resolved(
- afi, newhop, nexthop);
- }
- resolved = 1;
+ for (ALL_NEXTHOPS(match->nexthop, newhop)) {
+ if (newhop->type == NEXTHOP_TYPE_BLACKHOLE)
+ continue;
+ if (!CHECK_FLAG(newhop->flags,
+ NEXTHOP_FLAG_FIB))
+ continue;
+ if (CHECK_FLAG(newhop->flags,
+ NEXTHOP_FLAG_RECURSIVE))
+ continue;
+
+ if (set) {
+ SET_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_RECURSIVE);
+ SET_FLAG(re->status,
+ ROUTE_ENTRY_NEXTHOPS_CHANGED);
+ nexthop_set_resolved(afi, newhop,
+ nexthop);
}
+ resolved = 1;
+ }
if (resolved && set)
re->nexthop_mtu = match->mtu;
return resolved;
} else if (re->type == ZEBRA_ROUTE_STATIC) {
resolved = 0;
- for (ALL_NEXTHOPS(match->nexthop, newhop))
- if (CHECK_FLAG(newhop->flags,
- NEXTHOP_FLAG_FIB)) {
- if (set) {
- SET_FLAG(
- nexthop->flags,
- NEXTHOP_FLAG_RECURSIVE);
+ for (ALL_NEXTHOPS(match->nexthop, newhop)) {
+ if (newhop->type == NEXTHOP_TYPE_BLACKHOLE)
+ continue;
+ if (!CHECK_FLAG(newhop->flags,
+ NEXTHOP_FLAG_FIB))
+ continue;
- nexthop_set_resolved(
- afi, newhop, nexthop);
- }
- resolved = 1;
+ if (set) {
+ SET_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_RECURSIVE);
+ nexthop_set_resolved(afi, newhop,
+ nexthop);
}
+ resolved = 1;
+ }
if (resolved && set)
re->nexthop_mtu = match->mtu;
return resolved;
void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
u_short instance, int flags, struct prefix *p,
- struct prefix_ipv6 *src_p, union g_addr *gate,
- ifindex_t ifindex, u_int32_t table_id,
- u_int32_t metric)
+ struct prefix_ipv6 *src_p, const struct nexthop *nh,
+ u_int32_t table_id, u_int32_t metric)
{
struct route_table *table;
struct route_node *rn;
struct route_entry *re;
struct route_entry *fib = NULL;
struct route_entry *same = NULL;
- struct nexthop *nexthop;
+ struct nexthop *rtnh;
char buf2[INET6_ADDRSTRLEN];
assert(!src_p || afi == AFI_IP6);
if (re->type == ZEBRA_ROUTE_KERNEL &&
re->metric != metric)
continue;
- if (re->type == ZEBRA_ROUTE_CONNECT && (nexthop = re->nexthop)
- && nexthop->type == NEXTHOP_TYPE_IFINDEX) {
- if (nexthop->ifindex != ifindex)
+ if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->nexthop)
+ && rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) {
+ if (rtnh->ifindex != nh->ifindex)
continue;
if (re->refcnt) {
re->refcnt--;
}
/* Make sure that the route found has the same gateway. */
else {
- if (gate == NULL) {
+ if (nh == NULL) {
same = re;
break;
}
- for (ALL_NEXTHOPS(re->nexthop, nexthop))
- if (IPV4_ADDR_SAME(&nexthop->gate.ipv4, &gate->ipv4)
- || IPV6_ADDR_SAME(&nexthop->gate.ipv6,
- gate)) {
+ for (ALL_NEXTHOPS(re->nexthop, rtnh))
+ if (nexthop_same_no_recurse(rtnh, nh)) {
same = re;
break;
}
}
if (allow_delete) {
/* Unset flags. */
- for (nexthop = fib->nexthop; nexthop;
- nexthop = nexthop->next)
- UNSET_FLAG(nexthop->flags,
+ for (rtnh = fib->nexthop; rtnh;
+ rtnh = rtnh->next)
+ UNSET_FLAG(rtnh->flags,
NEXTHOP_FLAG_FIB);
UNSET_FLAG(fib->status,
}
} else {
if (IS_ZEBRA_DEBUG_RIB) {
- if (gate)
+ if (nh)
rnode_debug(
rn, vrf_id,
"via %s ifindex %d type %d "
"doesn't exist in rib",
inet_ntop(
- family2afi(afi), gate,
- buf2,
+ family2afi(afi),
+ &nh->gate, buf2,
INET_ADDRSTRLEN), /* FIXME
*/
- ifindex, type);
+ nh->ifindex, type);
else
rnode_debug(
rn, vrf_id,
- "ifindex %d type %d doesn't exist in rib",
- ifindex, type);
+ "type %d doesn't exist in rib",
+ type);
}
route_unlock_node(rn);
return;
int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance,
int flags, struct prefix *p, struct prefix_ipv6 *src_p,
- union g_addr *gate, union g_addr *src, ifindex_t ifindex,
- u_int32_t table_id, u_int32_t metric, u_int32_t mtu,
- u_char distance)
+ const struct nexthop *nh, u_int32_t table_id, u_int32_t metric,
+ u_int32_t mtu, u_char distance)
{
struct route_entry *re;
struct route_entry *same = NULL;
struct route_table *table;
struct route_node *rn;
- struct nexthop *nexthop;
+ struct nexthop *rtnh;
assert(!src_p || afi == AFI_IP6);
break;
}
/* Duplicate system route comes in. */
- else if ((nexthop = re->nexthop)
- && nexthop->type == NEXTHOP_TYPE_IFINDEX
- && nexthop->ifindex == ifindex
+ else if ((rtnh = re->nexthop)
+ && rtnh->type == NEXTHOP_TYPE_IFINDEX
+ && rtnh->ifindex == nh->ifindex
&& !CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) {
re->refcnt++;
return 0;
re->nexthop_num = 0;
re->uptime = time(NULL);
- /* Nexthop settings. */
- if (gate) {
- if (afi == AFI_IP6) {
- if (ifindex)
- route_entry_nexthop_ipv6_ifindex_add(
- re, &gate->ipv6, ifindex);
- else
- route_entry_nexthop_ipv6_add(re, &gate->ipv6);
- } else {
- if (ifindex)
- route_entry_nexthop_ipv4_ifindex_add(
- re, &gate->ipv4, &src->ipv4, ifindex);
- else
- route_entry_nexthop_ipv4_add(re, &gate->ipv4,
- &src->ipv4);
- }
- } else
- route_entry_nexthop_ifindex_add(re, ifindex);
+ rtnh = nexthop_new();
+ *rtnh = *nh;
+ route_entry_nexthop_add(re, rtnh);
/* If this route is kernel route, set FIB flag to the route. */
if (RIB_SYSTEM_ROUTE(re))
- for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next)
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+ for (rtnh = re->nexthop; rtnh; rtnh = rtnh->next)
+ SET_FLAG(rtnh->flags, NEXTHOP_FLAG_FIB);
/* Link new rib to node.*/
if (IS_ZEBRA_DEBUG_RIB) {
void rib_close_table(struct route_table *table)
{
struct route_node *rn;
- rib_table_info_t *info = table->info;
+ rib_table_info_t *info;
struct route_entry *re;
- if (table)
- for (rn = route_top(table); rn; rn = srcdest_route_next(rn))
- RNODE_FOREACH_RE(rn, re)
- {
- if (!CHECK_FLAG(re->status,
- ROUTE_ENTRY_SELECTED_FIB))
- continue;
+ if (!table)
+ return;
- if (info->safi == SAFI_UNICAST)
- hook_call(rib_update, rn, NULL);
+ info = table->info;
- if (!RIB_SYSTEM_ROUTE(re))
- rib_uninstall_kernel(rn, re);
- }
+ for (rn = route_top(table); rn; rn = srcdest_route_next(rn))
+ RNODE_FOREACH_RE(rn, re)
+ {
+ if (!CHECK_FLAG(re->status,
+ ROUTE_ENTRY_SELECTED_FIB))
+ continue;
+
+ if (info->safi == SAFI_UNICAST)
+ hook_call(rib_update, rn, NULL);
+
+ if (!RIB_SYSTEM_ROUTE(re))
+ rib_uninstall_kernel(rn, re);
+ }
}
/* Routing information base initialize. */
{
VTY_DECLVAR_CONTEXT(route_map_index, index);
int ret;
+ int retval = CMD_SUCCESS;
ret = route_map_add_match(index, command, arg);
- if (ret) {
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% Zebra Can't find rule.\n");
- return CMD_WARNING_CONFIG_FAILED;
- case RMAP_COMPILE_ERROR:
- vty_out(vty, "%% Zebra Argument is malformed.\n");
- return CMD_WARNING_CONFIG_FAILED;
+ switch (ret) {
+ case RMAP_RULE_MISSING:
+ vty_out(vty, "%% Zebra Can't find rule.\n");
+ retval = CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out(vty, "%% Zebra Argument is malformed.\n");
+ retval = CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_SUCCESS:
+ if (type != RMAP_EVENT_MATCH_ADDED) {
+ route_map_upd8_dependency(type, arg, index->map->name);
}
+ break;
}
- if (type != RMAP_EVENT_MATCH_ADDED) {
- route_map_upd8_dependency(type, arg, index->map->name);
- }
- return CMD_SUCCESS;
+ return retval;
}
/* Delete zebra route map rule. */
{
VTY_DECLVAR_CONTEXT(route_map_index, index);
int ret;
+ int retval = CMD_SUCCESS;
char *dep_name = NULL;
const char *tmpstr;
char *rmap_name = NULL;
}
ret = route_map_delete_match(index, command, arg);
- if (ret) {
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% Zebra Can't find rule.\n");
- return CMD_WARNING_CONFIG_FAILED;
- case RMAP_COMPILE_ERROR:
- vty_out(vty, "%% Zebra Argument is malformed.\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
+ switch (ret) {
+ case RMAP_RULE_MISSING:
+ vty_out(vty, "%% Zebra Can't find rule.\n");
+ retval = CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out(vty, "%% Zebra Argument is malformed.\n");
+ retval = CMD_WARNING_CONFIG_FAILED;
+ break;
+ case RMAP_COMPILE_SUCCESS:
+ if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
+ route_map_upd8_dependency(type, dep_name, rmap_name);
+ break;
}
- if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
- route_map_upd8_dependency(type, dep_name, rmap_name);
-
if (dep_name)
XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
if (rmap_name)
XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
- return CMD_SUCCESS;
+ return retval;
}
/* 'match tag TAG'
si->ifindex);
break;
case STATIC_BLACKHOLE:
- nexthop = route_entry_nexthop_blackhole_add(re);
+ nexthop = route_entry_nexthop_blackhole_add(
+ re, si->bh_type);
break;
case STATIC_IPV6_GATEWAY:
nexthop = route_entry_nexthop_ipv6_add(re,
si->ifindex);
break;
case STATIC_BLACKHOLE:
- nexthop = route_entry_nexthop_blackhole_add(re);
+ nexthop = route_entry_nexthop_blackhole_add(
+ re, si->bh_type);
break;
case STATIC_IPV6_GATEWAY:
nexthop = route_entry_nexthop_ipv6_add(re,
si->snh_label.num_labels,
&si->snh_label.label[0]);
- /* Save the flags of this static routes (reject, blackhole) */
- re->flags = si->flags;
-
if (IS_ZEBRA_DEBUG_RIB) {
char buf[INET6_ADDRSTRLEN];
if (IS_ZEBRA_DEBUG_RIB) {
int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
struct prefix_ipv6 *src_p, union g_addr *gate,
- const char *ifname, u_char flags,
+ const char *ifname, enum blackhole_type bh_type,
route_tag_t tag, u_char distance, struct zebra_vrf *zvrf,
struct static_nh_label *snh_label)
{
if ((distance == si->distance) && (tag == si->tag)
&& !memcmp(&si->snh_label, snh_label,
sizeof(struct static_nh_label))
- && si->flags == flags) {
+ && si->bh_type == bh_type) {
route_unlock_node(rn);
return 0;
} else
si->type = type;
si->distance = distance;
- si->flags = flags;
+ si->bh_type = bh_type;
si->tag = tag;
si->vrf_id = zvrf_id(zvrf);
if (ifname)
/*
* Nexthop value.
*/
+ enum blackhole_type bh_type;
union g_addr addr;
ifindex_t ifindex;
char ifname[INTERFACE_NAMSIZ + 1];
- /* bit flags */
- u_char flags;
- /*
- see ZEBRA_FLAG_REJECT
- ZEBRA_FLAG_BLACKHOLE
- */
-
/* Label information */
struct static_nh_label snh_label;
};
extern int static_add_route(afi_t, safi_t safi, u_char type, struct prefix *p,
struct prefix_ipv6 *src_p, union g_addr *gate,
- const char *ifname, u_char flags,
+ const char *ifname, enum blackhole_type bh_type,
route_tag_t tag, u_char distance,
struct zebra_vrf *zvrf,
struct static_nh_label *snh_label);
RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
{
zvrf = vrf->info;
- if (!zvrf || strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) {
+
+ if (!zvrf)
+ continue;
+
+ if (strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) {
vty_out(vty, "vrf %s\n", zvrf_name(zvrf));
vty_out(vty, "!\n");
}
union g_addr gate;
union g_addr *gatep = NULL;
struct in_addr mask;
- u_char flag = 0;
+ enum blackhole_type bh_type = 0;
route_tag_t tag = 0;
struct zebra_vrf *zvrf;
u_char type;
}
}
- /* Null0 static route. */
- if ((ifname != NULL)
- && (strncasecmp(ifname, "Null0", strlen(ifname)) == 0)) {
- if (flag_str) {
- vty_out(vty, "%% can not have flag %s with Null0\n",
- flag_str);
- return CMD_WARNING_CONFIG_FAILED;
- }
- SET_FLAG(flag, ZEBRA_FLAG_BLACKHOLE);
- ifname = NULL;
- }
-
/* Route flags */
if (flag_str) {
switch (flag_str[0]) {
case 'r':
case 'R': /* XXX */
- SET_FLAG(flag, ZEBRA_FLAG_REJECT);
+ bh_type = BLACKHOLE_REJECT;
break;
+ case 'n':
+ case 'N' /* XXX */:
case 'b':
case 'B': /* XXX */
- SET_FLAG(flag, ZEBRA_FLAG_BLACKHOLE);
+ bh_type = BLACKHOLE_NULL;
break;
default:
vty_out(vty, "%% Malformed flag %s \n", flag_str);
if (!negate)
static_add_route(afi, safi, type, &p, src_p, gatep, ifname,
- flag, tag, distance, zvrf, &snh_label);
+ bh_type, tag, distance, zvrf, &snh_label);
else
static_delete_route(afi, safi, type, &p, src_p, gatep, ifname,
tag, distance, zvrf, &snh_label);
}
/* Static route configuration. */
-DEFPY (ip_route,
- ip_route_cmd,
- "[no] ip route\
+DEFPY(ip_route, ip_route_cmd,
+ "[no] ip route\
<A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask>\
<\
{A.B.C.D$gate|INTERFACE$ifname}\
- |null0$ifname\
- |<reject|blackhole>$flag\
+ |<null0|reject|blackhole>$flag\
>\
[{\
tag (1-4294967295)\
|vrf NAME\
|label WORD\
}]",
- NO_STR
- IP_STR
- "Establish static routes\n"
- "IP destination prefix (e.g. 10.0.0.0/8)\n"
- "IP destination prefix\n"
- "IP destination prefix mask\n"
- "IP gateway address\n"
- "IP gateway interface name\n"
- "Null interface\n"
- "Emit an ICMP unreachable when matched\n"
- "Silently discard pkts when matched\n"
- "Set tag for this route\n"
- "Tag value\n"
- "Distance value for this route\n"
- VRF_CMD_HELP_STR
- MPLS_LABEL_HELPSTR)
+ NO_STR IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ VRF_CMD_HELP_STR
+ MPLS_LABEL_HELPSTR)
{
return zebra_static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix,
mask_str, NULL, gate_str, ifname, flag,
vty_out(vty, ", best");
if (re->refcnt)
vty_out(vty, ", refcnt %ld", re->refcnt);
- if (CHECK_FLAG(re->flags, ZEBRA_FLAG_BLACKHOLE))
- vty_out(vty, ", blackhole");
- if (CHECK_FLAG(re->flags, ZEBRA_FLAG_REJECT))
- vty_out(vty, ", reject");
vty_out(vty, "\n");
if (re->type == ZEBRA_ROUTE_RIP || re->type == ZEBRA_ROUTE_OSPF
re->vrf_id));
break;
case NEXTHOP_TYPE_BLACKHOLE:
- vty_out(vty, " directly connected, Null0");
+ vty_out(vty, " unreachable");
+ switch (nexthop->bh_type) {
+ case BLACKHOLE_REJECT:
+ vty_out(vty, " (ICMP unreachable)");
+ break;
+ case BLACKHOLE_ADMINPROHIB:
+ vty_out(vty,
+ " (ICMP admin-prohibited)");
+ break;
+ case BLACKHOLE_NULL:
+ vty_out(vty, " (blackhole)");
+ break;
+ case BLACKHOLE_UNSPEC:
+ break;
+ }
break;
default:
break;
json_object_int_add(json_route, "metric", re->metric);
}
- if (CHECK_FLAG(re->flags, ZEBRA_FLAG_BLACKHOLE))
- json_object_boolean_true_add(json_route, "blackhole");
-
- if (CHECK_FLAG(re->flags, ZEBRA_FLAG_REJECT))
- json_object_boolean_true_add(json_route, "reject");
-
if (re->type == ZEBRA_ROUTE_RIP || re->type == ZEBRA_ROUTE_OSPF
|| re->type == ZEBRA_ROUTE_ISIS
|| re->type == ZEBRA_ROUTE_NHRP
break;
case NEXTHOP_TYPE_BLACKHOLE:
json_object_boolean_true_add(json_nexthop,
- "blackhole");
+ "unreachable");
+ switch (nexthop->bh_type) {
+ case BLACKHOLE_REJECT:
+ json_object_boolean_true_add(
+ json_nexthop, "reject");
+ break;
+ case BLACKHOLE_ADMINPROHIB:
+ json_object_boolean_true_add(
+ json_nexthop,
+ "admin-prohibited");
+ break;
+ case BLACKHOLE_NULL:
+ json_object_boolean_true_add(
+ json_nexthop, "blackhole");
+ break;
+ case BLACKHOLE_UNSPEC:
+ break;
+ }
break;
default:
break;
ifindex2ifname(nexthop->ifindex, re->vrf_id));
break;
case NEXTHOP_TYPE_BLACKHOLE:
- vty_out(vty, " is directly connected, Null0");
+ vty_out(vty, " unreachable");
+ switch (nexthop->bh_type) {
+ case BLACKHOLE_REJECT:
+ vty_out(vty, " (ICMP unreachable)");
+ break;
+ case BLACKHOLE_ADMINPROHIB:
+ vty_out(vty, " (ICMP admin-prohibited)");
+ break;
+ case BLACKHOLE_NULL:
+ vty_out(vty, " (blackhole)");
+ break;
+ case BLACKHOLE_UNSPEC:
+ break;
+ }
break;
default:
break;
sizeof buf, 1));
}
- if (CHECK_FLAG(re->flags, ZEBRA_FLAG_BLACKHOLE))
- vty_out(vty, ", bh");
- if (CHECK_FLAG(re->flags, ZEBRA_FLAG_REJECT))
- vty_out(vty, ", rej");
-
if (re->type == ZEBRA_ROUTE_RIP || re->type == ZEBRA_ROUTE_OSPF
|| re->type == ZEBRA_ROUTE_ISIS
|| re->type == ZEBRA_ROUTE_NHRP
tag = strtoul(argv[idx + 1]->arg, NULL, 10);
else if (argv_find(argv, argc, "A.B.C.D/M", &idx)) {
- str2prefix(argv[idx]->arg, &p);
+ if (str2prefix(argv[idx]->arg, &p) <= 0) {
+ vty_out(vty, "%% Malformed prefix\n");
+ return CMD_WARNING;
+ }
longer_prefixes = true;
}
case STATIC_IFNAME:
vty_out(vty, " %s", si->ifname);
break;
- /* blackhole and Null0 mean the same thing */
case STATIC_BLACKHOLE:
- if (CHECK_FLAG(si->flags, ZEBRA_FLAG_REJECT))
+ switch (si->bh_type) {
+ case BLACKHOLE_REJECT:
vty_out(vty, " reject");
- else
- vty_out(vty, " Null0");
+ break;
+ default:
+ vty_out(vty, " blackhole");
+ break;
+ }
break;
case STATIC_IPV4_GATEWAY_IFNAME:
vty_out(vty, " %s %s",
break;
}
- /* flags are incompatible with STATIC_BLACKHOLE
- */
- if (si->type != STATIC_BLACKHOLE) {
- if (CHECK_FLAG(si->flags,
- ZEBRA_FLAG_REJECT))
- vty_out(vty, " %s", "reject");
-
- if (CHECK_FLAG(si->flags,
- ZEBRA_FLAG_BLACKHOLE))
- vty_out(vty, " %s",
- "blackhole");
- }
-
if (si->tag)
vty_out(vty, " tag %" ROUTE_TAG_PRI,
si->tag);
return write;
}
-DEFPY (ipv6_route,
- ipv6_route_cmd,
- "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M]\
+DEFPY(ipv6_route,
+ ipv6_route_cmd,
+ "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M]\
<\
{X:X::X:X$gate|INTERFACE$ifname}\
- |null0$ifname\
- |<reject|blackhole>$flag\
+ |<null0|reject|blackhole>$flag\
>\
[{\
tag (1-4294967295)\
|vrf NAME\
|label WORD\
}]",
- NO_STR
- IPV6_STR
- "Establish static routes\n"
- "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
- "IPv6 source-dest route\n"
- "IPv6 source prefix\n"
- "IPv6 gateway address\n"
- "IPv6 gateway interface name\n"
- "Null interface\n"
- "Emit an ICMP unreachable when matched\n"
- "Silently discard pkts when matched\n"
- "Set tag for this route\n"
- "Tag value\n"
- "Distance value for this prefix\n"
- VRF_CMD_HELP_STR
- MPLS_LABEL_HELPSTR)
+ NO_STR
+ IPV6_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 source-dest route\n"
+ "IPv6 source prefix\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Null interface\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n"
+ VRF_CMD_HELP_STR
+ MPLS_LABEL_HELPSTR)
{
return zebra_static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str,
NULL, from_str, gate_str, ifname, flag,
tag = strtoul(argv[idx + 1]->arg, NULL, 10);
else if (argv_find(argv, argc, "X:X::X:X/M", &idx)) {
- str2prefix(argv[idx]->arg, &p);
+ if (str2prefix(argv[idx]->arg, &p) <= 0) {
+ vty_out(vty, "%% Malformed prefix\n");
+ return CMD_WARNING;
+ }
longer_prefixes = true;
}
vty_out(vty,
"Invalid routing table ID, %d. Must be in range 1-252\n",
table_id);
+ if (rmap)
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap);
return CMD_WARNING;
}
vty_out(vty,
"Invalid routing table ID, %d. Must be non-default table\n",
table_id);
+ if (rmap)
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap);
return CMD_WARNING;
}
if (json == NULL) {
vty_out(vty, " Remote VTEP: %s",
inet_ntoa(n->r_vtep_ip));
- vty_out(vty, " State: %s", IS_ZEBRA_NEIGH_ACTIVE(n)
- ? "Active"
- : "Inactive");
} else
json_object_string_add(json, "remoteVtep",
inet_ntoa(n->r_vtep_ip));
}
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ if (!json) {
+ vty_out(vty, "\n");
+ vty_out(vty, " State: %s",
+ IS_ZEBRA_NEIGH_ACTIVE(n) ? "Active"
+ : "Inactive");
+ }
+ }
if (json == NULL)
vty_out(vty, "\n");
}
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
vty_out(vty, " Auto Mac ");
}
- vty_out(vty, " ARP ref: %u\n", mac->neigh_refcnt);
+ vty_out(vty, "\n");
/* print all the associated neigh */
vty_out(vty, " Neighbors:\n");
if (!listcount(mac->neigh_list))
if (!(n->flags & ZEBRA_NEIGH_REMOTE))
return 0;
- zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
- assert(zvrf);
if (!zvni->vxlan_if) {
zlog_err("VNI %u hash %p couldn't be uninstalled - no intf",
zvni->vni, zvni);
return -1;
}
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+ assert(zvrf);
+
zif = zvni->vxlan_if->info;
if (!zif)
return -1;
zlog_err(
"%u:Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)),
- prefix_mac2str(macaddr, NULL,
- ETHER_ADDR_STRLEN),
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
ifp->name, ifp->ifindex, zvni->vni);
return -1;
}
memcpy(&n->emac, macaddr, ETH_ALEN);
n->ifindex = ifp->ifindex;
- /* We have a neigh associated to mac increment the refcnt*/
- mac->neigh_refcnt++;
-
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s add to BGP",
ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni,
- prefix_mac2str(macaddr, NULL, ETHER_ADDR_STRLEN),
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
ipaddr2str(ip, buf2, sizeof(buf2)));
zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip, macaddr,
struct zebra_vrf *zvrf = NULL;
zebra_neigh_t *n = NULL;
zebra_mac_t *mac = NULL;
+ char buf1[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
/* mac entry should be present */
mac = zvni_mac_lookup(zvni, &n->emac);
- if (!mac)
- zlog_err("%u: MAC %s doesnt exsists for neigh %s on VNI %u",
+ if (!mac) {
+ zlog_err("%u: MAC %s doesnt exists for neigh %s on VNI %u",
ifp->vrf_id,
- prefix_mac2str(&n->emac, NULL, ETHER_ADDR_STRLEN),
+ prefix_mac2str(&n->emac, buf1, sizeof(buf1)),
ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni);
+ return -1;
+ }
/* If the entry is not local nothing to do*/
if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
zlog_debug(
"%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP",
ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni,
- prefix_mac2str(&(n->emac), NULL, ETHER_ADDR_STRLEN),
+ prefix_mac2str(&(n->emac), buf1, sizeof(buf1)),
ipaddr2str(ip, buf2, sizeof(buf2)));
/* Remove neighbor from BGP. */
zvni_neigh_del(zvni, n);
/* see if the mac needs to be deleted as well*/
- zvni_deref_ip2mac(zvni, mac, 0);
+ if (mac)
+ zvni_deref_ip2mac(zvni, mac, 0);
return 0;
}
struct zebra_l2info_vxlan zl2_info;
struct interface *vlan_if = NULL;
struct interface *vrr_if = NULL;
+ struct interface *ifp;
/* Add primary SVI MAC*/
zvni = (zebra_vni_t *)backet->data;
if (!zvni)
return;
- zif = zvni->vxlan_if->info;
+ ifp = zvni->vxlan_if;
+ if (!ifp)
+ return;
+ zif = ifp->info;
+
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ return;
+
zl2_info = zif->l2info.vxl;
vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan,
struct zebra_l2info_vxlan zl2_info;
struct interface *vlan_if = NULL;
struct interface *vrr_if = NULL;
+ struct interface *ifp = NULL;
zvni = (zebra_vni_t *)backet->data;
if (!zvni)
if (!advertise_gw_macip_enabled(zvrf, zvni))
return;
- zif = zvni->vxlan_if->info;
+ ifp = zvni->vxlan_if;
+ if (!ifp)
+ return;
+ zif = ifp->info;
+
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ return;
zl2_info = zif->l2info.vxl;
vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan,
vlanid_t vid = 0;
zebra_vni_t *zvni;
+ if (!br_if)
+ return NULL;
+
/* Make sure the linked interface is a bridge. */
if (!IS_ZEBRA_IF_BRIDGE(br_if))
return NULL;
struct zebra_l2info_vlan *vl;
u_char bridge_vlan_aware;
+ /* Defensive check, caller expected to invoke only with valid bridge. */
+ if (!br_if)
+ return NULL;
+
/* Determine if bridge is VLAN-aware or not */
zif = br_if->info;
assert(zif);
static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac,
int uninstall)
{
- if (mac->neigh_refcnt)
- mac->neigh_refcnt--;
-
- if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) || mac->neigh_refcnt > 0)
+ if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)
+ || !list_isempty(mac->neigh_list))
return;
if (uninstall)
/* see if the AUTO mac needs to be deleted */
if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_AUTO)
- || !listcount(zmac->neigh_list))
+ && !listcount(zmac->neigh_list))
zvni_mac_del(zvni, zmac);
return 0;
zebra_vni_t *zvni;
zebra_neigh_t *n;
struct zebra_vrf *zvrf;
- zebra_mac_t *zmac;
+ zebra_mac_t *zmac, *old_zmac;
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
- int send_upd = 1, send_del = 0;
/* We are only interested in neighbors on an SVI that resides on top
* of a VxLAN bridge.
if (memcmp(n->emac.octet, macaddr->octet,
ETH_ALEN)
== 0) {
- if (n->ifindex == ifp->ifindex)
- /* we're not interested in whatever has
- * changed. */
- return 0;
- /* client doesn't care about a purely local
- * change. */
- send_upd = 0;
- } else
- /* If the MAC has changed, issue a delete first
- * as this means a
- * different MACIP route.
+ /* Update any params and return - client doesn't
+ * care about a purely local change.
*/
- send_del = 1;
+ n->ifindex = ifp->ifindex;
+ return 0;
+ }
+
+ /* If the MAC has changed,
+ * need to issue a delete first
+ * as this means a different MACIP route.
+ * Also, need to do some unlinking/relinking.
+ */
+ zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip,
+ &n->emac, 0);
+ old_zmac = zvni_mac_lookup(zvni, &n->emac);
+ if (old_zmac) {
+ listnode_delete(old_zmac->neigh_list, n);
+ zvni_deref_ip2mac(zvni, old_zmac, 0);
+ }
+
+ /* Set "local" forwarding info. */
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ n->ifindex = ifp->ifindex;
+ memcpy(&n->emac, macaddr, ETH_ALEN);
+
+ /* Link to new MAC */
+ listnode_add_sort(zmac->neigh_list, n);
} else if (ext_learned)
/* The neighbor is remote and that is the notification we got.
*/
{
UNSET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
n->r_vtep_ip.s_addr = 0;
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ n->ifindex = ifp->ifindex;
}
} else {
n = zvni_neigh_add(zvni, ip, macaddr);
ifp->name, ifp->ifindex, zvni->vni);
return -1;
}
+ /* Set "local" forwarding info. */
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ n->ifindex = ifp->ifindex;
}
- /* Issue delete for older info, if needed. */
- if (send_del)
- zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac,
- 0);
-
- /* Set "local" forwarding info. */
- SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
- n->ifindex = ifp->ifindex;
-
/* Before we program this in BGP, we need to check if MAC is locally
* learnt as well */
if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) {
return 0;
}
- /* Inform BGP if required. */
- if (send_upd) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "%u: neigh %s (MAC %s) is now ACTIVE on VNI %u",
- ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)),
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- zvni->vni);
-
- ZEBRA_NEIGH_SET_ACTIVE(n);
- return zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip,
- macaddr, 0);
- }
+ /* Inform BGP. */
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("%u: neigh %s (MAC %s) is now ACTIVE on VNI %u",
+ ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)),
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ zvni->vni);
- return 0;
+ ZEBRA_NEIGH_SET_ACTIVE(n);
+ return zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip, macaddr, 0);
}
+
/*
* Handle message from client to delete a remote MACIP for a VNI.
*/
u_short l = 0, ipa_len;
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
+ struct interface *ifp = NULL;
+ struct zebra_if *zif = NULL;
s = client->ibuf;
zvrf_id(zvrf), vni);
continue;
}
- if (!zvni->vxlan_if) {
+ ifp = zvni->vxlan_if;
+ if (!ifp) {
zlog_err(
"VNI %u hash %p doesn't have intf upon remote MACIP DEL",
vni, zvni);
continue;
}
+ zif = ifp->info;
+
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ continue;
/* The remote VTEP specified is normally expected to exist, but
* it is
if (!zvni_vtep_find(zvni, &vtep_ip))
continue;
- /* If the local VxLAN interface is not up (should be a transient
- * event), there's nothing more to do.
- */
- if (!if_is_operative(zvni->vxlan_if))
- continue;
-
mac = zvni_mac_lookup(zvni, &macaddr);
if (ipa_len)
n = zvni_neigh_lookup(zvni, &ip);
zvni_process_neigh_on_remote_mac_del(zvrf, zvni,
mac);
- if (!mac->neigh_refcnt) {
+ if (list_isempty(mac->neigh_list)) {
zvni_mac_uninstall(zvni, mac, 0);
zvni_mac_del(zvni, mac);
} else
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
u_char sticky;
+ struct interface *ifp = NULL;
+ struct zebra_if *zif = NULL;
assert(EVPN_ENABLED(zvrf));
zvrf_id(zvrf), vni);
continue;
}
- if (!zvni->vxlan_if) {
+ ifp = zvni->vxlan_if;
+ if (!ifp) {
zlog_err(
"VNI %u hash %p doesn't have intf upon remote MACIP add",
vni, zvni);
continue;
}
- /* If the local VxLAN interface is not up (should be a transient
- * event), there's nothing more to do.
- */
- if (!if_is_operative(zvni->vxlan_if))
+ zif = ifp->info;
+
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
continue;
/* The remote VTEP specified should normally exist, but it is
/* Is this MAC created for a MACIP? */
if (ipa_len)
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
- } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
- /* Moving from local to remote, issue delete. */
- zvni_mac_uninstall(zvni, mac, 1);
}
/* Set "auto" and "remote" forwarding info. */
return -1;
}
- /* New neighbor referring to this MAC. */
- mac->neigh_refcnt++;
} else if (memcmp(&n->emac, &macaddr, sizeof(macaddr))
!= 0) {
- /* MAC change, update ref counts for old and new
- * MAC. */
+ /* MAC change, update neigh list for old and new
+ * mac */
old_mac = zvni_mac_lookup(zvni, &n->emac);
- if (old_mac)
+ if (old_mac) {
+ listnode_delete(old_mac->neigh_list, n);
zvni_deref_ip2mac(zvni, old_mac, 1);
- mac->neigh_refcnt++;
+ }
+ listnode_add_sort(mac->neigh_list, n);
memcpy(&n->emac, &macaddr, ETH_ALEN);
}
struct in_addr vtep_ip;
zebra_vni_t *zvni;
zebra_vtep_t *zvtep;
+ struct interface *ifp;
+ struct zebra_if *zif;
s = client->ibuf;
continue;
}
+ ifp = zvni->vxlan_if;
+ if (!ifp) {
+ zlog_err(
+ "VNI %u hash %p doesn't have intf upon remote VTEP DEL",
+ zvni->vni, zvni);
+ continue;
+ }
+ zif = ifp->info;
+
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ continue;
+
/* If the remote VTEP does not exist, there's nothing more to
* do.
* Otherwise, uninstall any remote MACs pointing to this VTEP
vni_t vni;
struct in_addr vtep_ip;
zebra_vni_t *zvni;
+ struct interface *ifp;
+ struct zebra_if *zif;
assert(EVPN_ENABLED(zvrf));
zvrf_id(zvrf), vni);
continue;
}
- if (!zvni->vxlan_if) {
+
+ ifp = zvni->vxlan_if;
+ if (!ifp) {
zlog_err(
"VNI %u hash %p doesn't have intf upon remote VTEP ADD",
zvni->vni, zvni);
continue;
}
+ zif = ifp->info;
- /* If the remote VTEP already exists, or the local VxLAN
- * interface is
- * not up (should be a transient event), there's nothing more
- * to do.
- * Otherwise, add and install the entry.
- */
- if (zvni_vtep_find(zvni, &vtep_ip))
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
continue;
- if (!if_is_operative(zvni->vxlan_if))
+ /* If the remote VTEP already exists,
+ there's nothing more to do. */
+ if (zvni_vtep_find(zvni, &vtep_ip))
continue;
if (zvni_vtep_add(zvni, &vtep_ip) == NULL) {
if (!ifp_zif)
return -1;
- svi_if = ifp_zif->link;
+ /*
+ * for a MACVLAN interface the link represents the svi_if
+ */
+ svi_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
+ ifp_zif->link_ifindex);
if (!svi_if) {
zlog_err("%u:MACVLAN %s(%u) without link information",
ifp->vrf_id, ifp->name, ifp->ifindex);
}
if (IS_ZEBRA_IF_VLAN(svi_if)) {
+ /*
+ * If it is a vlan aware bridge then the link gives the
+ * bridge information
+ */
+ struct interface *svi_if_link = NULL;
+
svi_if_zif = svi_if->info;
- if (svi_if_zif)
- zvni = zvni_map_svi(svi_if, svi_if_zif->link);
+ if (svi_if_zif) {
+ svi_if_link = if_lookup_by_index_per_ns(
+ zebra_ns_lookup(NS_DEFAULT),
+ svi_if_zif->link_ifindex);
+ zvni = zvni_map_svi(svi_if, svi_if_link);
+ }
} else if (IS_ZEBRA_IF_BRIDGE(svi_if)) {
+ /*
+ * If it is a vlan unaware bridge then svi is the bridge
+ * itself
+ */
zvni = zvni_map_svi(svi_if, svi_if);
}
} else if (IS_ZEBRA_IF_VLAN(ifp)) {
struct zebra_if *svi_if_zif =
- NULL; /* Zebra daemon specific info for SVI*/
+ NULL; /* Zebra daemon specific info for SVI */
+ struct interface *svi_if_link =
+ NULL; /* link info for the SVI = bridge info */
svi_if_zif = ifp->info;
- if (svi_if_zif)
- zvni = zvni_map_svi(ifp, svi_if_zif->link);
+ svi_if_link = if_lookup_by_index_per_ns(
+ zebra_ns_lookup(NS_DEFAULT), svi_if_zif->link_ifindex);
+ if (svi_if_zif && svi_if_link)
+ zvni = zvni_map_svi(ifp, svi_if_link);
} else if (IS_ZEBRA_IF_BRIDGE(ifp)) {
zvni = zvni_map_svi(ifp, ifp);
}
vxl->access_vlan, inet_ntoa(vxl->vtep_ip),
zif->brslave_info.bridge_ifindex, chgflags);
- /* Removed from bridge? */
+ /* Removed from bridge? Cleanup and return */
if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
&& (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
/* Delete from client, remove all remote VTEPs */
zvni_neigh_del_all(zvrf, zvni, 1, 0, DEL_ALL_NEIGH);
zvni_mac_del_all(zvrf, zvni, 1, 0, DEL_ALL_MAC);
zvni_vtep_del_all(zvni, 1);
- } else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
+ return 0;
+ }
+
+ /* Handle other changes. */
+ if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
/* Remove all existing local neighbors and MACs for this VNI
* (including from BGP)
*/
int advertise;
vni_t vni = 0;
zebra_vni_t *zvni = NULL;
+ struct interface *ifp = NULL;
s = client->ibuf;
advertise = stream_getc(s);
zvni->advertise_gw_macip = advertise;
- zif = zvni->vxlan_if->info;
+ ifp = zvni->vxlan_if;
+ if (!ifp)
+ return 0;
+
+ zif = ifp->info;
+
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ return 0;
+
zl2_info = zif->l2info.vxl;
vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan,
struct in_addr r_vtep_ip;
} fwd_info;
- u_int32_t neigh_refcnt;
-
/* List of neigh associated with this mac */
struct list *neigh_list;
};
api_nh->type = nexthop->type;
switch (nexthop->type) {
case NEXTHOP_TYPE_BLACKHOLE:
+ api_nh->bh_type = nexthop->bh_type;
break;
case NEXTHOP_TYPE_IPV4:
api_nh->gate.ipv4 = nexthop->gate.ipv4;
api_nh->ifindex);
break;
case NEXTHOP_TYPE_BLACKHOLE:
- route_entry_nexthop_blackhole_add(re);
+ route_entry_nexthop_blackhole_add(
+ re, api_nh->bh_type);
break;
}
src_p = &api.src_prefix;
rib_delete(afi, api.safi, zvrf_id(zvrf), api.type, api.instance,
- api.flags, &api.prefix, src_p, NULL, 0, zvrf->table_id,
+ api.flags, &api.prefix, src_p, NULL, zvrf->table_id,
api.metric);
/* Stats */
enum lsp_types_t label_type = ZEBRA_LSP_NONE;
mpls_label_t label;
struct nexthop *nexthop;
+ enum blackhole_type bh_type = BLACKHOLE_NULL;
/* Get input stream. */
s = client->ibuf;
stream_forward_getp(s, IPV6_MAX_BYTELEN);
break;
case NEXTHOP_TYPE_BLACKHOLE:
- route_entry_nexthop_blackhole_add(re);
+ route_entry_nexthop_blackhole_add(re, bh_type);
break;
}
}
table_id = zvrf->table_id;
rib_delete(AFI_IP, api.safi, zvrf_id(zvrf), api.type, api.instance,
- api.flags, &p, NULL, NULL, 0, table_id, 0);
+ api.flags, &p, NULL, NULL, table_id, 0);
client->v4_route_del_cnt++;
return 0;
}
enum lsp_types_t label_type = ZEBRA_LSP_NONE;
mpls_label_t label;
struct nexthop *nexthop;
+ enum blackhole_type bh_type = BLACKHOLE_NULL;
/* Get input stream. */
s = client->ibuf;
}
break;
case NEXTHOP_TYPE_BLACKHOLE:
- route_entry_nexthop_blackhole_add(re);
+ route_entry_nexthop_blackhole_add(re, bh_type);
break;
}
}
enum lsp_types_t label_type = ZEBRA_LSP_NONE;
mpls_label_t label;
struct nexthop *nexthop;
+ enum blackhole_type bh_type = BLACKHOLE_NULL;
/* Get input stream. */
s = client->ibuf;
}
break;
case NEXTHOP_TYPE_BLACKHOLE:
- route_entry_nexthop_blackhole_add(re);
+ route_entry_nexthop_blackhole_add(re, bh_type);
break;
}
}
api.safi = stream_getw(s);
/* IPv4 prefix. */
- memset(&p, 0, sizeof(struct prefix_ipv6));
+ memset(&p, 0, sizeof(struct prefix));
p.family = AF_INET6;
p.prefixlen = stream_getc(s);
stream_get(&p.u.prefix6, s, PSIZE(p.prefixlen));
src_pp = NULL;
rib_delete(AFI_IP6, api.safi, zvrf_id(zvrf), api.type, api.instance,
- api.flags, &p, src_pp, NULL, 0, client->rtm_table, 0);
+ api.flags, &p, src_pp, NULL, client->rtm_table, 0);
client->v6_route_del_cnt++;
return 0;