break;
if(k > 0)
channels[j++] = ',';
- snprintf(channels + j, 100 - j, "%d", route->channels[k]);
+ snprintf(channels + j, 100 - j, "%u", route->channels[k]);
j = strlen(channels);
}
snprintf(channels + j, 100 - j, ")");
check_bucket(struct interface *ifp)
{
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
- if(babel_ifp->bucket <= 0) {
+ if(babel_ifp->bucket == 0) {
int seconds = babel_now.tv_sec - babel_ifp->bucket_time;
if(seconds > 0) {
babel_ifp->bucket = MIN(BUCKET_TOKENS_MAX,
int rc = 0;
if(hello < 0) {
- if(neigh->hello_interval <= 0)
+ if(neigh->hello_interval == 0)
return rc;
missed_hellos =
((int)timeval_minus_msec(&babel_now, &neigh->hello_time) -
static char buf[4][15];
static int i = 0;
i = (i + 1) % 4;
- snprintf(buf[i], 15, "%d.%.3d", value / 1000, value % 1000);
+ snprintf(buf[i], 15, "%u.%.3u", value / 1000, value % 1000);
return buf[i];
}
struct aspath *newpath = NULL, *mergedpath;
int hops, cpasns = 0;
- if (!aspath)
+ if (!aspath || !as4path)
return NULL;
seg = aspath->segments;
if (!ignore_as4_path
&& (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))) {
newpath = aspath_reconcile_as4(attr->aspath, as4_path);
+ if (!newpath)
+ return BGP_ATTR_PARSE_ERROR;
+
aspath_unintern(&attr->aspath);
attr->aspath = aspath_intern(newpath);
}
int main(int argc, char **argv)
{
int ret;
- FILE *fp;
+ int fd;
struct stream *s;
time_t now;
int type;
fprintf(stderr, "Usage: %s FILENAME\n", argv[0]);
exit(1);
}
- fp = fopen(argv[1], "r");
- if (!fp) {
+ fd = open(argv[1], O_RDONLY);
+ if (fd < 0) {
fprintf(stdout,
"%% Can't open configuration file %s due to '%s'.\n",
argv[1], safe_strerror(errno));
while (1) {
stream_reset(s);
- ret = fread(s->data, 12, 1, fp);
- if (!ret || feof(fp)) {
- printf("END OF FILE\n");
- break;
- }
- if (ferror(fp)) {
- printf("ERROR OF FREAD\n");
+ ret = stream_read(s, fd, 12);
+ if (ret != 12) {
+ if (!ret)
+ printf("END OF FILE\n");
+ else if (ret < 0)
+ printf("ERROR OF READ\n");
+ else
+ printf("UNDERFLOW\n");
break;
}
printf("len: %zd\n", len);
- fread(s->data + 12, len, 1, fp);
- if (feof(fp)) {
- printf("ENDOF FILE 2\n");
- break;
- }
- if (ferror(fp)) {
- printf("ERROR OF FREAD 2\n");
+ ret = stream_read(s, fd, len);
+ if (ret != (int)len) {
+ if (!ret)
+ printf("END OF FILE 2\n");
+ else if (ret < 0)
+ printf("ERROR OF READ 2\n");
+ else
+ printf("UNDERFLOW 2\n");
break;
}
printf("\n");
}
}
- fclose(fp);
+ close(fd);
return 0;
}
struct ecommunity *ecom = NULL;
regex_t *regex = NULL;
+ if (str == NULL)
+ return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+
entry = NULL;
/* Get community list. */
entry = community_entry_new();
entry->direct = direct;
entry->style = style;
- entry->any = (str ? 0 : 1);
+ entry->any = 0;
if (ecom)
entry->config = ecommunity_ecom2str(
ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0);
if (node_to_del)
list_delete_node(bgp_vrf->vrf_import_rtl, node_to_del);
+ assert(bgp_vrf->vrf_import_rtl);
/* fallback to auto import rt, if this was the last RT */
- if (list_isempty(bgp_vrf->vrf_import_rtl)) {
+ if (bgp_vrf->vrf_import_rtl && list_isempty(bgp_vrf->vrf_import_rtl)) {
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
evpn_auto_rt_import_add_for_vrf(bgp_vrf);
}
json_object *json;
};
-#if defined(HAVE_CUMULUS)
static void display_vrf_import_rt(struct vty *vty, struct vrf_irt_node *irt,
json_object *json)
{
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));
+ json_vnis, json_object_new_int(tmp_vpn->vni));
else
vty_out(vty, " %u\n", tmp_vpn->vni);
}
vty_out(vty, "\n");
}
}
-#endif /* HAVE_CUMULUS */
static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
enum bgp_show_type type, void *output_arg,
argv[idx_gwip]->arg, argv[idx_ethtag]->arg);
}
-#if defined(HAVE_CUMULUS)
-
static void evpn_import_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)
{
evpn_rt_delete_auto(bgp, vpn->vni, vpn->import_rtl);
list_delete_node(vpn->import_rtl, node_to_del);
}
+ assert(vpn->import_rtl);
/* Reset to auto RT - this also rebuilds the RT to VNI mapping */
if (list_isempty(vpn->import_rtl)) {
UNSET_FLAG(vpn->flags, VNI_FLAG_IMPRT_CFGD);
list_delete_node(vpn->export_rtl, node_to_del);
}
+ assert(vpn->export_rtl);
if (list_isempty(vpn->export_rtl)) {
UNSET_FLAG(vpn->flags, VNI_FLAG_EXPRT_CFGD);
bgp_evpn_derive_auto_rt_export(bgp, vpn);
/* fall back to default RD */
bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf);
+ UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD);
/* We have a new RD for VRF.
* Advertise all type-5 routes again with the new RD
bgp->advertise_autort_rfc8365 = 0;
bgp_evpn_handle_autort_change(bgp);
}
-#endif /* HAVE_CUMULUS */
static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
{
}
}
-#if defined(HAVE_CUMULUS)
DEFUN (bgp_evpn_advertise_default_gw_vni,
bgp_evpn_advertise_default_gw_vni_cmd,
"advertise-default-gw",
{
int idx = 0;
uint8_t uj = 0;
- esi_t esi = {0};
+ esi_t esi;
json_object *json = NULL;
struct bgp *bgp = NULL;
+ memset(&esi, 0, sizeof(esi));
uj = use_json(argc, argv);
bgp = bgp_get_default();
JSON_STR)
{
int uj = 0;
- esi_t esi = {0};
+ esi_t esi;
struct bgp *bgp = NULL;
json_object *json = NULL;
+ memset(&esi, 0, sizeof(esi));
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
return CMD_SUCCESS;
}
-#if defined(HAVE_CUMULUS)
DEFUN(test_adv_evpn_type4_route,
test_adv_evpn_type4_route_cmd,
"advertise es ESI",
ALIAS_HIDDEN(show_bgp_l2vpn_evpn_import_rt, show_bgp_evpn_import_rt_cmd,
"show bgp evpn import-rt",
SHOW_STR BGP_STR EVPN_HELP_STR "Show import route target\n")
-#endif
DEFUN_NOSH (bgp_evpn_vni,
bgp_evpn_vni_cmd,
evpn_unconfigure_export_rt(bgp, vpn, NULL);
return CMD_SUCCESS;
}
-#endif
static int vni_cmp(const void **a, const void **b)
{
install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd);
install_element(BGP_EVPN_NODE, &no_evpnrt5_network_cmd);
install_element(BGP_EVPN_NODE, &evpnrt5_network_cmd);
-#if defined(HAVE_CUMULUS)
install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_all_vni_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_all_vni_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_autort_rfc8365_cmd);
install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_advertise_vni_subnet_cmd);
install_element(BGP_EVPN_VNI_NODE,
&no_bgp_evpn_advertise_vni_subnet_cmd);
-#endif
}
len - offset, NULL, &error);
break;
case FLOWSPEC_TCP_FLAGS:
- ret = bgp_flowspec_tcpflags_decode(
+ case FLOWSPEC_FRAGMENT:
+ ret = bgp_flowspec_bitmask_decode(
BGP_FLOWSPEC_VALIDATE_ONLY,
nlri_content + offset,
len - offset, NULL, &error);
nlri_content + offset,
len - offset, NULL, &error);
break;
- case FLOWSPEC_FRAGMENT:
- ret = bgp_flowspec_fragment_type_decode(
- BGP_FLOWSPEC_VALIDATE_ONLY,
- nlri_content + offset,
- len - offset, NULL, &error);
- break;
default:
error = -1;
break;
len - offset,
NULL, &error);
break;
+ case FLOWSPEC_FRAGMENT:
case FLOWSPEC_TCP_FLAGS:
- ret = bgp_flowspec_tcpflags_decode(
+ ret = bgp_flowspec_bitmask_decode(
BGP_FLOWSPEC_VALIDATE_ONLY,
nlri_content+offset,
len - offset,
len - offset, NULL,
&error);
break;
- case FLOWSPEC_FRAGMENT:
- ret = bgp_flowspec_fragment_type_decode(
- BGP_FLOWSPEC_VALIDATE_ONLY,
- nlri_content + offset,
- len - offset, NULL,
- &error);
- break;
default:
error = -1;
break;
/*
- * handle the flowspec tcpflags field
+ * handle the flowspec tcpflags or fragment field
* return number of bytes analysed
* if there is an error, the passed error param is used to give error:
* -1 if decoding error,
* if result is a string, its assumed length
* is BGP_FLOWSPEC_STRING_DISPLAY_MAX
*/
-int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
+int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type,
uint8_t *nlri_ptr,
uint32_t max_len,
void *result, int *error)
case BGP_FLOWSPEC_RETURN_STRING:
if (op[1] == 1 && loop != 0) {
len_written = snprintf(ptr, len_string,
- ", and ");
+ ",&");
len_string -= len_written;
ptr += len_written;
} else if (op[1] == 0 && loop != 0) {
len_written = snprintf(ptr, len_string,
- ", or ");
+ ",|");
len_string -= len_written;
ptr += len_written;
}
- len_written = snprintf(ptr, len_string,
- "tcp flags is ");
- len_string -= len_written;
- ptr += len_written;
- if (op[6] == 1) {
- ptr += snprintf(ptr, len_string,
- "not ");
+ if (op[7] == 1) {
+ len_written = snprintf(ptr, len_string,
+ "= ");
+ len_string -= len_written;
+ ptr += len_written;
+ } else {
+ len_written = snprintf(ptr, len_string,
+ "∋ ");
len_string -= len_written;
ptr += len_written;
}
- if (op[7] == 1) {
- ptr += snprintf(ptr, len_string,
- "exactly match ");
+ if (op[6] == 1) {
+ len_written = snprintf(ptr, len_string,
+ "! ");
len_string -= len_written;
ptr += len_written;
}
- ptr += snprintf(ptr, len_string,
+ len_written = snprintf(ptr, len_string,
"%d", value);
len_string -= len_written;
ptr += len_written;
return offset;
}
-/*
- * handle the flowspec fragment type field
- * return error (returned values are invalid) or number of bytes analysed
- * -1 if error in decoding
- * >= 0 : number of bytes analysed (ok).
- */
-int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type,
- uint8_t *nlri_ptr,
- uint32_t max_len,
- void *result, int *error)
-{
- int op[8];
- int len, value, value_size, loop = 0;
- char *ptr = (char *)result; /* for return_string */
- struct bgp_pbr_fragment_val *mval =
- (struct bgp_pbr_fragment_val *)result;
- uint32_t offset = 0;
- int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
- int len_written;
-
- *error = 0;
- do {
- hex2bin(&nlri_ptr[offset], op);
- offset++;
- len = 2 * op[2] + op[3];
- value_size = 1 << len;
- value = hexstr2num(&nlri_ptr[offset], value_size);
- if (value != 1 && value != 2 && value != 4 && value != 8)
- *error = -1;
- offset += value_size;
- /* TODO : as per RFC5574 : first Fragment bits are Reserved
- * does that mean that it is not possible
- * to handle multiple occurences ?
- * as of today, we only grab the first TCP fragment
- */
- if (loop) {
- *error = -2;
- loop++;
- continue;
- }
- switch (type) {
- case BGP_FLOWSPEC_RETURN_STRING:
- switch (value) {
- case 1:
- len_written = snprintf(ptr, len_string,
- "dont-fragment");
- len_string -= len_written;
- ptr += len_written;
- break;
- case 2:
- len_written = snprintf(ptr, len_string,
- "is-fragment");
- len_string -= len_written;
- ptr += len_written;
- break;
- case 4:
- len_written = snprintf(ptr, len_string,
- "first-fragment");
- len_string -= len_written;
- ptr += len_written;
- break;
- case 8:
- len_written = snprintf(ptr, len_string,
- "last-fragment");
- len_string -= len_written;
- ptr += len_written;
- break;
- default:
- {}
- }
- break;
- case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
- mval->bitmask = (uint8_t)value;
- break;
- case BGP_FLOWSPEC_VALIDATE_ONLY:
- default:
- /* no action */
- break;
- }
- loop++;
- } while (op[0] == 0 && offset < max_len - 1);
- if (offset > max_len)
- *error = -1;
- return offset;
-}
-
int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
struct bgp_pbr_entry_main *bpem)
{
&error);
break;
case FLOWSPEC_TCP_FLAGS:
- ret = bgp_flowspec_tcpflags_decode(
+ ret = bgp_flowspec_bitmask_decode(
BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
nlri_content + offset,
len - offset,
offset += ret;
break;
case FLOWSPEC_FRAGMENT:
- ret = bgp_flowspec_fragment_type_decode(
+ ret = bgp_flowspec_bitmask_decode(
BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
nlri_content + offset,
len - offset, &bpem->fragment,
zlog_err("%s: flowspec_fragment_type_decode error %d",
__func__, error);
else
- bpem->match_bitmask |= FRAGMENT_PRESENT;
+ bpem->match_fragment_num = error;
offset += ret;
break;
default:
uint32_t max_len,
void *result, int *error);
-extern int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
+extern int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type,
uint8_t *nlri_ptr,
uint32_t max_len,
void *result, int *error);
-extern int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type,
- uint8_t *nlri_ptr,
- uint32_t max_len,
- void *result, int *error);
struct bgp_pbr_entry_main;
extern int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
struct bgp_pbr_entry_main *bpem);
{FLOWSPEC_SRC_PORT, "srcp"},
{FLOWSPEC_ICMP_TYPE, "type"},
{FLOWSPEC_ICMP_CODE, "code"},
- {FLOWSPEC_TCP_FLAGS, "flags"},
+ {FLOWSPEC_TCP_FLAGS, "tcp"},
{FLOWSPEC_PKT_LEN, "pktlen"},
{FLOWSPEC_DSCP, "dscp"},
{FLOWSPEC_FRAGMENT, "pktfrag"},
ptr += len_written;
break;
case FLOWSPEC_TCP_FLAGS:
- ret = bgp_flowspec_tcpflags_decode(
+ ret = bgp_flowspec_bitmask_decode(
type_util,
nlri_content+offset,
len - offset,
ptr += len_written;
break;
case FLOWSPEC_FRAGMENT:
- ret = bgp_flowspec_fragment_type_decode(
- type_util,
- nlri_content + offset,
- len - offset, local_string,
- &error);
+ ret = bgp_flowspec_bitmask_decode(
+ type_util,
+ nlri_content+offset,
+ len - offset,
+ local_string, &error);
if (ret <= 0)
break;
if (json_path) {
peer->as = from_peer->as;
peer->v_holdtime = from_peer->v_holdtime;
peer->v_keepalive = from_peer->v_keepalive;
- peer->routeadv = from_peer->routeadv;
peer->v_routeadv = from_peer->v_routeadv;
peer->v_gr_restart = from_peer->v_gr_restart;
peer->cap = from_peer->cap;
}
/* Reset keepalive and holdtime */
- if (PEER_OR_GROUP_TIMER_SET(peer)) {
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) {
peer->v_keepalive = peer->keepalive;
peer->v_holdtime = peer->holdtime;
} else {
bool more = true; // whether we got more data
bool fatal = false; // whether fatal error occurred
bool added_pkt = false; // whether we pushed onto ->ibuf
- bool header_valid = true; // whether header is valid
/* clang-format on */
peer = THREAD_ARG(thread);
if (ringbuf_remain(ibw) < BGP_HEADER_SIZE)
break;
- /* validate header */
- header_valid = validate_header(peer);
-
- if (!header_valid) {
+ /* check that header is valid */
+ if (!validate_header(peer)) {
fatal = true;
break;
}
zlog_debug(
"%s: starting mpath update, newbest %s num candidates %d old-mpath-count %d",
pfx_buf, new_best ? new_best->peer->host : "NONE",
- listcount(mp_list), old_mpath_count);
+ mp_list ? listcount(mp_list) : 0, old_mpath_count);
/*
* We perform an ordered walk through both lists in parallel.
{
struct prefix *p = &bn->p;
struct bgp_info *bi;
+ struct bgp_info *bi_ultimate;
struct bgp_info *new;
char buf_prefix[PREFIX_STRLEN];
source_bi->type, source_bi->sub_type);
}
+ /*
+ * Routes that are redistributed into BGP from zebra do not get
+ * nexthop tracking. However, if those routes are subsequently
+ * imported to other RIBs within BGP, the leaked routes do not
+ * carry the original BGP_ROUTE_REDISTRIBUTE sub_type. Therefore,
+ * in order to determine if the route we are currently leaking
+ * should have nexthop tracking, we must find the ultimate
+ * parent so we can check its sub_type.
+ *
+ * As of now, source_bi may at most be a second-generation route
+ * (only one hop back to ultimate parent for vrf-vpn-vrf scheme).
+ * Using a loop here supports more complex intra-bgp import-export
+ * schemes that could be implemented in the future.
+ *
+ */
+ for (bi_ultimate = source_bi;
+ bi_ultimate->extra && bi_ultimate->extra->parent;
+ bi_ultimate = bi_ultimate->extra->parent)
+ ;
+
/*
* match parent
*/
bgp_nexthop = bi->extra->bgp_orig;
/* No nexthop tracking for redistributed routes */
- if (source_bi->sub_type == BGP_ROUTE_REDISTRIBUTE)
+ if (bi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)
nh_valid = 1;
else
/*
* their originating protocols will do the tracking and
* withdraw those routes if the nexthops become unreachable
*/
- if (source_bi->sub_type == BGP_ROUTE_REDISTRIBUTE)
+ if (bi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)
nh_valid = 1;
else
/*
struct bgp_node *prn;
safi_t safi = SAFI_MPLS_VPN;
+ if (!bgp_vpn)
+ return;
+
/*
* Walk vpn table
*/
struct bgp_node *rn1, *rn2;
struct peer_af *paf;
struct prefix p, np;
- struct bgp *bgp = NULL;
+ struct bgp *bgp;
np.family = AF_INET;
np.prefixlen = IPV4_MAX_BITLEN;
p.family = AF_INET;
p.prefixlen = IPV4_MAX_BITLEN;
- rn1 = rn2 = NULL;
+ rn2 = NULL;
bgp = SUBGRP_INST(subgrp);
rn1 = bgp_node_match(bgp->connected_table[AFI_IP], &np);
afi_t afi;
safi_t safi;
- bgp_map_afi_safi_iana2int(ntohs(mpc.afi), mpc.safi,
- &afi, &safi);
+ (void)bgp_map_afi_safi_iana2int(ntohs(mpc.afi),
+ mpc.safi, &afi, &safi);
+
if (use_json) {
switch (afi) {
case AFI_IP:
uint16_t send_holdtime;
as_t local_as;
- if (PEER_OR_GROUP_TIMER_SET(peer))
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
send_holdtime = peer->holdtime;
else
send_holdtime = peer->bgp->default_holdtime;
implementation MAY adjust the rate at which it sends KEEPALIVE
messages as a function of the Hold Time interval. */
- if (PEER_OR_GROUP_TIMER_SET(peer))
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
send_holdtime = peer->holdtime;
else
send_holdtime = peer->bgp->default_holdtime;
else
peer->v_holdtime = send_holdtime;
- if ((PEER_OR_GROUP_TIMER_SET(peer))
+ if ((CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
&& (peer->keepalive < peer->v_holdtime / 3))
peer->v_keepalive = peer->keepalive;
else
#include "prefix.h"
#include "zclient.h"
#include "jhash.h"
+#include "pbr.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_pbr.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_flowspec_private.h"
DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry")
DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match")
DEFINE_MTYPE_STATIC(BGPD, PBR_ACTION, "PBR action")
DEFINE_MTYPE_STATIC(BGPD, PBR, "BGP PBR Context")
+DEFINE_MTYPE_STATIC(BGPD, PBR_VALMASK, "BGP PBR Val Mask Value")
RB_GENERATE(bgp_pbr_interface_head, bgp_pbr_interface,
id_entry, bgp_pbr_interface_compare);
_cnt++; \
} while (0)
+/* this structure can be used for port range,
+ * but also for other values range like packet length range
+ */
struct bgp_pbr_range_port {
uint16_t min_port;
uint16_t max_port;
};
+/* this structure can be used to filter with a mask
+ * for instance it supports not instructions like for
+ * tcpflags
+ */
+struct bgp_pbr_val_mask {
+ uint16_t val;
+ uint16_t mask;
+};
+
+/* this structure is used to pass instructs
+ * so that BGP can create pbr instructions to ZEBRA
+ */
+struct bgp_pbr_filter {
+ vrf_id_t vrf_id;
+ struct prefix *src;
+ struct prefix *dst;
+ uint8_t protocol;
+ struct bgp_pbr_range_port *pkt_len;
+ struct bgp_pbr_range_port *src_port;
+ struct bgp_pbr_range_port *dst_port;
+ struct bgp_pbr_val_mask *tcp_flags;
+ struct bgp_pbr_val_mask *dscp;
+ struct bgp_pbr_val_mask *pkt_len_val;
+ struct bgp_pbr_val_mask *fragment;
+};
+
+/* this structure is used to contain OR instructions
+ * so that BGP can create multiple pbr instructions
+ * to ZEBRA
+ */
+struct bgp_pbr_or_filter {
+ struct list *tcpflags;
+ struct list *dscp;
+ struct list *pkt_len;
+ struct list *fragment;
+ struct list *icmp_type;
+ struct list *icmp_code;
+};
+
+static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
+ struct bgp_info *binfo,
+ struct bgp_pbr_filter *bpf,
+ struct nexthop *nh,
+ float *rate);
+
+static bool bgp_pbr_extract_enumerate_unary_opposite(
+ uint8_t unary_operator,
+ struct bgp_pbr_val_mask *and_valmask,
+ struct list *or_valmask, uint32_t value,
+ uint8_t type_entry)
+{
+ if (unary_operator == OPERATOR_UNARY_AND && and_valmask) {
+ if (type_entry == FLOWSPEC_TCP_FLAGS) {
+ and_valmask->mask |=
+ TCP_HEADER_ALL_FLAGS &
+ ~(value);
+ } else if (type_entry == FLOWSPEC_DSCP ||
+ type_entry == FLOWSPEC_PKT_LEN ||
+ type_entry == FLOWSPEC_FRAGMENT) {
+ and_valmask->val = value;
+ and_valmask->mask = 1; /* inverse */
+ }
+ } else if (unary_operator == OPERATOR_UNARY_OR && or_valmask) {
+ and_valmask = XCALLOC(MTYPE_PBR_VALMASK,
+ sizeof(struct bgp_pbr_val_mask));
+ if (type_entry == FLOWSPEC_TCP_FLAGS) {
+ and_valmask->val = TCP_HEADER_ALL_FLAGS;
+ and_valmask->mask |=
+ TCP_HEADER_ALL_FLAGS &
+ ~(value);
+ } else if (type_entry == FLOWSPEC_DSCP ||
+ type_entry == FLOWSPEC_FRAGMENT ||
+ type_entry == FLOWSPEC_PKT_LEN) {
+ and_valmask->val = value;
+ and_valmask->mask = 1; /* inverse */
+ }
+ listnode_add(or_valmask, and_valmask);
+ } else if (type_entry == FLOWSPEC_ICMP_CODE ||
+ type_entry == FLOWSPEC_ICMP_TYPE)
+ return false;
+ return true;
+}
+
+/* TCP : FIN and SYN -> val = ALL; mask = 3
+ * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
+ * other variables type: dscp, pkt len, fragment
+ * - value is copied in bgp_pbr_val_mask->val value
+ * - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1
+ */
+static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[],
+ int num, uint8_t unary_operator,
+ void *valmask, uint8_t type_entry)
+{
+ int i = 0;
+ struct bgp_pbr_val_mask *and_valmask = NULL;
+ struct list *or_valmask = NULL;
+ bool ret;
+
+ if (valmask) {
+ if (unary_operator == OPERATOR_UNARY_AND) {
+ and_valmask = (struct bgp_pbr_val_mask *)valmask;
+ memset(and_valmask, 0, sizeof(struct bgp_pbr_val_mask));
+ } else if (unary_operator == OPERATOR_UNARY_OR) {
+ or_valmask = (struct list *)valmask;
+ }
+ }
+ for (i = 0; i < num; i++) {
+ if (i != 0 && list[i].unary_operator !=
+ unary_operator)
+ return false;
+ if (!(list[i].compare_operator &
+ OPERATOR_COMPARE_EQUAL_TO) &&
+ !(list[i].compare_operator &
+ OPERATOR_COMPARE_EXACT_MATCH)) {
+ if ((list[i].compare_operator &
+ OPERATOR_COMPARE_LESS_THAN) &&
+ (list[i].compare_operator &
+ OPERATOR_COMPARE_GREATER_THAN)) {
+ ret = bgp_pbr_extract_enumerate_unary_opposite(
+ unary_operator, and_valmask,
+ or_valmask, list[i].value,
+ type_entry);
+ if (ret == false)
+ return ret;
+ continue;
+ }
+ return false;
+ }
+ if (unary_operator == OPERATOR_UNARY_AND && and_valmask) {
+ if (type_entry == FLOWSPEC_TCP_FLAGS)
+ and_valmask->mask |=
+ TCP_HEADER_ALL_FLAGS & list[i].value;
+ } else if (unary_operator == OPERATOR_UNARY_OR && or_valmask) {
+ and_valmask = XCALLOC(MTYPE_PBR_VALMASK,
+ sizeof(struct bgp_pbr_val_mask));
+ if (type_entry == FLOWSPEC_TCP_FLAGS) {
+ and_valmask->val = TCP_HEADER_ALL_FLAGS;
+ and_valmask->mask |=
+ TCP_HEADER_ALL_FLAGS & list[i].value;
+ } else if (type_entry == FLOWSPEC_DSCP ||
+ type_entry == FLOWSPEC_ICMP_TYPE ||
+ type_entry == FLOWSPEC_ICMP_CODE ||
+ type_entry == FLOWSPEC_FRAGMENT ||
+ type_entry == FLOWSPEC_PKT_LEN)
+ and_valmask->val = list[i].value;
+ listnode_add(or_valmask, and_valmask);
+ }
+ }
+ if (unary_operator == OPERATOR_UNARY_AND && and_valmask
+ && type_entry == FLOWSPEC_TCP_FLAGS)
+ and_valmask->val = TCP_HEADER_ALL_FLAGS;
+ return true;
+}
+
+/* if unary operator can either be UNARY_OR/AND/OR-AND.
+ * in the latter case, combinationf of both is not handled
+ */
+static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list[],
+ int num, uint8_t unary_operator,
+ void *valmask, uint8_t type_entry)
+{
+ bool ret;
+ uint8_t unary_operator_val = unary_operator;
+ bool double_check = false;
+
+ if ((unary_operator & OPERATOR_UNARY_OR) &&
+ (unary_operator & OPERATOR_UNARY_AND)) {
+ unary_operator_val = OPERATOR_UNARY_AND;
+ double_check = true;
+ } else
+ unary_operator_val = unary_operator;
+ ret = bgp_pbr_extract_enumerate_unary(list, num, unary_operator_val,
+ valmask, type_entry);
+ if (!ret && double_check)
+ ret = bgp_pbr_extract_enumerate_unary(list, num,
+ OPERATOR_UNARY_OR,
+ valmask,
+ type_entry);
+ return ret;
+}
+
+/* returns the unary operator that is in the list
+ * return 0 if both operators are used
+ */
+static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list[],
+ int num)
+
+{
+ int i;
+ uint8_t unary_operator = OPERATOR_UNARY_AND;
+
+ for (i = 0; i < num; i++) {
+ if (i == 0)
+ continue;
+ if (list[i].unary_operator & OPERATOR_UNARY_OR)
+ unary_operator = OPERATOR_UNARY_OR;
+ if ((list[i].unary_operator & OPERATOR_UNARY_AND
+ && unary_operator == OPERATOR_UNARY_OR) ||
+ (list[i].unary_operator & OPERATOR_UNARY_OR
+ && unary_operator == OPERATOR_UNARY_AND))
+ return 0;
+ }
+ return unary_operator;
+}
+
+
/* return true if extraction ok
*/
static bool bgp_pbr_extract(struct bgp_pbr_match_val list[],
static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
{
+ bool enumerate_icmp = false;
+
/* because bgp pbr entry may contain unsupported
* combinations, a message will be displayed here if
* not supported.
* - combination src/dst => drop
* - combination srcport + @IP
*/
- if (api->match_icmp_type_num || api->match_packet_length_num
- || api->match_dscp_num || api->match_tcpflags_num) {
- if (BGP_DEBUG(pbr, PBR)) {
- bgp_pbr_print_policy_route(api);
- zlog_debug("BGP: some SET actions not supported by Zebra. ignoring.");
- zlog_debug("BGP: case icmp or length or dscp or tcp flags");
- }
- return 0;
- }
-
if (api->match_protocol_num > 1) {
if (BGP_DEBUG(pbr, PBR))
zlog_debug("BGP: match protocol operations:"
}
if (api->match_protocol_num == 1 &&
api->protocol[0].value != PROTOCOL_UDP &&
+ api->protocol[0].value != PROTOCOL_ICMP &&
api->protocol[0].value != PROTOCOL_TCP) {
if (BGP_DEBUG(pbr, PBR))
zlog_debug("BGP: match protocol operations:"
"too complex. ignoring.");
return 0;
}
+ if (!bgp_pbr_extract_enumerate(api->tcpflags,
+ api->match_tcpflags_num,
+ OPERATOR_UNARY_AND |
+ OPERATOR_UNARY_OR, NULL,
+ FLOWSPEC_TCP_FLAGS)) {
+ if (BGP_DEBUG(pbr, PBR))
+ zlog_debug("BGP: match tcp flags:"
+ "too complex. ignoring.");
+ return 0;
+ }
+ if (!bgp_pbr_extract(api->icmp_type, api->match_icmp_type_num, NULL)) {
+ if (!bgp_pbr_extract_enumerate(api->icmp_type,
+ api->match_icmp_type_num,
+ OPERATOR_UNARY_OR, NULL,
+ FLOWSPEC_ICMP_TYPE)) {
+ if (BGP_DEBUG(pbr, PBR))
+ zlog_debug("BGP: match icmp type operations:"
+ "too complex. ignoring.");
+ return 0;
+ }
+ enumerate_icmp = true;
+ }
+ if (!bgp_pbr_extract(api->icmp_code, api->match_icmp_code_num, NULL)) {
+ if (!bgp_pbr_extract_enumerate(api->icmp_code,
+ api->match_icmp_code_num,
+ OPERATOR_UNARY_OR, NULL,
+ FLOWSPEC_ICMP_CODE)) {
+ if (BGP_DEBUG(pbr, PBR))
+ zlog_debug("BGP: match icmp code operations:"
+ "too complex. ignoring.");
+ return 0;
+ } else if (api->match_icmp_type_num > 1 &&
+ enumerate_icmp == false) {
+ if (BGP_DEBUG(pbr, PBR))
+ zlog_debug("BGP: match icmp code is enumerate"
+ ", and icmp type is not."
+ " too complex. ignoring.");
+ return 0;
+ }
+ }
if (!bgp_pbr_extract(api->port, api->match_port_num, NULL)) {
if (BGP_DEBUG(pbr, PBR))
zlog_debug("BGP: match port operations:"
"too complex. ignoring.");
return 0;
}
+ if (api->match_packet_length_num) {
+ bool ret;
+
+ ret = bgp_pbr_extract(api->packet_length,
+ api->match_packet_length_num, NULL);
+ if (!ret)
+ ret = bgp_pbr_extract_enumerate(api->packet_length,
+ api->match_packet_length_num,
+ OPERATOR_UNARY_OR
+ | OPERATOR_UNARY_AND,
+ NULL, FLOWSPEC_PKT_LEN);
+ if (!ret) {
+ if (BGP_DEBUG(pbr, PBR))
+ zlog_debug("BGP: match packet length operations:"
+ "too complex. ignoring.");
+ return 0;
+ }
+ }
+ if (api->match_dscp_num) {
+ if (!bgp_pbr_extract_enumerate(api->dscp, api->match_dscp_num,
+ OPERATOR_UNARY_OR | OPERATOR_UNARY_AND,
+ NULL, FLOWSPEC_DSCP)) {
+ if (BGP_DEBUG(pbr, PBR))
+ zlog_debug("BGP: match DSCP operations:"
+ "too complex. ignoring.");
+ return 0;
+ }
+ }
+ if (api->match_fragment_num) {
+ char fail_str[64];
+ bool success;
+
+ success = bgp_pbr_extract_enumerate(api->fragment,
+ api->match_fragment_num,
+ OPERATOR_UNARY_OR
+ | OPERATOR_UNARY_AND,
+ NULL, FLOWSPEC_FRAGMENT);
+ if (success) {
+ int i;
+
+ for (i = 0; i < api->match_fragment_num; i++) {
+ if (api->fragment[i].value != 1 &&
+ api->fragment[i].value != 2 &&
+ api->fragment[i].value != 4 &&
+ api->fragment[i].value != 8) {
+ success = false;
+ sprintf(fail_str,
+ "Value not valid (%d) for this implementation",
+ api->fragment[i].value);
+ }
+ }
+ } else
+ sprintf(fail_str, "too complex. ignoring");
+ if (!success) {
+ if (BGP_DEBUG(pbr, PBR))
+ zlog_debug("BGP: match fragment operation (%d) %s",
+ api->match_fragment_num,
+ fail_str);
+ return 0;
+ }
+ }
+
/* no combinations with both src_port and dst_port
* or port with src_port and dst_port
*/
" too complex. ignoring.");
return 0;
}
+ if ((api->match_src_port_num || api->match_dst_port_num
+ || api->match_port_num) && (api->match_icmp_type_num
+ || api->match_icmp_code_num)) {
+ if (BGP_DEBUG(pbr, PBR))
+ zlog_debug("BGP: match multiple port/imcp operations:"
+ " too complex. ignoring.");
+ return 0;
+ }
if (!(api->match_bitmask & PREFIX_SRC_PRESENT) &&
!(api->match_bitmask & PREFIX_DST_PRESENT)) {
if (BGP_DEBUG(pbr, PBR)) {
key = jhash_1word(pbm->vrf_id, 0x4312abde);
key = jhash_1word(pbm->flags, key);
+ key = jhash_1word(pbm->pkt_len_min, key);
+ key = jhash_1word(pbm->pkt_len_max, key);
+ key = jhash_1word(pbm->tcp_flags, key);
+ key = jhash_1word(pbm->tcp_mask_flags, key);
+ key = jhash_1word(pbm->dscp_value, key);
+ key = jhash_1word(pbm->fragment, key);
return jhash_1word(pbm->type, key);
}
if (r1->action != r2->action)
return 0;
+ if (r1->pkt_len_min != r2->pkt_len_min)
+ return 0;
+
+ if (r1->pkt_len_max != r2->pkt_len_max)
+ return 0;
+
+ if (r1->tcp_flags != r2->tcp_flags)
+ return 0;
+
+ if (r1->tcp_mask_flags != r2->tcp_mask_flags)
+ return 0;
+
+ if (r1->dscp_value != r2->dscp_value)
+ return 0;
+
+ if (r1->fragment != r2->fragment)
+ return 0;
return 1;
}
ptr += sprintf_bgp_pbr_match_val(ptr, &api->tcpflags[i],
i > 0 ? NULL : "@tcpflags ");
- if (api->match_bitmask & FRAGMENT_PRESENT) {
+ if (api->match_fragment_num)
INCREMENT_DISPLAY(ptr, nb_items);
- ptr += sprintf(ptr, "@fragment %u", api->fragment.bitmask);
- }
+ for (i = 0; i < api->match_fragment_num; i++)
+ ptr += sprintf_bgp_pbr_match_val(ptr, &api->fragment[i],
+ i > 0 ? NULL : "@fragment ");
if (!nb_items)
ptr = return_string;
else
return HASHWALK_ABORT;
}
-static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
- struct bgp_info *binfo,
- vrf_id_t vrf_id,
- struct prefix *src,
- struct prefix *dst,
- uint8_t protocol,
- struct bgp_pbr_range_port *src_port,
- struct bgp_pbr_range_port *dst_port)
+static void bgp_pbr_policyroute_remove_from_zebra_unit(struct bgp *bgp,
+ struct bgp_info *binfo,
+ struct bgp_pbr_filter *bpf)
{
struct bgp_pbr_match temp;
struct bgp_pbr_match_entry temp2;
struct bgp_pbr_match *bpm;
struct bgp_pbr_match_entry *bpme;
struct bgp_pbr_match_entry_remain bpmer;
+ struct bgp_pbr_range_port *src_port;
+ struct bgp_pbr_range_port *dst_port;
+ struct bgp_pbr_range_port *pkt_len;
+
+ if (!bpf)
+ return;
+ src_port = bpf->src_port;
+ dst_port = bpf->dst_port;
+ pkt_len = bpf->pkt_len;
/* as we don't know information from EC
* look for bpm that have the bpm
*/
memset(&temp2, 0, sizeof(temp2));
memset(&temp, 0, sizeof(temp));
- if (src) {
+ if (bpf->src) {
temp.flags |= MATCH_IP_SRC_SET;
- prefix_copy(&temp2.src, src);
+ prefix_copy(&temp2.src, bpf->src);
} else
temp2.src.family = AF_INET;
- if (dst) {
+ if (bpf->dst) {
temp.flags |= MATCH_IP_DST_SET;
- prefix_copy(&temp2.dst, dst);
+ prefix_copy(&temp2.dst, bpf->dst);
} else
temp2.dst.family = AF_INET;
- if (src_port) {
+ if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
+ if (bpf->protocol == IPPROTO_ICMP)
+ temp.flags |= MATCH_ICMP_SET;
temp.flags |= MATCH_PORT_SRC_SET;
temp2.src_port_min = src_port->min_port;
if (src_port->max_port) {
temp2.src_port_max = src_port->max_port;
}
}
- if (dst_port) {
+ if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
+ if (bpf->protocol == IPPROTO_ICMP)
+ temp.flags |= MATCH_ICMP_SET;
temp.flags |= MATCH_PORT_DST_SET;
temp2.dst_port_min = dst_port->min_port;
if (dst_port->max_port) {
temp2.dst_port_max = dst_port->max_port;
}
}
- temp2.proto = protocol;
+ temp2.proto = bpf->protocol;
+
+ if (pkt_len) {
+ temp.pkt_len_min = pkt_len->min_port;
+ if (pkt_len->max_port)
+ temp.pkt_len_max = pkt_len->max_port;
+ } else if (bpf->pkt_len_val) {
+ if (bpf->pkt_len_val->mask)
+ temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
+ temp.pkt_len_min = bpf->pkt_len_val->val;
+ }
+ if (bpf->tcp_flags) {
+ temp.tcp_flags = bpf->tcp_flags->val;
+ temp.tcp_mask_flags = bpf->tcp_flags->mask;
+ }
+ if (bpf->dscp) {
+ if (bpf->dscp->mask)
+ temp.flags |= MATCH_DSCP_INVERSE_SET;
+ else
+ temp.flags |= MATCH_DSCP_SET;
+ temp.dscp_value = bpf->dscp->val;
+ }
+ if (bpf->fragment) {
+ if (bpf->fragment->mask)
+ temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
+ temp.fragment = bpf->fragment->val;
+ }
- if (src == NULL || dst == NULL) {
+ if (bpf->src == NULL || bpf->dst == NULL) {
if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
temp.type = IPSET_NET_PORT;
else
else
temp.type = IPSET_NET_NET;
}
- if (vrf_id == VRF_UNKNOWN) /* XXX case BGP destroy */
+ if (bpf->vrf_id == VRF_UNKNOWN) /* XXX case BGP destroy */
temp.vrf_id = 0;
else
- temp.vrf_id = vrf_id;
+ temp.vrf_id = bpf->vrf_id;
bpme = &temp2;
bpm = &temp;
bpme->backpointer = bpm;
}
}
-static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
+static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry)
+{
+ if (type_entry == FLOWSPEC_TCP_FLAGS)
+ return FLOWSPEC_DSCP;
+ if (type_entry == FLOWSPEC_DSCP)
+ return FLOWSPEC_PKT_LEN;
+ if (type_entry == FLOWSPEC_PKT_LEN)
+ return FLOWSPEC_FRAGMENT;
+ if (type_entry == FLOWSPEC_FRAGMENT)
+ return FLOWSPEC_ICMP_TYPE;
+ return 0;
+}
+
+static void bgp_pbr_icmp_action(struct bgp *bgp,
+ struct bgp_info *binfo,
+ struct bgp_pbr_filter *bpf,
+ struct bgp_pbr_or_filter *bpof,
+ bool add,
+ struct nexthop *nh,
+ float *rate)
+{
+ struct bgp_pbr_range_port srcp, dstp;
+ struct bgp_pbr_val_mask *icmp_type, *icmp_code;
+ struct listnode *tnode, *cnode;
+
+ if (!bpf)
+ return;
+ if (bpf->protocol != IPPROTO_ICMP)
+ return;
+ bpf->src_port = &srcp;
+ bpf->dst_port = &dstp;
+ /* parse icmp type and lookup appropriate icmp code
+ * if no icmp code found, create as many entryes as
+ * there are listed icmp codes for that icmp type
+ */
+ if (!bpof->icmp_type) {
+ srcp.min_port = 0;
+ srcp.max_port = 255;
+ for (ALL_LIST_ELEMENTS_RO(bpof->icmp_code, cnode, icmp_code)) {
+ dstp.min_port = icmp_code->val;
+ if (add)
+ bgp_pbr_policyroute_add_to_zebra_unit(bgp, binfo,
+ bpf, nh, rate);
+ else
+ bgp_pbr_policyroute_remove_from_zebra_unit(
+ bgp, binfo, bpf);
+ }
+ return;
+ }
+ for (ALL_LIST_ELEMENTS_RO(bpof->icmp_type, tnode, icmp_type)) {
+ srcp.min_port = icmp_type->val;
+ srcp.max_port = 0;
+ dstp.max_port = 0;
+ /* only icmp type. create an entry only with icmp type */
+ if (!bpof->icmp_code) {
+ /* icmp type is not one of the above
+ * forge an entry only based on the icmp type
+ */
+ dstp.min_port = 0;
+ dstp.max_port = 255;
+ if (add)
+ bgp_pbr_policyroute_add_to_zebra_unit(
+ bgp, binfo,
+ bpf, nh, rate);
+ else
+ bgp_pbr_policyroute_remove_from_zebra_unit(bgp,
+ binfo, bpf);
+ continue;
+ }
+ for (ALL_LIST_ELEMENTS_RO(bpof->icmp_code, cnode, icmp_code)) {
+ dstp.min_port = icmp_code->val;
+ if (add)
+ bgp_pbr_policyroute_add_to_zebra_unit(
+ bgp, binfo,
+ bpf, nh, rate);
+ else
+ bgp_pbr_policyroute_remove_from_zebra_unit(
+ bgp, binfo, bpf);
+ }
+ }
+}
+
+static void bgp_pbr_policyroute_remove_from_zebra_recursive(struct bgp *bgp,
+ struct bgp_info *binfo,
+ struct bgp_pbr_filter *bpf,
+ struct bgp_pbr_or_filter *bpof,
+ uint8_t type_entry)
+{
+ struct listnode *node, *nnode;
+ struct bgp_pbr_val_mask *valmask;
+ uint8_t next_type_entry;
+ struct list *orig_list;
+ struct bgp_pbr_val_mask **target_val;
+
+ if (type_entry == 0)
+ return bgp_pbr_policyroute_remove_from_zebra_unit(bgp,
+ binfo, bpf);
+ next_type_entry = bgp_pbr_next_type_entry(type_entry);
+ if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
+ orig_list = bpof->tcpflags;
+ target_val = &bpf->tcp_flags;
+ } else if (type_entry == FLOWSPEC_DSCP && bpof->dscp) {
+ orig_list = bpof->dscp;
+ target_val = &bpf->dscp;
+ } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) {
+ orig_list = bpof->pkt_len;
+ target_val = &bpf->pkt_len_val;
+ } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) {
+ orig_list = bpof->fragment;
+ target_val = &bpf->fragment;
+ } else if (type_entry == FLOWSPEC_ICMP_TYPE &&
+ (bpof->icmp_type || bpof->icmp_code)) {
+ /* enumerate list for icmp - must be last one */
+ bgp_pbr_icmp_action(bgp, binfo, bpf, bpof, false, NULL, NULL);
+ return;
+ } else {
+ return bgp_pbr_policyroute_remove_from_zebra_recursive(bgp,
+ binfo,
+ bpf, bpof,
+ next_type_entry);
+ }
+ for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
+ *target_val = valmask;
+ bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
+ bpf, bpof,
+ next_type_entry);
+ }
+}
+
+static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
+ struct bgp_info *binfo,
+ struct bgp_pbr_filter *bpf,
+ struct bgp_pbr_or_filter *bpof)
+{
+ if (!bpof)
+ return bgp_pbr_policyroute_remove_from_zebra_unit(bgp,
+ binfo,
+ bpf);
+ if (bpof->tcpflags)
+ bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
+ bpf, bpof,
+ FLOWSPEC_TCP_FLAGS);
+ else if (bpof->dscp)
+ bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
+ bpf, bpof,
+ FLOWSPEC_DSCP);
+ else if (bpof->pkt_len)
+ bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
+ bpf, bpof,
+ FLOWSPEC_PKT_LEN);
+ else if (bpof->fragment)
+ bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
+ bpf, bpof,
+ FLOWSPEC_FRAGMENT);
+ else if (bpof->icmp_type || bpof->icmp_code)
+ bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
+ bpf, bpof,
+ FLOWSPEC_ICMP_TYPE);
+ else
+ bgp_pbr_policyroute_remove_from_zebra_unit(bgp, binfo, bpf);
+ /* flush bpof */
+ if (bpof->tcpflags)
+ list_delete_all_node(bpof->tcpflags);
+ if (bpof->dscp)
+ list_delete_all_node(bpof->dscp);
+ if (bpof->pkt_len)
+ list_delete_all_node(bpof->pkt_len);
+ if (bpof->fragment)
+ list_delete_all_node(bpof->fragment);
+}
+
+static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
struct bgp_info *binfo,
- vrf_id_t vrf_id,
- struct prefix *src,
- struct prefix *dst,
+ struct bgp_pbr_filter *bpf,
struct nexthop *nh,
- float *rate,
- uint8_t protocol,
- struct bgp_pbr_range_port *src_port,
- struct bgp_pbr_range_port *dst_port)
+ float *rate)
{
struct bgp_pbr_match temp;
struct bgp_pbr_match_entry temp2;
struct bgp_pbr_action temp3;
struct bgp_pbr_action *bpa = NULL;
struct bgp_pbr_match_entry_remain bpmer;
+ struct bgp_pbr_range_port *src_port;
+ struct bgp_pbr_range_port *dst_port;
+ struct bgp_pbr_range_port *pkt_len;
+ if (!bpf)
+ return;
+ src_port = bpf->src_port;
+ dst_port = bpf->dst_port;
+ pkt_len = bpf->pkt_len;
+
+ if (BGP_DEBUG(zebra, ZEBRA)) {
+ char bufsrc[64], bufdst[64];
+ char buffer[64];
+ int remaining_len = 0;
+ char protocol_str[16];
+
+ protocol_str[0] = '\0';
+ if (bpf->tcp_flags && bpf->tcp_flags->mask)
+ bpf->protocol = IPPROTO_TCP;
+ if (bpf->protocol)
+ snprintf(protocol_str, sizeof(protocol_str),
+ "proto %d", bpf->protocol);
+ buffer[0] = '\0';
+ if (bpf->protocol == IPPROTO_ICMP && src_port && dst_port)
+ remaining_len += snprintf(buffer, sizeof(buffer),
+ "type %d, code %d",
+ src_port->min_port, dst_port->min_port);
+ else if (bpf->protocol == IPPROTO_UDP ||
+ bpf->protocol == IPPROTO_TCP) {
+
+ if (src_port && src_port->min_port)
+ remaining_len += snprintf(buffer,
+ sizeof(buffer),
+ "from [%u:%u]",
+ src_port->min_port,
+ src_port->max_port ?
+ src_port->max_port :
+ src_port->min_port);
+ if (dst_port && dst_port->min_port)
+ remaining_len += snprintf(buffer +
+ remaining_len,
+ sizeof(buffer)
+ - remaining_len,
+ "to [%u:%u]",
+ dst_port->min_port,
+ dst_port->max_port ?
+ dst_port->max_port :
+ dst_port->min_port);
+ }
+ if (pkt_len && (pkt_len->min_port || pkt_len->max_port)) {
+ remaining_len += snprintf(buffer + remaining_len,
+ sizeof(buffer)
+ - remaining_len,
+ " len [%u:%u]",
+ pkt_len->min_port,
+ pkt_len->max_port ?
+ pkt_len->max_port :
+ pkt_len->min_port);
+ } else if (bpf->pkt_len_val) {
+ remaining_len += snprintf(buffer + remaining_len,
+ sizeof(buffer)
+ - remaining_len,
+ " %s len %u",
+ bpf->pkt_len_val->mask
+ ? "!" : "",
+ bpf->pkt_len_val->val);
+ }
+ if (bpf->tcp_flags) {
+ remaining_len += snprintf(buffer + remaining_len,
+ sizeof(buffer)
+ - remaining_len,
+ "tcpflags %x/%x",
+ bpf->tcp_flags->val,
+ bpf->tcp_flags->mask);
+ }
+ if (bpf->dscp) {
+ snprintf(buffer + remaining_len,
+ sizeof(buffer)
+ - remaining_len,
+ "%s dscp %d",
+ bpf->dscp->mask
+ ? "!" : "",
+ bpf->dscp->val);
+ }
+ zlog_info("BGP: adding FS PBR from %s to %s, %s %s",
+ bpf->src == NULL ? "<all>" :
+ prefix2str(bpf->src, bufsrc, sizeof(bufsrc)),
+ bpf->dst == NULL ? "<all>" :
+ prefix2str(bpf->dst, bufdst, sizeof(bufdst)),
+ protocol_str, buffer);
+ }
/* look for bpa first */
memset(&temp3, 0, sizeof(temp3));
if (rate)
temp3.rate = *rate;
if (nh)
memcpy(&temp3.nh, nh, sizeof(struct nexthop));
- temp3.vrf_id = vrf_id;
+ temp3.vrf_id = bpf->vrf_id;
bpa = hash_get(bgp->pbr_action_hash, &temp3,
bgp_pbr_action_alloc_intern);
/* then look for bpm */
memset(&temp, 0, sizeof(temp));
- if (src == NULL || dst == NULL) {
- if ((src_port && src_port->min_port) ||
- (dst_port && dst_port->min_port))
- temp.type = IPSET_NET_PORT;
- else
- temp.type = IPSET_NET;
- } else {
- if ((src_port && src_port->min_port) ||
- (dst_port && dst_port->min_port))
- temp.type = IPSET_NET_PORT_NET;
- else
- temp.type = IPSET_NET_NET;
- }
- temp.vrf_id = vrf_id;
- if (src)
+ temp.vrf_id = bpf->vrf_id;
+ if (bpf->src)
temp.flags |= MATCH_IP_SRC_SET;
- if (dst)
+ if (bpf->dst)
temp.flags |= MATCH_IP_DST_SET;
- if (src_port && src_port->min_port)
+ if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
+ if (bpf->protocol == IPPROTO_ICMP)
+ temp.flags |= MATCH_ICMP_SET;
temp.flags |= MATCH_PORT_SRC_SET;
- if (dst_port && dst_port->min_port)
+ }
+ if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
+ if (bpf->protocol == IPPROTO_ICMP)
+ temp.flags |= MATCH_ICMP_SET;
temp.flags |= MATCH_PORT_DST_SET;
+ }
if (src_port && src_port->max_port)
temp.flags |= MATCH_PORT_SRC_RANGE_SET;
if (dst_port && dst_port->max_port)
temp.flags |= MATCH_PORT_DST_RANGE_SET;
+
+ if (bpf->src == NULL || bpf->dst == NULL) {
+ if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
+ temp.type = IPSET_NET_PORT;
+ else
+ temp.type = IPSET_NET;
+ } else {
+ if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
+ temp.type = IPSET_NET_PORT_NET;
+ else
+ temp.type = IPSET_NET_NET;
+ }
+ if (pkt_len) {
+ temp.pkt_len_min = pkt_len->min_port;
+ if (pkt_len->max_port)
+ temp.pkt_len_max = pkt_len->max_port;
+ } else if (bpf->pkt_len_val) {
+ if (bpf->pkt_len_val->mask)
+ temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
+ temp.pkt_len_min = bpf->pkt_len_val->val;
+ }
+ if (bpf->tcp_flags) {
+ temp.tcp_flags = bpf->tcp_flags->val;
+ temp.tcp_mask_flags = bpf->tcp_flags->mask;
+ }
+ if (bpf->dscp) {
+ if (bpf->dscp->mask)
+ temp.flags |= MATCH_DSCP_INVERSE_SET;
+ else
+ temp.flags |= MATCH_DSCP_SET;
+ temp.dscp_value = bpf->dscp->val;
+ }
+ if (bpf->fragment) {
+ if (bpf->fragment->mask)
+ temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
+ temp.fragment = bpf->fragment->val;
+ }
temp.action = bpa;
bpm = hash_get(bgp->pbr_match_hash, &temp,
bgp_pbr_match_alloc_intern);
}
memset(&temp2, 0, sizeof(temp2));
- if (src)
- prefix_copy(&temp2.src, src);
+ if (bpf->src)
+ prefix_copy(&temp2.src, bpf->src);
else
temp2.src.family = AF_INET;
- if (dst)
- prefix_copy(&temp2.dst, dst);
+ if (bpf->dst)
+ prefix_copy(&temp2.dst, bpf->dst);
else
temp2.dst.family = AF_INET;
temp2.src_port_min = src_port ? src_port->min_port : 0;
temp2.dst_port_min = dst_port ? dst_port->min_port : 0;
temp2.src_port_max = src_port ? src_port->max_port : 0;
temp2.dst_port_max = dst_port ? dst_port->max_port : 0;
- temp2.proto = protocol;
+ temp2.proto = bpf->protocol;
if (bpm)
bpme = hash_get(bpm->entry_hash, &temp2,
bgp_pbr_match_entry_alloc_intern);
* it will be suppressed subsequently
*/
/* ip rule add */
- if (!bpa->installed) {
+ if (!bpa->installed && !bpa->install_in_progress) {
bgp_send_pbr_rule_action(bpa, true);
bgp_zebra_announce_default(bgp, nh,
AFI_IP, bpa->table_id, true);
}
+static void bgp_pbr_policyroute_add_to_zebra_recursive(struct bgp *bgp,
+ struct bgp_info *binfo,
+ struct bgp_pbr_filter *bpf,
+ struct bgp_pbr_or_filter *bpof,
+ struct nexthop *nh,
+ float *rate,
+ uint8_t type_entry)
+{
+ struct listnode *node, *nnode;
+ struct bgp_pbr_val_mask *valmask;
+ uint8_t next_type_entry;
+ struct list *orig_list;
+ struct bgp_pbr_val_mask **target_val;
+
+ if (type_entry == 0)
+ return bgp_pbr_policyroute_add_to_zebra_unit(bgp, binfo, bpf,
+ nh, rate);
+ next_type_entry = bgp_pbr_next_type_entry(type_entry);
+ if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
+ orig_list = bpof->tcpflags;
+ target_val = &bpf->tcp_flags;
+ } else if (type_entry == FLOWSPEC_DSCP && bpof->dscp) {
+ orig_list = bpof->dscp;
+ target_val = &bpf->dscp;
+ } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) {
+ orig_list = bpof->pkt_len;
+ target_val = &bpf->pkt_len_val;
+ } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) {
+ orig_list = bpof->fragment;
+ target_val = &bpf->fragment;
+ } else if (type_entry == FLOWSPEC_ICMP_TYPE &&
+ (bpof->icmp_type || bpof->icmp_code)) {
+ /* enumerate list for icmp - must be last one */
+ bgp_pbr_icmp_action(bgp, binfo, bpf, bpof, true, nh, rate);
+ return;
+ } else {
+ return bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
+ bpf, bpof, nh, rate,
+ next_type_entry);
+ }
+ for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
+ *target_val = valmask;
+ bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
+ bpf, bpof,
+ nh, rate,
+ next_type_entry);
+ }
+}
+
+static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
+ struct bgp_info *binfo,
+ struct bgp_pbr_filter *bpf,
+ struct bgp_pbr_or_filter *bpof,
+ struct nexthop *nh,
+ float *rate)
+{
+ if (!bpof)
+ return bgp_pbr_policyroute_add_to_zebra_unit(bgp, binfo,
+ bpf, nh, rate);
+ if (bpof->tcpflags)
+ bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
+ bpf, bpof,
+ nh, rate,
+ FLOWSPEC_TCP_FLAGS);
+ else if (bpof->dscp)
+ bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
+ bpf, bpof,
+ nh, rate,
+ FLOWSPEC_DSCP);
+ else if (bpof->pkt_len)
+ bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
+ bpf, bpof,
+ nh, rate,
+ FLOWSPEC_PKT_LEN);
+ else if (bpof->fragment)
+ bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
+ bpf, bpof,
+ nh, rate,
+ FLOWSPEC_FRAGMENT);
+ else if (bpof->icmp_type || bpof->icmp_code)
+ bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
+ bpf, bpof, nh, rate,
+ FLOWSPEC_ICMP_TYPE);
+ else
+ bgp_pbr_policyroute_add_to_zebra_unit(bgp, binfo, bpf,
+ nh, rate);
+ /* flush bpof */
+ if (bpof->tcpflags)
+ list_delete_all_node(bpof->tcpflags);
+ if (bpof->dscp)
+ list_delete_all_node(bpof->dscp);
+ if (bpof->pkt_len)
+ list_delete_all_node(bpof->pkt_len);
+ if (bpof->fragment)
+ list_delete_all_node(bpof->fragment);
+ if (bpof->icmp_type)
+ list_delete_all_node(bpof->icmp_type);
+ if (bpof->icmp_code)
+ list_delete_all_node(bpof->icmp_code);
+}
+
static void bgp_pbr_handle_entry(struct bgp *bgp,
struct bgp_info *binfo,
struct bgp_pbr_entry_main *api,
struct prefix *src = NULL, *dst = NULL;
uint8_t proto = 0;
struct bgp_pbr_range_port *srcp = NULL, *dstp = NULL;
- struct bgp_pbr_range_port range;
+ struct bgp_pbr_range_port range, range_icmp_code;
+ struct bgp_pbr_range_port pkt_len;
+ struct bgp_pbr_filter bpf;
+ uint8_t kind_enum;
+ struct bgp_pbr_or_filter bpof;
+ struct bgp_pbr_val_mask bpvm;
memset(&nh, 0, sizeof(struct nexthop));
+ memset(&bpf, 0, sizeof(struct bgp_pbr_filter));
+ memset(&bpof, 0, sizeof(struct bgp_pbr_or_filter));
if (api->match_bitmask & PREFIX_SRC_PRESENT)
src = &api->src_prefix;
if (api->match_bitmask & PREFIX_DST_PRESENT)
dstp = ⦥
srcp = NULL;
}
+ if (api->match_icmp_type_num >= 1) {
+ proto = IPPROTO_ICMP;
+ if (bgp_pbr_extract(api->icmp_type,
+ api->match_icmp_type_num,
+ &range))
+ srcp = ⦥
+ else {
+ bpof.icmp_type = list_new();
+ bgp_pbr_extract_enumerate(api->icmp_type,
+ api->match_icmp_type_num,
+ OPERATOR_UNARY_OR,
+ bpof.icmp_type,
+ FLOWSPEC_ICMP_TYPE);
+ }
+ }
+ if (api->match_icmp_code_num >= 1) {
+ proto = IPPROTO_ICMP;
+ if (bgp_pbr_extract(api->icmp_code,
+ api->match_icmp_code_num,
+ &range_icmp_code))
+ dstp = &range_icmp_code;
+ else {
+ bpof.icmp_code = list_new();
+ bgp_pbr_extract_enumerate(api->icmp_code,
+ api->match_icmp_code_num,
+ OPERATOR_UNARY_OR,
+ bpof.icmp_code,
+ FLOWSPEC_ICMP_CODE);
+ }
+ }
+
+ if (api->match_tcpflags_num) {
+ kind_enum = bgp_pbr_match_val_get_operator(api->tcpflags,
+ api->match_tcpflags_num);
+ if (kind_enum == OPERATOR_UNARY_AND) {
+ bpf.tcp_flags = &bpvm;
+ bgp_pbr_extract_enumerate(api->tcpflags,
+ api->match_tcpflags_num,
+ OPERATOR_UNARY_AND,
+ bpf.tcp_flags,
+ FLOWSPEC_TCP_FLAGS);
+ } else if (kind_enum == OPERATOR_UNARY_OR) {
+ bpof.tcpflags = list_new();
+ bgp_pbr_extract_enumerate(api->tcpflags,
+ api->match_tcpflags_num,
+ OPERATOR_UNARY_OR,
+ bpof.tcpflags,
+ FLOWSPEC_TCP_FLAGS);
+ }
+ }
+ if (api->match_packet_length_num) {
+ bool ret;
+
+ ret = bgp_pbr_extract(api->packet_length,
+ api->match_packet_length_num,
+ &pkt_len);
+ if (ret)
+ bpf.pkt_len = &pkt_len;
+ else {
+ bpof.pkt_len = list_new();
+ bgp_pbr_extract_enumerate(api->packet_length,
+ api->match_packet_length_num,
+ OPERATOR_UNARY_OR,
+ bpof.pkt_len,
+ FLOWSPEC_PKT_LEN);
+ }
+ }
+ if (api->match_dscp_num >= 1) {
+ bpof.dscp = list_new();
+ bgp_pbr_extract_enumerate(api->dscp, api->match_dscp_num,
+ OPERATOR_UNARY_OR,
+ bpof.dscp, FLOWSPEC_DSCP);
+ }
+ if (api->match_fragment_num) {
+ bpof.fragment = list_new();
+ bgp_pbr_extract_enumerate(api->fragment,
+ api->match_fragment_num,
+ OPERATOR_UNARY_OR,
+ bpof.fragment,
+ FLOWSPEC_FRAGMENT);
+ }
+ bpf.vrf_id = api->vrf_id;
+ bpf.src = src;
+ bpf.dst = dst;
+ bpf.protocol = proto;
+ bpf.src_port = srcp;
+ bpf.dst_port = dstp;
if (!add)
- return bgp_pbr_policyroute_remove_from_zebra(bgp, binfo,
- api->vrf_id, src, dst,
- proto, srcp, dstp);
+ return bgp_pbr_policyroute_remove_from_zebra(bgp,
+ binfo,
+ &bpf, &bpof);
/* no action for add = true */
for (i = 0; i < api->action_num; i++) {
switch (api->actions[i].action) {
nh.vrf_id = api->vrf_id;
nh.type = NEXTHOP_TYPE_BLACKHOLE;
bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
- api->vrf_id, src, dst,
- &nh, &rate, proto,
- srcp, dstp);
+ &bpf, &bpof,
+ &nh, &rate);
} else {
/* update rate. can be reentrant */
rate = api->actions[i].u.r.rate;
api->actions[i].u.zr.redirect_ip_v4.s_addr;
nh.vrf_id = api->vrf_id;
bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
- api->vrf_id,
- src, dst,
- &nh, &rate, proto,
- srcp, dstp);
+ &bpf, &bpof,
+ &nh, &rate);
/* XXX combination with REDIRECT_VRF
* + REDIRECT_NH_IP not done
*/
nh.vrf_id = api->actions[i].u.redirect_vrf;
nh.type = NEXTHOP_TYPE_IPV4;
bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
- api->vrf_id,
- src, dst,
- &nh, &rate, proto,
- srcp, dstp);
+ &bpf, &bpof,
+ &nh, &rate);
continue_loop = 0;
break;
case ACTION_MARKING:
#define PREFIX_SRC_PRESENT (1 << 0)
#define PREFIX_DST_PRESENT (1 << 1)
-#define FRAGMENT_PRESENT (1 << 2)
uint8_t match_bitmask;
uint8_t match_src_port_num;
uint8_t match_packet_length_num;
uint8_t match_dscp_num;
uint8_t match_tcpflags_num;
+ uint8_t match_fragment_num;
struct prefix src_prefix;
struct prefix dst_prefix;
#define PROTOCOL_UDP 17
#define PROTOCOL_TCP 6
+#define PROTOCOL_ICMP 1
struct bgp_pbr_match_val protocol[BGP_PBR_MATCH_VAL_MAX];
struct bgp_pbr_match_val src_port[BGP_PBR_MATCH_VAL_MAX];
struct bgp_pbr_match_val dst_port[BGP_PBR_MATCH_VAL_MAX];
struct bgp_pbr_match_val icmp_code[BGP_PBR_MATCH_VAL_MAX];
struct bgp_pbr_match_val packet_length[BGP_PBR_MATCH_VAL_MAX];
struct bgp_pbr_match_val dscp[BGP_PBR_MATCH_VAL_MAX];
+
struct bgp_pbr_match_val tcpflags[BGP_PBR_MATCH_VAL_MAX];
- struct bgp_pbr_fragment_val fragment;
+ struct bgp_pbr_match_val fragment[BGP_PBR_MATCH_VAL_MAX];
uint16_t action_num;
struct bgp_pbr_entry_action actions[ACTIONS_MAX_NUM];
*/
uint32_t type;
-#define MATCH_IP_SRC_SET (1 << 0)
-#define MATCH_IP_DST_SET (1 << 1)
-#define MATCH_PORT_SRC_SET (1 << 2)
-#define MATCH_PORT_DST_SET (1 << 3)
-#define MATCH_PORT_SRC_RANGE_SET (1 << 4)
-#define MATCH_PORT_DST_RANGE_SET (1 << 5)
uint32_t flags;
+ uint16_t pkt_len_min;
+ uint16_t pkt_len_max;
+ uint16_t tcp_flags;
+ uint16_t tcp_mask_flags;
+ uint8_t dscp_value;
+ uint8_t fragment;
+
vrf_id_t vrf_id;
/* unique identifier for ipset create transaction
#include "memory.h"
#include "stream.h"
#include "filter.h"
+#include "frrstr.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_rd.h"
peer->rmap_type = 0;
- if (ret == RMAP_DENYMATCH) {
- /* Free newly generated AS path and community by
- * route-map. */
- bgp_attr_flush(attr);
+ if (ret == RMAP_DENYMATCH)
return RMAP_DENY;
- }
}
return RMAP_PERMIT;
}
old = attr->community;
gshut = community_str2com("graceful-shutdown");
+ assert(gshut);
+
if (old) {
merge = community_merge(community_dup(old), gshut);
prefix2str(p, buf, PREFIX_STRLEN);
len = vty_out(vty, "%s", buf);
} else if (p->family == AF_EVPN) {
-#if defined(HAVE_CUMULUS)
if (!json)
len = vty_out(
vty, "%s",
BUFSIZ));
else
bgp_evpn_route2json((struct prefix_evpn *)p, json);
-#else
- prefix2str(p, buf, PREFIX_STRLEN);
- len = vty_out(vty, "%s", buf);
-#endif
} else if (p->family == AF_FLOWSPEC) {
route_vty_out_flowspec(vty, p, NULL,
json ?
} else {
char buf[BUFSIZ];
- if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN))
- snprintf(buf, sizeof(buf), "%s%s",
- inet_ntoa(attr->mp_nexthop_global_in),
- vrf_id_str);
- else
- snprintf(buf, sizeof(buf), "%s%s",
- inet_ntoa(attr->nexthop),
- vrf_id_str);
+ snprintf(buf, sizeof(buf), "%s%s",
+ inet_ntoa(attr->nexthop), vrf_id_str);
vty_out(vty, "%-16s", buf);
}
}
{
char buf[INET6_ADDRSTRLEN];
char buf1[BUFSIZ];
-#if defined(HAVE_CUMULUS)
char buf2[EVPN_ROUTE_STRLEN];
-#endif
struct attr *attr;
int sockunion_vty_out(struct vty *, union sockunion *);
time_t tbuf;
json_nexthop_global = json_object_new_object();
}
-#if defined(HAVE_CUMULUS)
if (!json_paths && safi == SAFI_EVPN) {
char tag_buf[30];
}
}
}
-#endif
attr = binfo->attr;
if (binfo->extra && binfo->extra->damp_info)
bgp_damp_info_vty(vty, binfo, json_path);
-/* Remote Label */
-#if defined(HAVE_CUMULUS)
+ /* Remote Label */
if (binfo->extra && bgp_is_valid_label(&binfo->extra->label[0])
- && safi != SAFI_EVPN)
-#else
- if (binfo->extra && bgp_is_valid_label(&binfo->extra->label[0]))
-#endif
- {
+ && safi != SAFI_EVPN) {
mpls_label_t label =
label_pton(&binfo->extra->label[0]);
if (json_paths)
struct listnode *node, *nnode;
char buf1[RD_ADDRSTRLEN];
char buf2[INET6_ADDRSTRLEN];
-#if defined(HAVE_CUMULUS)
char buf3[EVPN_ROUTE_STRLEN];
-#endif
char prefix_str[BUFSIZ];
int count = 0;
int best = 0;
json, "prefix",
prefix2str(p, prefix_str, sizeof(prefix_str)));
} else {
-#if defined(HAVE_CUMULUS)
if (safi == SAFI_EVPN)
vty_out(vty, "BGP routing table entry for %s%s%s\n",
prd ? prefix_rd2str(prd, buf1, sizeof(buf1))
inet_ntop(p->family, &p->u.prefix, buf2,
INET6_ADDRSTRLEN),
p->prefixlen);
-#else
- if (p->family == AF_ETHERNET)
- prefix2str(p, buf2, INET6_ADDRSTRLEN);
- else
- inet_ntop(p->family, &p->u.prefix, buf2,
- INET6_ADDRSTRLEN);
- vty_out(vty, "BGP routing table entry for %s%s%s/%d\n",
- ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
- || safi == SAFI_EVPN)
- ? prefix_rd2str(prd, buf1, sizeof(buf1))
- : ""),
- ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) ? ":"
- : "",
- buf2, p->prefixlen);
-#endif
if (has_valid_label)
vty_out(vty, "Local label: %d\n", label);
-#if defined(HAVE_CUMULUS)
if (bgp_labeled_safi(safi) && safi != SAFI_EVPN)
-#else
- if (bgp_labeled_safi(safi))
-#endif
vty_out(vty, "not allocated\n");
}
#include "sockunion.h"
#include "hash.h"
#include "queue.h"
+#include "frrstr.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
}
}
-static int bgp_route_map_process_update_cb(char *rmap_name)
+static void bgp_route_map_process_update_cb(char *rmap_name)
{
struct listnode *node, *nnode;
struct bgp *bgp;
}
vpn_policy_routemap_event(rmap_name);
-
- return 0;
}
int bgp_route_map_update_timer(struct thread *thread)
static void bgp_route_map_add(const char *rmap_name)
{
- if (route_map_mark_updated(rmap_name, 0) == 0)
+ if (route_map_mark_updated(rmap_name) == 0)
bgp_route_map_mark_update(rmap_name);
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
static void bgp_route_map_delete(const char *rmap_name)
{
- if (route_map_mark_updated(rmap_name, 1) == 0)
+ if (route_map_mark_updated(rmap_name) == 0)
bgp_route_map_mark_update(rmap_name);
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
static void bgp_route_map_event(route_map_event_t event, const char *rmap_name)
{
- if (route_map_mark_updated(rmap_name, 0) == 0)
+ if (route_map_mark_updated(rmap_name) == 0)
bgp_route_map_mark_update(rmap_name);
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
XFREE(MTYPE_BGP_RPKI_CACHE, ptr);
}
+static void init_tr_socket(struct cache *cache)
+{
+ if (cache->type == TCP)
+ tr_tcp_init(cache->tr_config.tcp_config,
+ cache->tr_socket);
+#if defined(FOUND_SSH)
+ else
+ tr_ssh_init(cache->tr_config.ssh_config,
+ cache->tr_socket);
+#endif
+}
+
+static void free_tr_socket(struct cache *cache)
+{
+ if (cache->type == TCP)
+ tr_tcp_init(cache->tr_config.tcp_config,
+ cache->tr_socket);
+#if defined(FOUND_SSH)
+ else
+ tr_ssh_init(cache->tr_config.ssh_config,
+ cache->tr_socket);
+#endif
+}
+
static int rpki_validate_prefix(struct peer *peer, struct attr *attr,
struct prefix *prefix);
rtr_mgr_groups[i].sockets_len = 1;
rtr_mgr_groups[i].preference = cache->preference;
- if (cache->type == TCP)
- tr_tcp_init(cache->tr_config.tcp_config,
- cache->tr_socket);
-#if defined(FOUND_SSH)
- else
- tr_ssh_init(cache->tr_config.ssh_config,
- cache->tr_socket);
-#endif
+ init_tr_socket(cache);
i++;
}
static struct rtr_mgr_group *get_connected_group(void)
{
- if (list_isempty(cache_list))
+ if (!cache_list || list_isempty(cache_list))
return NULL;
return rtr_mgr_get_first_group(rtr_config);
listnode_add(cache_list, cache);
- if (rtr_is_running
- && rtr_mgr_add_group(rtr_config, &group) != RTR_SUCCESS) {
- return ERROR;
+ if (rtr_is_running) {
+ init_tr_socket(cache);
+
+ if (rtr_mgr_add_group(rtr_config, &group) != RTR_SUCCESS) {
+ free_tr_socket(cache);
+ return ERROR;
+ }
}
return SUCCESS;
return SNMP_ERR_NOSUCHNAME;
break;
case BGPPEERCONNECTRETRYINTERVAL:
- SET_FLAG(peer->config, PEER_CONFIG_CONNECT);
+ peer_flag_set(peer, PEER_FLAG_TIMER_CONNECT);
peer->connect = intval;
peer->v_connect = intval;
break;
case BGPPEERHOLDTIMECONFIGURED:
- SET_FLAG(peer->config, PEER_CONFIG_TIMER);
+ peer_flag_set(peer, PEER_FLAG_TIMER);
peer->holdtime = intval;
peer->v_holdtime = intval;
break;
case BGPPEERKEEPALIVECONFIGURED:
- SET_FLAG(peer->config, PEER_CONFIG_TIMER);
+ peer_flag_set(peer, PEER_FLAG_TIMER);
peer->keepalive = intval;
peer->v_keepalive = intval;
break;
break;
case BGPPEERHOLDTIMECONFIGURED:
*write_method = write_bgpPeerTable;
- if (PEER_OR_GROUP_TIMER_SET(peer))
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
return SNMP_INTEGER(peer->holdtime);
else
return SNMP_INTEGER(peer->v_holdtime);
break;
case BGPPEERKEEPALIVECONFIGURED:
*write_method = write_bgpPeerTable;
- if (PEER_OR_GROUP_TIMER_SET(peer))
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
return SNMP_INTEGER(peer->keepalive);
else
return SNMP_INTEGER(peer->v_keepalive);
static void update_subgroup_remove_peer_internal(struct update_subgroup *subgrp,
struct peer_af *paf)
{
- assert(subgrp && paf);
+ assert(subgrp && paf && subgrp->update_group);
if (bgp_debug_peer_updout_enabled(paf->peer->host)) {
UPDGRP_PEER_DBG_DIS(subgrp->update_group);
vec = &pkt->arr.entries[BGP_ATTR_VEC_NH];
if (CHECK_FLAG(vec->flags, BPKT_ATTRVEC_FLAGS_UPDATED)) {
uint8_t nhlen;
- afi_t nhafi = AFI_MAX; /* NH AFI is based on nhlen! */
+ afi_t nhafi;
int route_map_sets_nh;
nhlen = stream_getc_from(s, vec->offset);
if (peer_cap_enhe(peer, paf->afi, paf->safi))
if (rd_header) {
uint16_t type;
- struct rd_as rd_as;
+ struct rd_as rd_as = {0};
struct rd_ip rd_ip = {0};
#if ENABLE_BGP_VNC
struct rd_vnc_eth rd_vnc_eth = {
}
rd_header = 0;
}
- route_vty_out_tmp(vty, &rm->p, attr,
- SAFI_MPLS_VPN,
- use_json, json_array);
+ if (use_json) {
+ char buf_a[BUFSIZ];
+ char buf_b[BUFSIZ];
+
+ sprintf(buf_a, "%s/%d",
+ inet_ntop(rm->p.family,
+ rm->p.u.val,
+ buf_b,
+ BUFSIZ),
+ rm->p.prefixlen);
+ json_object_object_add(
+ json_routes, buf_a,
+ json_array);
+ } else {
+ route_vty_out_tmp(
+ vty, &rm->p, attr,
+ SAFI_MPLS_VPN, use_json,
+ json_array);
+ }
}
}
- if (use_json) {
- struct prefix *p;
- char buf_a[BUFSIZ];
- char buf_b[BUFSIZ];
- p = &rm->p;
- sprintf(buf_a, "%s/%d",
- inet_ntop(p->family, &p->u.prefix,
- buf_b, BUFSIZ),
- p->prefixlen);
- json_object_object_add(json_routes, buf_a,
- json_array);
- }
}
}
if (use_json) {
#include "hash.h"
#include "queue.h"
#include "filter.h"
+#include "frrstr.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_advertise.h"
CPP_NOTICE("bgpd: remove deprecated '[no] bgp enforce-first-as' commands")
#endif
-DEFUN_DEPRECATED (bgp_enforce_first_as,
- bgp_enforce_first_as_cmd,
- "bgp enforce-first-as",
- BGP_STR
- "Enforce the first AS for EBGP routes\n")
+DEFUN_HIDDEN (bgp_enforce_first_as,
+ bgp_enforce_first_as_cmd,
+ "[no] bgp enforce-first-as",
+ NO_STR
+ BGP_STR
+ "Enforce the first AS for EBGP routes\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- bgp_flag_set(bgp, BGP_FLAG_ENFORCE_FIRST_AS);
-
- return CMD_SUCCESS;
-}
-DEFUN_DEPRECATED (no_bgp_enforce_first_as,
- no_bgp_enforce_first_as_cmd,
- "no bgp enforce-first-as",
- NO_STR
- BGP_STR
- "Enforce the first AS for EBGP routes\n")
-{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
- bgp_flag_unset(bgp, BGP_FLAG_ENFORCE_FIRST_AS);
+ if (strmatch(argv[0]->text, "no"))
+ bgp_flag_unset(bgp, BGP_FLAG_ENFORCE_FIRST_AS);
+ else
+ bgp_flag_set(bgp, BGP_FLAG_ENFORCE_FIRST_AS);
return CMD_SUCCESS;
}
}
if (v6only)
- SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
+ peer_flag_set(peer, PEER_FLAG_IFPEER_V6ONLY);
/* Request zebra to initiate IPv6 RAs on this interface. We do
* this
if ((v6only && !CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))
|| (!v6only && CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))) {
if (v6only)
- SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
+ peer_flag_set(peer, PEER_FLAG_IFPEER_V6ONLY);
else
- UNSET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
+ peer_flag_unset(peer, PEER_FLAG_IFPEER_V6ONLY);
/* v6only flag changed. Reset bgp seesion */
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
bgp_session_reset(peer);
}
- if (!CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE))
- peer_flag_set(peer, PEER_FLAG_CAPABILITY_ENHE);
+ if (!CHECK_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE)) {
+ SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE);
+ SET_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE);
+ UNSET_FLAG(peer->flags_override, PEER_FLAG_CAPABILITY_ENHE);
+ }
if (peer_group_name) {
group = peer_group_lookup(bgp, peer_group_name);
DEFUN (no_neighbor_description,
no_neighbor_description_cmd,
- "no neighbor <A.B.C.D|X:X::X:X|WORD> description [LINE]",
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> description",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
- "Neighbor specific description\n"
- "Up to 80 characters describing this neighbor\n")
+ "Neighbor specific description\n")
{
int idx_peer = 2;
struct peer *peer;
return CMD_SUCCESS;
}
+ALIAS(no_neighbor_description, no_neighbor_description_comment_cmd,
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> description LINE...",
+ NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
+ "Neighbor specific description\n"
+ "Up to 80 characters describing this neighbor\n")
/* Neighbor update-source. */
static int peer_update_source_vty(struct vty *vty, const char *peer_str,
{
struct peer *peer;
struct prefix p;
+ union sockunion su;
peer = peer_and_group_lookup_vty(vty, peer_str);
if (!peer)
return CMD_WARNING;
if (source_str) {
- union sockunion su;
- int ret = str2sockunion(source_str, &su);
-
- if (ret == 0)
+ if (str2sockunion(source_str, &su) == 0)
peer_update_source_addr_set(peer, &su);
else {
if (str2prefix(source_str, &p)) {
DEFUN (neighbor_strict_capability,
neighbor_strict_capability_cmd,
- "neighbor <A.B.C.D|X:X::X:X> strict-capability-match",
+ "neighbor <A.B.C.D|X:X::X:X|WORD> strict-capability-match",
NEIGHBOR_STR
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR2
"Strict capability negotiation match\n")
{
- int idx_ip = 1;
- return peer_flag_set_vty(vty, argv[idx_ip]->arg,
+ int idx_peer = 1;
+
+ return peer_flag_set_vty(vty, argv[idx_peer]->arg,
PEER_FLAG_STRICT_CAP_MATCH);
}
DEFUN (no_neighbor_strict_capability,
no_neighbor_strict_capability_cmd,
- "no neighbor <A.B.C.D|X:X::X:X> strict-capability-match",
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> strict-capability-match",
NO_STR
NEIGHBOR_STR
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR2
"Strict capability negotiation match\n")
{
- int idx_ip = 2;
- return peer_flag_unset_vty(vty, argv[idx_ip]->arg,
+ int idx_peer = 2;
+
+ return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
PEER_FLAG_STRICT_CAP_MATCH);
}
safi_t safi;
afi_t afi;
+ if (import_name == NULL) {
+ vty_out(vty, "%% Missing import name\n");
+ return CMD_WARNING;
+ }
+
if (argv_find(argv, argc, "no", &idx))
remove = true;
!= NULL) {
if (rm->p.prefixlen
== match.prefixlen) {
- SET_FLAG(rn->flags,
+ SET_FLAG(rm->flags,
BGP_NODE_USER_CLEAR);
bgp_process(bgp, rm, afi, safi);
}
if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
json_object_string_add(json_peer, "state",
"Idle (Admin)");
+ else if (peer->afc_recv[afi][safi])
+ json_object_string_add(
+ json_peer, "state",
+ lookup_msg(bgp_status_msg, peer->status,
+ NULL));
else if (CHECK_FLAG(peer->sflags,
PEER_STATUS_PREFIX_OVERFLOW))
json_object_string_add(json_peer, "state",
json_object_int_add(json_neigh,
"bgpTimerKeepAliveIntervalMsecs",
p->v_keepalive * 1000);
-
- if (PEER_OR_GROUP_TIMER_SET(p)) {
+ if (CHECK_FLAG(p->flags, PEER_FLAG_TIMER)) {
json_object_int_add(json_neigh,
"bgpTimerConfiguredHoldTimeMsecs",
p->holdtime * 1000);
vty_out(vty,
" Hold time is %d, keepalive interval is %d seconds\n",
p->v_holdtime, p->v_keepalive);
- if (PEER_OR_GROUP_TIMER_SET(p)) {
+ if (CHECK_FLAG(p->flags, PEER_FLAG_TIMER)) {
vty_out(vty, " Configured hold time is %d",
p->holdtime);
vty_out(vty, ", keepalive interval is %d seconds\n",
"Peer group name\n")
{
char *vrf, *pg;
- vrf = pg = NULL;
int idx = 0;
vrf = argv_find(argv, argc, "VIEWVRFNAME", &idx) ? argv[idx]->arg
/* "bgp enforce-first-as" commands */
install_element(BGP_NODE, &bgp_enforce_first_as_cmd);
- install_element(BGP_NODE, &no_bgp_enforce_first_as_cmd);
/* "bgp bestpath compare-routerid" commands */
install_element(BGP_NODE, &bgp_bestpath_compare_router_id_cmd);
/* "neighbor description" commands. */
install_element(BGP_NODE, &neighbor_description_cmd);
install_element(BGP_NODE, &no_neighbor_description_cmd);
+ install_element(BGP_NODE, &no_neighbor_description_comment_cmd);
/* "neighbor update-source" commands. "*/
install_element(BGP_NODE, &neighbor_update_source_cmd);
stream_putl(s, bpa->fwmark);
stream_put(s, pbm->ipset_name,
ZEBRA_IPSET_NAME_SIZE);
+ stream_putw(s, pbm->pkt_len_min);
+ stream_putw(s, pbm->pkt_len_max);
+ stream_putw(s, pbm->tcp_flags);
+ stream_putw(s, pbm->tcp_mask_flags);
+ stream_putc(s, pbm->dscp_value);
+ stream_putc(s, pbm->fragment);
}
/* BGP has established connection with Zebra. */
== CHECK_FLAG(peer2->flags, PEER_FLAG_CONFIG_NODE));
}
+void peer_flag_inherit(struct peer *peer, uint32_t flag)
+{
+ bool group_val;
+
+ /* Skip if peer is not a peer-group member. */
+ if (!peer_group_active(peer))
+ return;
+
+ /* Unset override flag to signal inheritance from peer-group. */
+ UNSET_FLAG(peer->flags_override, flag);
+
+ /*
+ * Inherit flag state from peer-group. If the flag of the peer-group is
+ * not being inverted, the peer must inherit the inverse of the current
+ * peer-group flag state.
+ */
+ group_val = CHECK_FLAG(peer->group->conf->flags, flag);
+ if (!CHECK_FLAG(peer->group->conf->flags_invert, flag)
+ && CHECK_FLAG(peer->flags_invert, flag))
+ COND_FLAG(peer->flags, flag, !group_val);
+ else
+ COND_FLAG(peer->flags, flag, group_val);
+}
+
int peer_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, uint32_t flag)
{
return CHECK_FLAG(peer->af_flags[afi][safi], flag);
void peer_af_flag_inherit(struct peer *peer, afi_t afi, safi_t safi,
uint32_t flag)
{
+ bool group_val;
+
/* Skip if peer is not a peer-group member. */
if (!peer_group_active(peer))
return;
/* Unset override flag to signal inheritance from peer-group. */
UNSET_FLAG(peer->af_flags_override[afi][safi], flag);
- /* Inherit flag state from peer-group. */
- if (CHECK_FLAG(peer->group->conf->af_flags[afi][safi], flag))
- SET_FLAG(peer->af_flags[afi][safi], flag);
+ /*
+ * Inherit flag state from peer-group. If the flag of the peer-group is
+ * not being inverted, the peer must inherit the inverse of the current
+ * peer-group flag state.
+ */
+ group_val = CHECK_FLAG(peer->group->conf->af_flags[afi][safi], flag);
+ if (!CHECK_FLAG(peer->group->conf->af_flags_invert[afi][safi], flag)
+ && CHECK_FLAG(peer->af_flags_invert[afi][safi], flag))
+ COND_FLAG(peer->af_flags[afi][safi], flag, !group_val);
else
- UNSET_FLAG(peer->af_flags[afi][safi], flag);
+ COND_FLAG(peer->af_flags[afi][safi], flag, group_val);
+}
+
+static bool peergroup_flag_check(struct peer *peer, uint32_t flag)
+{
+ if (!peer_group_active(peer)) {
+ if (CHECK_FLAG(peer->flags_invert, flag))
+ return !CHECK_FLAG(peer->flags, flag);
+ else
+ return !!CHECK_FLAG(peer->flags, flag);
+ }
+
+ return !!CHECK_FLAG(peer->flags_override, flag);
}
static bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi,
peer->flags = 0;
SET_FLAG(peer->flags, saved_flags);
- peer->config = 0;
peer->holdtime = 0;
peer->keepalive = 0;
peer->connect = 0;
else {
struct peer *peer1;
+
+ assert(peer->group);
peer1 = listnode_head(peer->group->peer);
if (peer1)
/* peer flags apply */
peer_dst->flags = peer_src->flags;
peer_dst->cap = peer_src->cap;
- peer_dst->config = peer_src->config;
peer_dst->local_as = peer_src->local_as;
peer_dst->port = peer_src->port;
FOREACH_AFI_SAFI (afi, safi) {
peer_dst->afc[afi][safi] = peer_src->afc[afi][safi];
peer_dst->af_flags[afi][safi] = peer_src->af_flags[afi][safi];
- peer_dst->af_flags_invert[afi][safi] =
- peer_src->af_flags_invert[afi][safi];
peer_dst->allowas_in[afi][safi] =
peer_src->allowas_in[afi][safi];
peer_dst->weight[afi][safi] = peer_src->weight[afi][safi];
* needed.
*/
if (peer_addr_updated) {
- if (peer->password && prev_family == AF_UNSPEC)
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSWORD)
+ && prev_family == AF_UNSPEC)
bgp_md5_set(peer);
} else {
- if (peer->password && prev_family != AF_UNSPEC)
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSWORD)
+ && prev_family != AF_UNSPEC)
bgp_md5_unset(peer);
peer->su.sa.sa_family = AF_UNSPEC;
memset(&peer->su.sin6.sin6_addr, 0, sizeof(struct in6_addr));
peer->local_id = bgp->router_id;
peer->v_holdtime = bgp->default_holdtime;
peer->v_keepalive = bgp->default_keepalive;
- if (peer_sort(peer) == BGP_PEER_IBGP)
- peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
- else
- peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+ peer->v_routeadv = (peer_sort(peer) == BGP_PEER_IBGP)
+ ? BGP_DEFAULT_IBGP_ROUTEADV
+ : BGP_DEFAULT_EBGP_ROUTEADV;
peer = peer_lock(peer); /* bgp peer list reference */
peer->group = group;
void peer_as_change(struct peer *peer, as_t as, int as_specified)
{
bgp_peer_sort_t type;
- struct peer *conf;
/* Stop peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
peer->local_as = peer->bgp->as;
/* Advertisement-interval reset */
- conf = NULL;
- if (peer->group)
- conf = peer->group->conf;
-
- if (conf && CHECK_FLAG(conf->config, PEER_CONFIG_ROUTEADV)) {
- peer->v_routeadv = conf->routeadv;
- }
- /* Only go back to the default advertisement-interval if the user had
- * not
- * already configured it */
- else if (!CHECK_FLAG(peer->config, PEER_CONFIG_ROUTEADV)) {
- if (peer_sort(peer) == BGP_PEER_IBGP)
- peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
- else
- peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_ROUTEADV)) {
+ peer->v_routeadv = (peer_sort(peer) == BGP_PEER_IBGP)
+ ? BGP_DEFAULT_IBGP_ROUTEADV
+ : BGP_DEFAULT_EBGP_ROUTEADV;
}
+
/* TTL reset */
if (peer_sort(peer) == BGP_PEER_IBGP)
peer->ttl = MAXTTL;
/* local-as reset */
if (peer_sort(peer) != BGP_PEER_EBGP) {
peer->change_local_as = 0;
- UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ peer_flag_unset(peer, PEER_FLAG_LOCAL_AS);
+ peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+ peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS);
}
}
{
int in = FILTER_IN;
int out = FILTER_OUT;
+ uint32_t flags_tmp;
+ uint32_t pflags_ovrd;
+ uint8_t *pfilter_ovrd;
struct peer *conf;
- struct bgp_filter *pfilter;
- struct bgp_filter *gfilter;
conf = group->conf;
- pfilter = &peer->filter[afi][safi];
- gfilter = &conf->filter[afi][safi];
+ pflags_ovrd = peer->af_flags_override[afi][safi];
+ pfilter_ovrd = &peer->filter_override[afi][safi][in];
/* peer af_flags apply */
- peer->af_flags[afi][safi] = conf->af_flags[afi][safi];
- peer->af_flags_invert[afi][safi] = conf->af_flags_invert[afi][safi];
+ flags_tmp = conf->af_flags[afi][safi] & ~pflags_ovrd;
+ flags_tmp ^= conf->af_flags_invert[afi][safi]
+ ^ peer->af_flags_invert[afi][safi];
+ flags_tmp &= ~pflags_ovrd;
+
+ UNSET_FLAG(peer->af_flags[afi][safi], ~pflags_ovrd);
+ SET_FLAG(peer->af_flags[afi][safi], flags_tmp);
+ SET_FLAG(peer->af_flags_invert[afi][safi],
+ conf->af_flags_invert[afi][safi]);
/* maximum-prefix */
- peer->pmax[afi][safi] = conf->pmax[afi][safi];
- peer->pmax_threshold[afi][safi] = conf->pmax_threshold[afi][safi];
- peer->pmax_restart[afi][safi] = conf->pmax_restart[afi][safi];
+ if (!CHECK_FLAG(pflags_ovrd, PEER_FLAG_MAX_PREFIX)) {
+ PEER_ATTR_INHERIT(peer, group, pmax[afi][safi]);
+ PEER_ATTR_INHERIT(peer, group, pmax_threshold[afi][safi]);
+ PEER_ATTR_INHERIT(peer, group, pmax_restart[afi][safi]);
+ }
/* allowas-in */
- peer->allowas_in[afi][safi] = conf->allowas_in[afi][safi];
+ if (!CHECK_FLAG(pflags_ovrd, PEER_FLAG_ALLOWAS_IN))
+ PEER_ATTR_INHERIT(peer, group, allowas_in[afi][safi]);
/* weight */
- peer->weight[afi][safi] = conf->weight[afi][safi];
+ if (!CHECK_FLAG(pflags_ovrd, PEER_FLAG_WEIGHT))
+ PEER_ATTR_INHERIT(peer, group, weight[afi][safi]);
/* default-originate route-map */
- if (conf->default_rmap[afi][safi].name) {
- if (peer->default_rmap[afi][safi].name)
- XFREE(MTYPE_BGP_FILTER_NAME,
- peer->default_rmap[afi][safi].name);
- peer->default_rmap[afi][safi].name =
- XSTRDUP(MTYPE_BGP_FILTER_NAME,
- conf->default_rmap[afi][safi].name);
- peer->default_rmap[afi][safi].map =
- conf->default_rmap[afi][safi].map;
+ if (!CHECK_FLAG(pflags_ovrd, PEER_FLAG_DEFAULT_ORIGINATE)) {
+ PEER_STR_ATTR_INHERIT(peer, group, default_rmap[afi][safi].name,
+ MTYPE_ROUTE_MAP_NAME);
+ PEER_ATTR_INHERIT(peer, group, default_rmap[afi][safi].map);
}
/* inbound filter apply */
- if (gfilter->dlist[in].name && !pfilter->dlist[in].name) {
- if (pfilter->dlist[in].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->dlist[in].name);
- pfilter->dlist[in].name =
- XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->dlist[in].name);
- pfilter->dlist[in].alist = gfilter->dlist[in].alist;
+ if (!CHECK_FLAG(pfilter_ovrd[in], PEER_FT_DISTRIBUTE_LIST)) {
+ PEER_STR_ATTR_INHERIT(peer, group,
+ filter[afi][safi].dlist[in].name,
+ MTYPE_BGP_FILTER_NAME);
+ PEER_ATTR_INHERIT(peer, group,
+ filter[afi][safi].dlist[in].alist);
}
- if (gfilter->plist[in].name && !pfilter->plist[in].name) {
- if (pfilter->plist[in].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->plist[in].name);
- pfilter->plist[in].name =
- XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->plist[in].name);
- pfilter->plist[in].plist = gfilter->plist[in].plist;
+ if (!CHECK_FLAG(pfilter_ovrd[in], PEER_FT_PREFIX_LIST)) {
+ PEER_STR_ATTR_INHERIT(peer, group,
+ filter[afi][safi].plist[in].name,
+ MTYPE_BGP_FILTER_NAME);
+ PEER_ATTR_INHERIT(peer, group,
+ filter[afi][safi].plist[in].plist);
}
- if (gfilter->aslist[in].name && !pfilter->aslist[in].name) {
- if (pfilter->aslist[in].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->aslist[in].name);
- pfilter->aslist[in].name = XSTRDUP(MTYPE_BGP_FILTER_NAME,
- gfilter->aslist[in].name);
- pfilter->aslist[in].aslist = gfilter->aslist[in].aslist;
+ if (!CHECK_FLAG(pfilter_ovrd[in], PEER_FT_FILTER_LIST)) {
+ PEER_STR_ATTR_INHERIT(peer, group,
+ filter[afi][safi].aslist[in].name,
+ MTYPE_BGP_FILTER_NAME);
+ PEER_ATTR_INHERIT(peer, group,
+ filter[afi][safi].aslist[in].aslist);
}
- if (gfilter->map[RMAP_IN].name && !pfilter->map[RMAP_IN].name) {
- if (pfilter->map[RMAP_IN].name)
- XFREE(MTYPE_BGP_FILTER_NAME,
- pfilter->map[RMAP_IN].name);
- pfilter->map[RMAP_IN].name = XSTRDUP(
- MTYPE_BGP_FILTER_NAME, gfilter->map[RMAP_IN].name);
- pfilter->map[RMAP_IN].map = gfilter->map[RMAP_IN].map;
+ if (!CHECK_FLAG(pfilter_ovrd[RMAP_IN], PEER_FT_ROUTE_MAP)) {
+ PEER_STR_ATTR_INHERIT(peer, group,
+ filter[afi][safi].map[in].name,
+ MTYPE_BGP_FILTER_NAME);
+ PEER_ATTR_INHERIT(peer, group,
+ filter[afi][safi].map[RMAP_IN].map);
}
/* outbound filter apply */
- if (gfilter->dlist[out].name) {
- if (pfilter->dlist[out].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->dlist[out].name);
- pfilter->dlist[out].name = XSTRDUP(MTYPE_BGP_FILTER_NAME,
- gfilter->dlist[out].name);
- pfilter->dlist[out].alist = gfilter->dlist[out].alist;
- } else {
- if (pfilter->dlist[out].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->dlist[out].name);
- pfilter->dlist[out].name = NULL;
- pfilter->dlist[out].alist = NULL;
- }
-
- if (gfilter->plist[out].name) {
- if (pfilter->plist[out].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->plist[out].name);
- pfilter->plist[out].name = XSTRDUP(MTYPE_BGP_FILTER_NAME,
- gfilter->plist[out].name);
- pfilter->plist[out].plist = gfilter->plist[out].plist;
- } else {
- if (pfilter->plist[out].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->plist[out].name);
- pfilter->plist[out].name = NULL;
- pfilter->plist[out].plist = NULL;
- }
-
- if (gfilter->aslist[out].name) {
- if (pfilter->aslist[out].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->aslist[out].name);
- pfilter->aslist[out].name = XSTRDUP(MTYPE_BGP_FILTER_NAME,
- gfilter->aslist[out].name);
- pfilter->aslist[out].aslist = gfilter->aslist[out].aslist;
- } else {
- if (pfilter->aslist[out].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->aslist[out].name);
- pfilter->aslist[out].name = NULL;
- pfilter->aslist[out].aslist = NULL;
+ if (!CHECK_FLAG(pfilter_ovrd[out], PEER_FT_DISTRIBUTE_LIST)) {
+ PEER_STR_ATTR_INHERIT(peer, group,
+ filter[afi][safi].dlist[out].name,
+ MTYPE_BGP_FILTER_NAME);
+ PEER_ATTR_INHERIT(peer, group,
+ filter[afi][safi].dlist[out].alist);
}
- if (gfilter->map[RMAP_OUT].name) {
- if (pfilter->map[RMAP_OUT].name)
- XFREE(MTYPE_BGP_FILTER_NAME,
- pfilter->map[RMAP_OUT].name);
- pfilter->map[RMAP_OUT].name = XSTRDUP(
- MTYPE_BGP_FILTER_NAME, gfilter->map[RMAP_OUT].name);
- pfilter->map[RMAP_OUT].map = gfilter->map[RMAP_OUT].map;
- } else {
- if (pfilter->map[RMAP_OUT].name)
- XFREE(MTYPE_BGP_FILTER_NAME,
- pfilter->map[RMAP_OUT].name);
- pfilter->map[RMAP_OUT].name = NULL;
- pfilter->map[RMAP_OUT].map = NULL;
+ if (!CHECK_FLAG(pfilter_ovrd[out], PEER_FT_PREFIX_LIST)) {
+ PEER_STR_ATTR_INHERIT(peer, group,
+ filter[afi][safi].plist[out].name,
+ MTYPE_BGP_FILTER_NAME);
+ PEER_ATTR_INHERIT(peer, group,
+ filter[afi][safi].plist[out].plist);
}
- if (gfilter->usmap.name) {
- if (pfilter->usmap.name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->usmap.name);
- pfilter->usmap.name =
- XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->usmap.name);
- pfilter->usmap.map = gfilter->usmap.map;
- } else {
- if (pfilter->usmap.name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->usmap.name);
- pfilter->usmap.name = NULL;
- pfilter->usmap.map = NULL;
+ if (!CHECK_FLAG(pfilter_ovrd[out], PEER_FT_FILTER_LIST)) {
+ PEER_STR_ATTR_INHERIT(peer, group,
+ filter[afi][safi].aslist[out].name,
+ MTYPE_BGP_FILTER_NAME);
+ PEER_ATTR_INHERIT(peer, group,
+ filter[afi][safi].aslist[out].aslist);
+ }
+
+ if (!CHECK_FLAG(pfilter_ovrd[RMAP_OUT], PEER_FT_ROUTE_MAP)) {
+ PEER_STR_ATTR_INHERIT(peer, group,
+ filter[afi][safi].map[RMAP_OUT].name,
+ MTYPE_BGP_FILTER_NAME);
+ PEER_ATTR_INHERIT(peer, group,
+ filter[afi][safi].map[RMAP_OUT].map);
+ }
+
+ /* nondirectional filter apply */
+ if (!CHECK_FLAG(pfilter_ovrd[0], PEER_FT_UNSUPPRESS_MAP)) {
+ PEER_STR_ATTR_INHERIT(peer, group, filter[afi][safi].usmap.name,
+ MTYPE_BGP_FILTER_NAME);
+ PEER_ATTR_INHERIT(peer, group, filter[afi][safi].usmap.map);
}
}
bgp_unlink_nexthop_by_peer(peer);
/* Password configuration */
- if (peer->password) {
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSWORD)) {
XFREE(MTYPE_PEER_PASSWORD, peer->password);
- peer->password = NULL;
if (!accept_peer && !BGP_PEER_SU_UNSPEC(peer)
&& !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
group->conf->ttl = 1;
group->conf->gtsm_hops = 0;
group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
- UNSET_FLAG(group->conf->config, PEER_CONFIG_TIMER);
- UNSET_FLAG(group->conf->config, PEER_GROUP_CONFIG_TIMER);
- UNSET_FLAG(group->conf->config, PEER_CONFIG_CONNECT);
- group->conf->keepalive = 0;
- group->conf->holdtime = 0;
- group->conf->connect = 0;
SET_FLAG(group->conf->sflags, PEER_STATUS_GROUP);
listnode_add_sort(bgp->group, group);
static void peer_group2peer_config_copy(struct peer_group *group,
struct peer *peer)
{
+ uint32_t flags_tmp;
struct peer *conf;
- int saved_flags = 0;
conf = group->conf;
if (conf->as)
peer->as = conf->as;
- /* remote-as */
- if (conf->change_local_as)
+ /* local-as */
+ if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_LOCAL_AS))
peer->change_local_as = conf->change_local_as;
/* TTL */
/* GTSM hops */
peer->gtsm_hops = conf->gtsm_hops;
- /* These are per-peer specific flags and so we must preserve them */
- saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
- saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN);
- peer->flags = conf->flags;
- SET_FLAG(peer->flags, saved_flags);
+ /* peer flags apply */
+ flags_tmp = conf->flags & ~peer->flags_override;
+ flags_tmp ^= conf->flags_invert ^ peer->flags_invert;
+ flags_tmp &= ~peer->flags_override;
- /* peer config apply */
- peer->config = conf->config;
+ UNSET_FLAG(peer->flags, ~peer->flags_override);
+ SET_FLAG(peer->flags, flags_tmp);
+ SET_FLAG(peer->flags_invert, conf->flags_invert);
/* peer timers apply */
- peer->holdtime = conf->holdtime;
- peer->keepalive = conf->keepalive;
- peer->connect = conf->connect;
- if (CHECK_FLAG(conf->config, PEER_CONFIG_CONNECT))
- peer->v_connect = conf->connect;
- else
- peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+ if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_TIMER)) {
+ PEER_ATTR_INHERIT(peer, group, holdtime);
+ PEER_ATTR_INHERIT(peer, group, keepalive);
+ }
- /* advertisement-interval reset */
- if (CHECK_FLAG(conf->config, PEER_CONFIG_ROUTEADV))
- peer->v_routeadv = conf->routeadv;
- else if (peer_sort(peer) == BGP_PEER_IBGP)
- peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
- else
- peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+ if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_TIMER_CONNECT)) {
+ PEER_ATTR_INHERIT(peer, group, connect);
+ if (CHECK_FLAG(conf->flags, PEER_FLAG_TIMER_CONNECT))
+ peer->v_connect = conf->connect;
+ else
+ peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+ }
+
+ /* advertisement-interval apply */
+ if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_ROUTEADV)) {
+ PEER_ATTR_INHERIT(peer, group, routeadv);
+ if (CHECK_FLAG(conf->flags, PEER_FLAG_ROUTEADV))
+ peer->v_routeadv = conf->routeadv;
+ else
+ peer->v_routeadv = (peer_sort(peer) == BGP_PEER_IBGP)
+ ? BGP_DEFAULT_IBGP_ROUTEADV
+ : BGP_DEFAULT_EBGP_ROUTEADV;
+ }
/* password apply */
- if (conf->password && !peer->password)
- peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, conf->password);
+ if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_PASSWORD))
+ PEER_STR_ATTR_INHERIT(peer, group, password,
+ MTYPE_PEER_PASSWORD);
if (!BGP_PEER_SU_UNSPEC(peer))
bgp_md5_set(peer);
/* update-source apply */
- if (conf->update_source) {
- if (peer->update_source)
- sockunion_free(peer->update_source);
- if (peer->update_if) {
+ if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_UPDATE_SOURCE)) {
+ if (conf->update_source) {
XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
- }
- peer->update_source = sockunion_dup(conf->update_source);
- } else if (conf->update_if) {
- if (peer->update_if)
- XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- if (peer->update_source) {
+ PEER_SU_ATTR_INHERIT(peer, group, update_source);
+ } else if (conf->update_if) {
sockunion_free(peer->update_source);
- peer->update_source = NULL;
+ PEER_STR_ATTR_INHERIT(peer, group, update_if,
+ MTYPE_PEER_UPDATE_SOURCE);
}
- peer->update_if =
- XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, conf->update_if);
}
bgp_bfd_peer_group2peer_copy(conf, peer);
int first_member = 0;
afi_t afi;
safi_t safi;
- int cap_enhe_preset = 0;
/* Lookup the peer. */
if (!peer)
first_member = 1;
}
- if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE))
- cap_enhe_preset = 1;
-
peer_group2peer_config_copy(group, peer);
- /*
- * Capability extended-nexthop is enabled for an interface
- * neighbor by
- * default. So, fix that up here.
- */
- if (peer->conf_if && cap_enhe_preset)
- peer_flag_set(peer, PEER_FLAG_CAPABILITY_ENHE);
-
FOREACH_AFI_SAFI (afi, safi) {
if (group->conf->afc[afi][safi]) {
peer->afc[afi][safi] = 1;
if (peer->group) {
assert(group && peer->group == group);
} else {
- struct listnode *pn;
- pn = listnode_lookup(bgp->peer, peer);
- list_delete_node(bgp->peer, pn);
+ listnode_delete(bgp->peer, peer);
+
peer->group = group;
listnode_add_sort(bgp->peer, peer);
if (first_member) {
/* Advertisement-interval reset */
- if (!CHECK_FLAG(group->conf->config,
- PEER_CONFIG_ROUTEADV)) {
- if (peer_sort(group->conf) == BGP_PEER_IBGP)
- group->conf->v_routeadv =
- BGP_DEFAULT_IBGP_ROUTEADV;
- else
- group->conf->v_routeadv =
- BGP_DEFAULT_EBGP_ROUTEADV;
+ if (!CHECK_FLAG(group->conf->flags,
+ PEER_FLAG_ROUTEADV)) {
+ group->conf->v_routeadv =
+ (peer_sort(group->conf)
+ == BGP_PEER_IBGP)
+ ? BGP_DEFAULT_IBGP_ROUTEADV
+ : BGP_DEFAULT_EBGP_ROUTEADV;
}
/* ebgp-multihop reset */
/* local-as reset */
if (peer_sort(group->conf) != BGP_PEER_EBGP) {
group->conf->change_local_as = 0;
- UNSET_FLAG(peer->flags,
- PEER_FLAG_LOCAL_AS_NO_PREPEND);
- UNSET_FLAG(peer->flags,
- PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ peer_flag_unset(group->conf,
+ PEER_FLAG_LOCAL_AS);
+ peer_flag_unset(group->conf,
+ PEER_FLAG_LOCAL_AS_NO_PREPEND);
+ peer_flag_unset(group->conf,
+ PEER_FLAG_LOCAL_AS_REPLACE_AS);
}
}
{PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset},
{PEER_FLAG_CAPABILITY_ENHE, 0, peer_change_reset},
{PEER_FLAG_ENFORCE_FIRST_AS, 0, peer_change_reset_in},
+ {PEER_FLAG_ROUTEADV, 0, peer_change_none},
+ {PEER_FLAG_TIMER, 0, peer_change_none},
+ {PEER_FLAG_TIMER_CONNECT, 0, peer_change_none},
+ {PEER_FLAG_PASSWORD, 0, peer_change_none},
+ {PEER_FLAG_LOCAL_AS, 0, peer_change_none},
+ {PEER_FLAG_LOCAL_AS_NO_PREPEND, 0, peer_change_none},
+ {PEER_FLAG_LOCAL_AS_REPLACE_AS, 0, peer_change_none},
+ {PEER_FLAG_UPDATE_SOURCE, 0, peer_change_none},
{0, 0, 0}};
static const struct peer_flag_action peer_af_flag_action_list[] = {
{
int found;
int size;
- struct peer_group *group;
- struct peer *tmp_peer;
+ bool invert, member_invert;
+ struct peer *member;
struct listnode *node, *nnode;
struct peer_flag_action action;
memset(&action, 0, sizeof(struct peer_flag_action));
size = sizeof peer_flag_action_list / sizeof(struct peer_flag_action);
+ invert = CHECK_FLAG(peer->flags_invert, flag);
found = peer_flag_action_set(peer_flag_action_list, size, &action,
flag);
- /* No flag action is found. */
+ /* Abort if no flag action exists. */
if (!found)
return BGP_ERR_INVALID_FLAG;
- /* When unset the peer-group member's flag we have to check
- peer-group configuration. */
- if (!set && peer_group_active(peer))
- if (CHECK_FLAG(peer->group->conf->flags, flag)) {
- if (flag == PEER_FLAG_SHUTDOWN)
- return BGP_ERR_PEER_GROUP_SHUTDOWN;
- }
-
- /* Flag conflict check. */
+ /* Check for flag conflict: STRICT_CAP_MATCH && OVERRIDE_CAPABILITY */
if (set && CHECK_FLAG(peer->flags | flag, PEER_FLAG_STRICT_CAP_MATCH)
&& CHECK_FLAG(peer->flags | flag, PEER_FLAG_OVERRIDE_CAPABILITY))
return BGP_ERR_PEER_FLAG_CONFLICT;
+ /* Handle flag updates where desired state matches current state. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- if (set && CHECK_FLAG(peer->flags, flag) == flag)
+ if (set && CHECK_FLAG(peer->flags, flag)) {
+ COND_FLAG(peer->flags_override, flag, !invert);
return 0;
- if (!set && !CHECK_FLAG(peer->flags, flag))
+ }
+
+ if (!set && !CHECK_FLAG(peer->flags, flag)) {
+ COND_FLAG(peer->flags_override, flag, invert);
return 0;
+ }
}
- if (set)
- SET_FLAG(peer->flags, flag);
+ /* Inherit from peer-group or set/unset flags accordingly. */
+ if (peer_group_active(peer) && set == invert)
+ peer_flag_inherit(peer, flag);
else
- UNSET_FLAG(peer->flags, flag);
+ COND_FLAG(peer->flags, flag, set);
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Update flag override state accordingly. */
+ COND_FLAG(peer->flags_override, flag, set != invert);
+
+ /* Execute flag action on peer. */
if (action.type == peer_change_reset)
peer_flag_modify_action(peer, flag);
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- /* peer-group member updates. */
- group = peer->group;
+ /*
+ * Update peer-group members, unless they are explicitely overriding
+ * peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->flags_override, flag))
+ continue;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) {
+ /* Check if only member without group is inverted. */
+ member_invert =
+ CHECK_FLAG(member->flags_invert, flag) && !invert;
- if (set && CHECK_FLAG(tmp_peer->flags, flag) == flag)
+ /* Skip peers with equivalent configuration. */
+ if (set != member_invert && CHECK_FLAG(member->flags, flag))
continue;
- if (!set && !CHECK_FLAG(tmp_peer->flags, flag))
+ if (set == member_invert && !CHECK_FLAG(member->flags, flag))
continue;
- if (set)
- SET_FLAG(tmp_peer->flags, flag);
- else
- UNSET_FLAG(tmp_peer->flags, flag);
+ /* Update flag on peer-group member. */
+ COND_FLAG(member->flags, flag, set != member_invert);
+ /* Execute flag action on peer-group member. */
if (action.type == peer_change_reset)
- peer_flag_modify_action(tmp_peer, flag);
+ peer_flag_modify_action(member, flag);
}
+
return 0;
}
int found;
int size;
int addpath_tx_used;
- bool invert;
+ bool invert, member_invert;
+ struct bgp *bgp;
+ struct peer *member;
struct listnode *node, *nnode;
- struct peer_group *group;
struct peer_flag_action action;
- struct peer *tmp_peer;
- struct bgp *bgp;
memset(&action, 0, sizeof(struct peer_flag_action));
size = sizeof peer_af_flag_action_list
found = peer_flag_action_set(peer_af_flag_action_list, size, &action,
flag);
- /* No flag action is found. */
+ /* Abort if flag action exists. */
if (!found)
return BGP_ERR_INVALID_FLAG;
if (flag & PEER_FLAG_AS_OVERRIDE && peer_sort(peer) == BGP_PEER_IBGP)
return BGP_ERR_AS_OVERRIDE;
- /* When current flag configuration is same as requested one. */
+ /* Handle flag updates where desired state matches current state. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
if (set && CHECK_FLAG(peer->af_flags[afi][safi], flag)) {
- if (invert)
- UNSET_FLAG(peer->af_flags_override[afi][safi],
- flag);
- else
- SET_FLAG(peer->af_flags_override[afi][safi],
- flag);
+ COND_FLAG(peer->af_flags_override[afi][safi], flag,
+ !invert);
return 0;
}
if (!set && !CHECK_FLAG(peer->af_flags[afi][safi], flag)) {
- if (invert)
- SET_FLAG(peer->af_flags_override[afi][safi],
- flag);
- else
- UNSET_FLAG(peer->af_flags_override[afi][safi],
- flag);
+ COND_FLAG(peer->af_flags_override[afi][safi], flag,
+ invert);
return 0;
}
}
}
}
- /* Set/unset flag or inherit from peer-group if appropriate. */
- if (invert) {
- if (!set)
- UNSET_FLAG(peer->af_flags[afi][safi], flag);
- else if (peer_group_active(peer))
- peer_af_flag_inherit(peer, afi, safi, flag);
- else
- SET_FLAG(peer->af_flags[afi][safi], flag);
- } else {
- if (set)
- SET_FLAG(peer->af_flags[afi][safi], flag);
- else if (peer_group_active(peer))
- peer_af_flag_inherit(peer, afi, safi, flag);
- else
- UNSET_FLAG(peer->af_flags[afi][safi], flag);
- }
+ /* Inherit from peer-group or set/unset flags accordingly. */
+ if (peer_group_active(peer) && set == invert)
+ peer_af_flag_inherit(peer, afi, safi, flag);
+ else
+ COND_FLAG(peer->af_flags[afi][safi], flag, set);
/* Execute action when peer is established. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
}
}
- /* Peer group member updates. */
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) {
- if (CHECK_FLAG(tmp_peer->af_flags_override[afi][safi],
+ /* Check if handling a regular peer. */
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ COND_FLAG(peer->af_flags_override[afi][safi], flag,
+ set != invert);
+ } else {
+ /*
+ * Update peer-group members, unless they are explicitely
+ * overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode,
+ member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->af_flags_override[afi][safi],
flag))
continue;
- if (set
- && CHECK_FLAG(tmp_peer->af_flags[afi][safi], flag))
+ /* Check if only member without group is inverted. */
+ member_invert =
+ CHECK_FLAG(member->af_flags_invert[afi][safi],
+ flag)
+ && !invert;
+
+ /* Skip peers with equivalent configuration. */
+ if (set != member_invert
+ && CHECK_FLAG(member->af_flags[afi][safi], flag))
continue;
- if (!set
- && !CHECK_FLAG(tmp_peer->af_flags[afi][safi], flag))
+ if (set == member_invert
+ && !CHECK_FLAG(member->af_flags[afi][safi], flag))
continue;
- if (set)
- SET_FLAG(tmp_peer->af_flags[afi][safi], flag);
- else
- UNSET_FLAG(tmp_peer->af_flags[afi][safi], flag);
+ /* Update flag on peer-group member. */
+ COND_FLAG(member->af_flags[afi][safi], flag,
+ set != member_invert);
- if (tmp_peer->status == Established) {
+ /* Execute flag action on peer-group member. */
+ if (member->status == Established) {
if (!set && flag == PEER_FLAG_SOFT_RECONFIG)
- bgp_clear_adj_in(tmp_peer, afi, safi);
+ bgp_clear_adj_in(member, afi, safi);
else {
if (flag == PEER_FLAG_REFLECTOR_CLIENT)
- tmp_peer->last_reset =
+ member->last_reset =
PEER_DOWN_RR_CLIENT_CHANGE;
else if (flag
== PEER_FLAG_RSERVER_CLIENT)
- tmp_peer->last_reset =
+ member->last_reset =
PEER_DOWN_RS_CLIENT_CHANGE;
else if (flag
== PEER_FLAG_ORF_PREFIX_SM)
- tmp_peer->last_reset =
+ member->last_reset =
PEER_DOWN_CAPABILITY_CHANGE;
else if (flag
== PEER_FLAG_ORF_PREFIX_RM)
- tmp_peer->last_reset =
+ member->last_reset =
PEER_DOWN_CAPABILITY_CHANGE;
- peer_change_action(tmp_peer, afi, safi,
+ peer_change_action(member, afi, safi,
action.type);
}
}
}
- } else {
- if (set != invert)
- SET_FLAG(peer->af_flags_override[afi][safi], flag);
- else
- UNSET_FLAG(peer->af_flags_override[afi][safi], flag);
}
/* Track if addpath TX is in use */
}
} else {
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode,
- tmp_peer)) {
- if (CHECK_FLAG(tmp_peer->af_flags[afi][safi],
+ member)) {
+ if (CHECK_FLAG(member->af_flags[afi][safi],
PEER_FLAG_ADDPATH_TX_ALL_PATHS)
|| CHECK_FLAG(
- tmp_peer->af_flags[afi][safi],
+ member->af_flags[afi][safi],
PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS)) {
addpath_tx_used = 1;
break;
/* Neighbor update-source. */
int peer_update_source_if_set(struct peer *peer, const char *ifname)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
+ /* Set flag and configuration on peer. */
+ peer_flag_set(peer, PEER_FLAG_UPDATE_SOURCE);
if (peer->update_if) {
- if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
- && strcmp(peer->update_if, ifname) == 0)
+ if (strcmp(peer->update_if, ifname) == 0)
return 0;
-
XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
- }
-
- if (peer->update_source) {
- sockunion_free(peer->update_source);
- peer->update_source = NULL;
}
-
peer->update_if = XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, ifname);
+ sockunion_free(peer->update_source);
+ peer->update_source = NULL;
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Send notification or reset peer depending on state. */
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
} else
bgp_session_reset(peer);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- if (peer->update_if) {
- if (strcmp(peer->update_if, ifname) == 0)
- continue;
-
- XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
- }
+ /*
+ * Set flag and configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->flags_override, PEER_FLAG_UPDATE_SOURCE))
+ continue;
- if (peer->update_source) {
- sockunion_free(peer->update_source);
- peer->update_source = NULL;
+ /* Skip peers with the same configuration. */
+ if (member->update_if) {
+ if (strcmp(member->update_if, ifname) == 0)
+ continue;
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if);
}
- peer->update_if = XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, ifname);
-
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ /* Set flag and configuration on peer-group member. */
+ SET_FLAG(member->flags, PEER_FLAG_UPDATE_SOURCE);
+ member->update_if = XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, ifname);
+ sockunion_free(member->update_source);
+ member->update_source = NULL;
+
+ /* Send notification or reset peer depending on state. */
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) {
+ member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
+ bgp_notify_send(member, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
} else
- bgp_session_reset(peer);
+ bgp_session_reset(member);
}
+
return 0;
}
int peer_update_source_addr_set(struct peer *peer, const union sockunion *su)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
+ /* Set flag and configuration on peer. */
+ peer_flag_set(peer, PEER_FLAG_UPDATE_SOURCE);
if (peer->update_source) {
- if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
- && sockunion_cmp(peer->update_source, su) == 0)
+ if (sockunion_cmp(peer->update_source, su) == 0)
return 0;
sockunion_free(peer->update_source);
- peer->update_source = NULL;
- }
-
- if (peer->update_if) {
- XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
}
-
peer->update_source = sockunion_dup(su);
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Send notification or reset peer depending on state. */
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
} else
bgp_session_reset(peer);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- if (peer->update_source) {
- if (sockunion_cmp(peer->update_source, su) == 0)
- continue;
- sockunion_free(peer->update_source);
- peer->update_source = NULL;
- }
+ /*
+ * Set flag and configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->flags_override, PEER_FLAG_UPDATE_SOURCE))
+ continue;
- if (peer->update_if) {
- XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
+ /* Skip peers with the same configuration. */
+ if (member->update_source) {
+ if (sockunion_cmp(member->update_source, su) == 0)
+ continue;
+ sockunion_free(member->update_source);
}
- peer->update_source = sockunion_dup(su);
-
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ /* Set flag and configuration on peer-group member. */
+ SET_FLAG(member->flags, PEER_FLAG_UPDATE_SOURCE);
+ member->update_source = sockunion_dup(su);
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if);
+
+ /* Send notification or reset peer depending on state. */
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) {
+ member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
+ bgp_notify_send(member, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
} else
- bgp_session_reset(peer);
+ bgp_session_reset(member);
}
+
return 0;
}
int peer_update_source_unset(struct peer *peer)
{
- union sockunion *su;
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
- if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) && !peer->update_source
- && !peer->update_if)
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_UPDATE_SOURCE))
return 0;
- if (peer->update_source) {
+ /* Inherit configuration from peer-group if peer is member. */
+ if (peer_group_active(peer)) {
+ peer_flag_inherit(peer, PEER_FLAG_UPDATE_SOURCE);
+ PEER_SU_ATTR_INHERIT(peer, peer->group, update_source);
+ PEER_STR_ATTR_INHERIT(peer, peer->group, update_if,
+ MTYPE_PEER_UPDATE_SOURCE);
+ } else {
+ /* Otherwise remove flag and configuration from peer. */
+ peer_flag_unset(peer, PEER_FLAG_UPDATE_SOURCE);
sockunion_free(peer->update_source);
peer->update_source = NULL;
- }
- if (peer->update_if) {
XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
- }
-
- if (peer_group_active(peer)) {
- group = peer->group;
-
- if (group->conf->update_source) {
- su = sockunion_dup(group->conf->update_source);
- peer->update_source = su;
- } else if (group->conf->update_if)
- peer->update_if = XSTRDUP(MTYPE_PEER_UPDATE_SOURCE,
- group->conf->update_if);
}
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Send notification or reset peer depending on state. */
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
} else
bgp_session_reset(peer);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- if (!peer->update_source && !peer->update_if)
+ /*
+ * Set flag and configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->flags_override, PEER_FLAG_UPDATE_SOURCE))
continue;
- if (peer->update_source) {
- sockunion_free(peer->update_source);
- peer->update_source = NULL;
- }
-
- if (peer->update_if) {
- XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
- }
+ /* Skip peers with the same configuration. */
+ if (!CHECK_FLAG(member->flags, PEER_FLAG_UPDATE_SOURCE)
+ && !member->update_source && !member->update_if)
+ continue;
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ /* Remove flag and configuration on peer-group member. */
+ UNSET_FLAG(member->flags, PEER_FLAG_UPDATE_SOURCE);
+ sockunion_free(member->update_source);
+ member->update_source = NULL;
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if);
+
+ /* Send notification or reset peer depending on state. */
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) {
+ member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
+ bgp_notify_send(member, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
} else
- bgp_session_reset(peer);
+ bgp_session_reset(member);
}
+
return 0;
}
if (peer_group_active(peer)) {
peer_af_flag_inherit(peer, afi, safi,
PEER_FLAG_DEFAULT_ORIGINATE);
- PEER_STR_ATTR_INHERIT(MTYPE_ROUTE_MAP_NAME, peer,
- default_rmap[afi][safi].name);
- PEER_ATTR_INHERIT(peer, default_rmap[afi][safi].map);
+ PEER_STR_ATTR_INHERIT(peer, peer->group,
+ default_rmap[afi][safi].name,
+ MTYPE_ROUTE_MAP_NAME);
+ PEER_ATTR_INHERIT(peer, peer->group,
+ default_rmap[afi][safi].map);
} else {
/* Otherwise remove flag and configuration from peer. */
peer_af_flag_unset(peer, afi, safi,
/* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
peer_af_flag_inherit(peer, afi, safi, PEER_FLAG_WEIGHT);
- PEER_ATTR_INHERIT(peer, weight[afi][safi]);
+ PEER_ATTR_INHERIT(peer, peer->group, weight[afi][safi]);
peer_on_policy_change(peer, afi, safi, 0);
return 0;
int peer_timers_set(struct peer *peer, uint32_t keepalive, uint32_t holdtime)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
- /* keepalive value check. */
if (keepalive > 65535)
return BGP_ERR_INVALID_VALUE;
- /* Holdtime value check. */
if (holdtime > 65535)
return BGP_ERR_INVALID_VALUE;
- /* Holdtime value must be either 0 or greater than 3. */
if (holdtime < 3 && holdtime != 0)
return BGP_ERR_INVALID_VALUE;
- /* Set value to the configuration. */
+ /* Set flag and configuration on peer. */
+ peer_flag_set(peer, PEER_FLAG_TIMER);
peer->holdtime = holdtime;
peer->keepalive = (keepalive < holdtime / 3 ? keepalive : holdtime / 3);
- /* First work on real peers with timers */
- if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- SET_FLAG(peer->config, PEER_CONFIG_TIMER);
- UNSET_FLAG(peer->config, PEER_GROUP_CONFIG_TIMER);
- } else {
- /* Now work on the peer-group timers */
- SET_FLAG(peer->config, PEER_GROUP_CONFIG_TIMER);
+ /* Skip peer-group mechanics for regular peers. */
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return 0;
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- /* Skip peers that have their own timers */
- if (CHECK_FLAG(peer->config, PEER_CONFIG_TIMER))
- continue;
+ /*
+ * Set flag and configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->flags_override, PEER_FLAG_TIMER))
+ continue;
- SET_FLAG(peer->config, PEER_GROUP_CONFIG_TIMER);
- peer->holdtime = group->conf->holdtime;
- peer->keepalive = group->conf->keepalive;
- }
+ /* Set flag and configuration on peer-group member. */
+ SET_FLAG(member->flags, PEER_FLAG_TIMER);
+ PEER_ATTR_INHERIT(peer, peer->group, holdtime);
+ PEER_ATTR_INHERIT(peer, peer->group, keepalive);
}
return 0;
int peer_timers_unset(struct peer *peer)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
- /* First work on real peers vs the peer-group */
- if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- UNSET_FLAG(peer->config, PEER_CONFIG_TIMER);
- peer->keepalive = 0;
- peer->holdtime = 0;
-
- if (peer->group && peer->group->conf->holdtime) {
- SET_FLAG(peer->config, PEER_GROUP_CONFIG_TIMER);
- peer->keepalive = peer->group->conf->keepalive;
- peer->holdtime = peer->group->conf->holdtime;
- }
+ /* Inherit configuration from peer-group if peer is member. */
+ if (peer_group_active(peer)) {
+ peer_flag_inherit(peer, PEER_FLAG_TIMER);
+ PEER_ATTR_INHERIT(peer, peer->group, holdtime);
+ PEER_ATTR_INHERIT(peer, peer->group, keepalive);
} else {
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- if (!CHECK_FLAG(peer->config, PEER_CONFIG_TIMER)) {
- UNSET_FLAG(peer->config,
- PEER_GROUP_CONFIG_TIMER);
- peer->holdtime = 0;
- peer->keepalive = 0;
- }
- }
+ /* Otherwise remove flag and configuration from peer. */
+ peer_flag_unset(peer, PEER_FLAG_TIMER);
+ peer->holdtime = 0;
+ peer->keepalive = 0;
+ }
+
+ /* Skip peer-group mechanics for regular peers. */
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return 0;
+
+ /*
+ * Remove flag and configuration from all peer-group members, unless
+ * they are explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->flags_override, PEER_FLAG_TIMER))
+ continue;
- UNSET_FLAG(group->conf->config, PEER_GROUP_CONFIG_TIMER);
- group->conf->holdtime = 0;
- group->conf->keepalive = 0;
+ /* Remove flag and configuration on peer-group member. */
+ UNSET_FLAG(member->flags, PEER_FLAG_TIMER);
+ member->holdtime = 0;
+ member->keepalive = 0;
}
return 0;
int peer_timers_connect_set(struct peer *peer, uint32_t connect)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
if (connect > 65535)
return BGP_ERR_INVALID_VALUE;
- /* Set value to the configuration. */
- SET_FLAG(peer->config, PEER_CONFIG_CONNECT);
+ /* Set flag and configuration on peer. */
+ peer_flag_set(peer, PEER_FLAG_TIMER_CONNECT);
peer->connect = connect;
-
- /* Set value to timer setting. */
peer->v_connect = connect;
+ /* Skip peer-group mechanics for regular peers. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
return 0;
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- SET_FLAG(peer->config, PEER_CONFIG_CONNECT);
- peer->connect = connect;
- peer->v_connect = connect;
+ /*
+ * Set flag and configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->flags_override, PEER_FLAG_TIMER_CONNECT))
+ continue;
+
+ /* Set flag and configuration on peer-group member. */
+ SET_FLAG(member->flags, PEER_FLAG_TIMER_CONNECT);
+ member->connect = connect;
+ member->v_connect = connect;
}
+
return 0;
}
int peer_timers_connect_unset(struct peer *peer)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
- /* Clear configuration. */
- UNSET_FLAG(peer->config, PEER_CONFIG_CONNECT);
- peer->connect = 0;
+ /* Inherit configuration from peer-group if peer is member. */
+ if (peer_group_active(peer)) {
+ peer_flag_inherit(peer, PEER_FLAG_TIMER_CONNECT);
+ PEER_ATTR_INHERIT(peer, peer->group, connect);
+ } else {
+ /* Otherwise remove flag and configuration from peer. */
+ peer_flag_unset(peer, PEER_FLAG_TIMER_CONNECT);
+ peer->connect = 0;
+ }
- /* Set timer setting to default value. */
- peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+ /* Set timer with fallback to default value. */
+ if (peer->connect)
+ peer->v_connect = peer->connect;
+ else
+ peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+ /* Skip peer-group mechanics for regular peers. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
return 0;
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- UNSET_FLAG(peer->config, PEER_CONFIG_CONNECT);
- peer->connect = 0;
- peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+ /*
+ * Remove flag and configuration from all peer-group members, unless
+ * they are explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->flags_override, PEER_FLAG_TIMER_CONNECT))
+ continue;
+
+ /* Remove flag and configuration on peer-group member. */
+ UNSET_FLAG(member->flags, PEER_FLAG_TIMER_CONNECT);
+ member->connect = 0;
+ member->v_connect = BGP_DEFAULT_CONNECT_RETRY;
}
+
return 0;
}
int peer_advertise_interval_set(struct peer *peer, uint32_t routeadv)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
if (routeadv > 600)
return BGP_ERR_INVALID_VALUE;
- SET_FLAG(peer->config, PEER_CONFIG_ROUTEADV);
+ /* Set flag and configuration on peer. */
+ peer_flag_set(peer, PEER_FLAG_ROUTEADV);
peer->routeadv = routeadv;
peer->v_routeadv = routeadv;
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Update peer route announcements. */
update_group_adjust_peer_afs(peer);
if (peer->status == Established)
bgp_announce_route_all(peer);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- SET_FLAG(peer->config, PEER_CONFIG_ROUTEADV);
- peer->routeadv = routeadv;
- peer->v_routeadv = routeadv;
- update_group_adjust_peer_afs(peer);
- if (peer->status == Established)
- bgp_announce_route_all(peer);
+ /*
+ * Set flag and configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->flags_override, PEER_FLAG_ROUTEADV))
+ continue;
+
+ /* Set flag and configuration on peer-group member. */
+ SET_FLAG(member->flags, PEER_FLAG_ROUTEADV);
+ member->routeadv = routeadv;
+ member->v_routeadv = routeadv;
+
+ /* Update peer route announcements. */
+ update_group_adjust_peer_afs(member);
+ if (member->status == Established)
+ bgp_announce_route_all(member);
}
return 0;
int peer_advertise_interval_unset(struct peer *peer)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
- UNSET_FLAG(peer->config, PEER_CONFIG_ROUTEADV);
- peer->routeadv = 0;
+ /* Inherit configuration from peer-group if peer is member. */
+ if (peer_group_active(peer)) {
+ peer_flag_inherit(peer, PEER_FLAG_ROUTEADV);
+ PEER_ATTR_INHERIT(peer, peer->group, routeadv);
+ } else {
+ /* Otherwise remove flag and configuration from peer. */
+ peer_flag_unset(peer, PEER_FLAG_ROUTEADV);
+ peer->routeadv = 0;
+ }
- if (peer->sort == BGP_PEER_IBGP)
- peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+ /* Set timer with fallback to default value. */
+ if (peer->routeadv)
+ peer->v_routeadv = peer->routeadv;
else
- peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+ peer->v_routeadv = (peer->sort == BGP_PEER_IBGP)
+ ? BGP_DEFAULT_IBGP_ROUTEADV
+ : BGP_DEFAULT_EBGP_ROUTEADV;
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Update peer route announcements. */
update_group_adjust_peer_afs(peer);
if (peer->status == Established)
bgp_announce_route_all(peer);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- UNSET_FLAG(peer->config, PEER_CONFIG_ROUTEADV);
- peer->routeadv = 0;
+ /*
+ * Remove flag and configuration from all peer-group members, unless
+ * they are explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->flags_override, PEER_FLAG_ROUTEADV))
+ continue;
- if (peer->sort == BGP_PEER_IBGP)
- peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
- else
- peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+ /* Remove flag and configuration on peer-group member. */
+ UNSET_FLAG(member->flags, PEER_FLAG_ROUTEADV);
+ member->routeadv = 0;
+ member->v_routeadv = (member->sort == BGP_PEER_IBGP)
+ ? BGP_DEFAULT_IBGP_ROUTEADV
+ : BGP_DEFAULT_EBGP_ROUTEADV;
- update_group_adjust_peer_afs(peer);
- if (peer->status == Established)
- bgp_announce_route_all(peer);
+ /* Update peer route announcements. */
+ update_group_adjust_peer_afs(member);
+ if (member->status == Established)
+ bgp_announce_route_all(member);
}
return 0;
peer_af_flag_inherit(peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
peer_af_flag_inherit(peer, afi, safi,
PEER_FLAG_ALLOWAS_IN_ORIGIN);
- PEER_ATTR_INHERIT(peer, allowas_in[afi][safi]);
+ PEER_ATTR_INHERIT(peer, peer->group, allowas_in[afi][safi]);
peer_on_policy_change(peer, afi, safi, 0);
return 0;
int peer_local_as_set(struct peer *peer, as_t as, int no_prepend,
int replace_as)
{
+ bool old_no_prepend, old_replace_as;
struct bgp *bgp = peer->bgp;
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
if (peer_sort(peer) != BGP_PEER_EBGP
if (peer->as == as)
return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS;
- if (peer->change_local_as == as
- && ((CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)
- && no_prepend)
- || (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)
- && !no_prepend))
- && ((CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS)
- && replace_as)
- || (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS)
- && !replace_as)))
- return 0;
+ /* Save previous flag states. */
+ old_no_prepend =
+ !!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+ old_replace_as =
+ !!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
- peer->change_local_as = as;
- if (no_prepend)
- SET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- else
- UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+ /* Set flag and configuration on peer. */
+ peer_flag_set(peer, PEER_FLAG_LOCAL_AS);
+ peer_flag_modify(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND, no_prepend);
+ peer_flag_modify(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS, replace_as);
- if (replace_as)
- SET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
- else
- UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ if (peer->change_local_as == as && old_no_prepend == no_prepend
+ && old_replace_as == replace_as)
+ return 0;
+ peer->change_local_as = as;
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Send notification or reset peer depending on state. */
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
} else
bgp_session_reset(peer);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- peer->change_local_as = as;
- if (no_prepend)
- SET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- else
- UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+ /*
+ * Set flag and configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->flags_override, PEER_FLAG_LOCAL_AS))
+ continue;
- if (replace_as)
- SET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
- else
- UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ /* Skip peers with the same configuration. */
+ old_no_prepend = CHECK_FLAG(member->flags,
+ PEER_FLAG_LOCAL_AS_NO_PREPEND);
+ old_replace_as = CHECK_FLAG(member->flags,
+ PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ if (member->change_local_as == as
+ && CHECK_FLAG(member->flags, PEER_FLAG_LOCAL_AS)
+ && old_no_prepend == no_prepend
+ && old_replace_as == replace_as)
+ continue;
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
- peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ /* Set flag and configuration on peer-group member. */
+ SET_FLAG(member->flags, PEER_FLAG_LOCAL_AS);
+ COND_FLAG(member->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND,
+ no_prepend);
+ COND_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS,
+ replace_as);
+ member->change_local_as = as;
+
+ /* Send notification or stop peer depending on state. */
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) {
+ member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
+ bgp_notify_send(member, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
} else
- BGP_EVENT_ADD(peer, BGP_Stop);
+ BGP_EVENT_ADD(member, BGP_Stop);
}
return 0;
int peer_local_as_unset(struct peer *peer)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
- if (!peer->change_local_as)
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS))
return 0;
- peer->change_local_as = 0;
- UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ /* Inherit configuration from peer-group if peer is member. */
+ if (peer_group_active(peer)) {
+ peer_flag_inherit(peer, PEER_FLAG_LOCAL_AS);
+ peer_flag_inherit(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+ peer_flag_inherit(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ PEER_ATTR_INHERIT(peer, peer->group, change_local_as);
+ } else {
+ /* Otherwise remove flag and configuration from peer. */
+ peer_flag_unset(peer, PEER_FLAG_LOCAL_AS);
+ peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+ peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ peer->change_local_as = 0;
+ }
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Send notification or stop peer depending on state. */
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
} else
BGP_EVENT_ADD(peer, BGP_Stop);
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- peer->change_local_as = 0;
- UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ /*
+ * Remove flag and configuration from all peer-group members, unless
+ * they are explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->flags_override, PEER_FLAG_LOCAL_AS))
+ continue;
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
- peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ /* Remove flag and configuration on peer-group member. */
+ UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS);
+ UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+ UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ member->change_local_as = 0;
+
+ /* Send notification or stop peer depending on state. */
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) {
+ member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
+ bgp_notify_send(member, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
} else
- bgp_session_reset(peer);
+ bgp_session_reset(member);
}
+
return 0;
}
/* Set password for authenticating with the peer. */
int peer_password_set(struct peer *peer, const char *password)
{
- struct listnode *nn, *nnode;
+ struct peer *member;
+ struct listnode *node, *nnode;
int len = password ? strlen(password) : 0;
int ret = BGP_SUCCESS;
if ((len < PEER_PASSWORD_MINLEN) || (len > PEER_PASSWORD_MAXLEN))
return BGP_ERR_INVALID_VALUE;
- if (peer->password && strcmp(peer->password, password) == 0
- && !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ /* Set flag and configuration on peer. */
+ peer_flag_set(peer, PEER_FLAG_PASSWORD);
+ if (peer->password && strcmp(peer->password, password) == 0)
return 0;
-
- if (peer->password)
- XFREE(MTYPE_PEER_PASSWORD, peer->password);
-
+ XFREE(MTYPE_PEER_PASSWORD, peer->password);
peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, password);
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Send notification or reset peer depending on state. */
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
bgp_session_reset(peer);
+ /*
+ * Attempt to install password on socket and skip peer-group
+ * mechanics.
+ */
if (BGP_PEER_SU_UNSPEC(peer))
return BGP_SUCCESS;
-
return (bgp_md5_set(peer) >= 0) ? BGP_SUCCESS
: BGP_ERR_TCPSIG_FAILED;
}
- for (ALL_LIST_ELEMENTS(peer->group->peer, nn, nnode, peer)) {
- if (peer->password && strcmp(peer->password, password) == 0)
+ /*
+ * Set flag and configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->flags_override, PEER_FLAG_PASSWORD))
continue;
- if (peer->password)
- XFREE(MTYPE_PEER_PASSWORD, peer->password);
-
- peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, password);
+ /* Skip peers with the same password. */
+ if (member->password && strcmp(member->password, password) == 0)
+ continue;
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ /* Set flag and configuration on peer-group member. */
+ SET_FLAG(member->flags, PEER_FLAG_PASSWORD);
+ if (member->password)
+ XFREE(MTYPE_PEER_PASSWORD, member->password);
+ member->password = XSTRDUP(MTYPE_PEER_PASSWORD, password);
+
+ /* Send notification or reset peer depending on state. */
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status))
+ bgp_notify_send(member, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
- bgp_session_reset(peer);
+ bgp_session_reset(member);
- if (!BGP_PEER_SU_UNSPEC(peer)) {
- if (bgp_md5_set(peer) < 0)
- ret = BGP_ERR_TCPSIG_FAILED;
- }
+ /* Attempt to install password on socket. */
+ if (!BGP_PEER_SU_UNSPEC(member) && bgp_md5_set(member) < 0)
+ ret = BGP_ERR_TCPSIG_FAILED;
}
return ret;
int peer_password_unset(struct peer *peer)
{
- struct listnode *nn, *nnode;
+ struct peer *member;
+ struct listnode *node, *nnode;
- if (!peer->password && !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_PASSWORD))
return 0;
+ /* Inherit configuration from peer-group if peer is member. */
+ if (peer_group_active(peer)) {
+ peer_flag_inherit(peer, PEER_FLAG_PASSWORD);
+ PEER_STR_ATTR_INHERIT(peer, peer->group, password,
+ MTYPE_PEER_PASSWORD);
+ } else {
+ /* Otherwise remove flag and configuration from peer. */
+ peer_flag_unset(peer, PEER_FLAG_PASSWORD);
+ XFREE(MTYPE_PEER_PASSWORD, peer->password);
+ }
+
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Send notification or reset peer depending on state. */
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
bgp_session_reset(peer);
- if (peer->password)
- XFREE(MTYPE_PEER_PASSWORD, peer->password);
-
- peer->password = NULL;
-
+ /* Attempt to uninstall password on socket. */
if (!BGP_PEER_SU_UNSPEC(peer))
bgp_md5_unset(peer);
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- XFREE(MTYPE_PEER_PASSWORD, peer->password);
- peer->password = NULL;
-
- for (ALL_LIST_ELEMENTS(peer->group->peer, nn, nnode, peer)) {
- if (!peer->password)
+ /*
+ * Remove flag and configuration from all peer-group members, unless
+ * they are explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->flags_override, PEER_FLAG_PASSWORD))
continue;
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ /* Remove flag and configuration on peer-group member. */
+ UNSET_FLAG(member->flags, PEER_FLAG_PASSWORD);
+ XFREE(MTYPE_PEER_PASSWORD, member->password);
+
+ /* Send notification or reset peer depending on state. */
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status))
+ bgp_notify_send(member, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
- bgp_session_reset(peer);
-
- XFREE(MTYPE_PEER_PASSWORD, peer->password);
- peer->password = NULL;
+ bgp_session_reset(member);
- if (!BGP_PEER_SU_UNSPEC(peer))
- bgp_md5_unset(peer);
+ /* Attempt to uninstall password on socket. */
+ if (!BGP_PEER_SU_UNSPEC(member))
+ bgp_md5_unset(member);
}
return 0;
/* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
- PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
- filter[afi][safi].dlist[direct].name);
- PEER_ATTR_INHERIT(peer, filter[afi][safi].dlist[direct].alist);
+ PEER_STR_ATTR_INHERIT(peer, peer->group,
+ filter[afi][safi].dlist[direct].name,
+ MTYPE_BGP_FILTER_NAME);
+ PEER_ATTR_INHERIT(peer, peer->group,
+ filter[afi][safi].dlist[direct].alist);
} else {
/* Otherwise remove configuration from peer. */
filter = &peer->filter[afi][safi];
/* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
- PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
- filter[afi][safi].plist[direct].name);
- PEER_ATTR_INHERIT(peer, filter[afi][safi].plist[direct].plist);
+ PEER_STR_ATTR_INHERIT(peer, peer->group,
+ filter[afi][safi].plist[direct].name,
+ MTYPE_BGP_FILTER_NAME);
+ PEER_ATTR_INHERIT(peer, peer->group,
+ filter[afi][safi].plist[direct].plist);
} else {
/* Otherwise remove configuration from peer. */
filter = &peer->filter[afi][safi];
/* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
- PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
- filter[afi][safi].aslist[direct].name);
- PEER_ATTR_INHERIT(peer,
+ PEER_STR_ATTR_INHERIT(peer, peer->group,
+ filter[afi][safi].aslist[direct].name,
+ MTYPE_BGP_FILTER_NAME);
+ PEER_ATTR_INHERIT(peer, peer->group,
filter[afi][safi].aslist[direct].aslist);
} else {
/* Otherwise remove configuration from peer. */
/* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
- PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
- filter[afi][safi].map[direct].name);
- PEER_ATTR_INHERIT(peer, filter[afi][safi].map[direct].map);
+ PEER_STR_ATTR_INHERIT(peer, peer->group,
+ filter[afi][safi].map[direct].name,
+ MTYPE_BGP_FILTER_NAME);
+ PEER_ATTR_INHERIT(peer, peer->group,
+ filter[afi][safi].map[direct].map);
} else {
/* Otherwise remove configuration from peer. */
filter = &peer->filter[afi][safi];
/* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
- PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
- filter[afi][safi].usmap.name);
- PEER_ATTR_INHERIT(peer, filter[afi][safi].usmap.map);
+ PEER_STR_ATTR_INHERIT(peer, peer->group,
+ filter[afi][safi].usmap.name,
+ MTYPE_BGP_FILTER_NAME);
+ PEER_ATTR_INHERIT(peer, peer->group,
+ filter[afi][safi].usmap.map);
} else {
/* Otherwise remove configuration from peer. */
filter = &peer->filter[afi][safi];
peer_af_flag_inherit(peer, afi, safi, PEER_FLAG_MAX_PREFIX);
peer_af_flag_inherit(peer, afi, safi,
PEER_FLAG_MAX_PREFIX_WARNING);
- PEER_ATTR_INHERIT(peer, pmax[afi][safi]);
- PEER_ATTR_INHERIT(peer, pmax_threshold[afi][safi]);
- PEER_ATTR_INHERIT(peer, pmax_restart[afi][safi]);
+ PEER_ATTR_INHERIT(peer, peer->group, pmax[afi][safi]);
+ PEER_ATTR_INHERIT(peer, peer->group, pmax_threshold[afi][safi]);
+ PEER_ATTR_INHERIT(peer, peer->group, pmax_restart[afi][safi]);
return 0;
}
}
/* local-as */
- if (peer->change_local_as) {
- if (!peer_group_active(peer)
- || peer->change_local_as != g_peer->change_local_as
- || (CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)
- != CHECK_FLAG(g_peer->flags,
- PEER_FLAG_LOCAL_AS_NO_PREPEND))
- || (CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS)
- != CHECK_FLAG(g_peer->flags,
- PEER_FLAG_LOCAL_AS_REPLACE_AS))) {
- vty_out(vty, " neighbor %s local-as %u%s%s\n", addr,
- peer->change_local_as,
- CHECK_FLAG(peer->flags,
- PEER_FLAG_LOCAL_AS_NO_PREPEND)
- ? " no-prepend"
- : "",
- CHECK_FLAG(peer->flags,
- PEER_FLAG_LOCAL_AS_REPLACE_AS)
- ? " replace-as"
- : "");
- }
+ if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS)) {
+ vty_out(vty, " neighbor %s local-as %u", addr,
+ peer->change_local_as);
+ if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND))
+ vty_out(vty, " no-prepend");
+ if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS))
+ vty_out(vty, " replace-as");
+ vty_out(vty, "\n");
}
/* description */
}
/* shutdown */
- if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)) {
- if (!peer_group_active(peer)
- || !CHECK_FLAG(g_peer->flags, PEER_FLAG_SHUTDOWN)
- || peer->tx_shutdown_message) {
- if (peer->tx_shutdown_message)
- vty_out(vty,
- " neighbor %s shutdown message %s\n",
- addr, peer->tx_shutdown_message);
- else
- vty_out(vty, " neighbor %s shutdown\n", addr);
- }
+ if (peergroup_flag_check(peer, PEER_FLAG_SHUTDOWN)) {
+ if (peer->tx_shutdown_message)
+ vty_out(vty, " neighbor %s shutdown message %s\n", addr,
+ peer->tx_shutdown_message);
+ else
+ vty_out(vty, " neighbor %s shutdown\n", addr);
}
/* bfd */
}
/* password */
- if (peer->password) {
- if (!peer_group_active(peer) || !g_peer->password
- || strcmp(peer->password, g_peer->password) != 0) {
- vty_out(vty, " neighbor %s password %s\n", addr,
- peer->password);
- }
- }
+ if (peergroup_flag_check(peer, PEER_FLAG_PASSWORD))
+ vty_out(vty, " neighbor %s password %s\n", addr,
+ peer->password);
/* neighbor solo */
if (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL)) {
}
/* passive */
- if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE)) {
- if (!peer_group_active(peer)
- || !CHECK_FLAG(g_peer->flags, PEER_FLAG_PASSIVE)) {
- vty_out(vty, " neighbor %s passive\n", addr);
- }
- }
+ if (peergroup_flag_check(peer, PEER_FLAG_PASSIVE))
+ vty_out(vty, " neighbor %s passive\n", addr);
/* ebgp-multihop */
if (peer->sort != BGP_PEER_IBGP && peer->ttl != 1
}
/* disable-connected-check */
- if (CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) {
- if (!peer_group_active(peer)
- || !CHECK_FLAG(g_peer->flags,
- PEER_FLAG_DISABLE_CONNECTED_CHECK)) {
- vty_out(vty, " neighbor %s disable-connected-check\n",
- addr);
- }
- }
+ if (peergroup_flag_check(peer, PEER_FLAG_DISABLE_CONNECTED_CHECK))
+ vty_out(vty, " neighbor %s disable-connected-check\n", addr);
/* enforce-first-as */
- if (CHECK_FLAG(peer->flags, PEER_FLAG_ENFORCE_FIRST_AS)) {
- if (!peer_group_active(peer)
- || !CHECK_FLAG(g_peer->flags, PEER_FLAG_ENFORCE_FIRST_AS)) {
- vty_out(vty, " neighbor %s enforce-first-as\n", addr);
- }
- }
+ if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS))
+ vty_out(vty, " neighbor %s enforce-first-as\n", addr);
/* update-source */
- if (peer->update_if) {
- if (!peer_group_active(peer) || !g_peer->update_if
- || strcmp(g_peer->update_if, peer->update_if) != 0) {
- vty_out(vty, " neighbor %s update-source %s\n", addr,
- peer->update_if);
- }
- }
- if (peer->update_source) {
- if (!peer_group_active(peer) || !g_peer->update_source
- || sockunion_cmp(g_peer->update_source, peer->update_source)
- != 0) {
+ if (peergroup_flag_check(peer, PEER_FLAG_UPDATE_SOURCE)) {
+ if (peer->update_source)
vty_out(vty, " neighbor %s update-source %s\n", addr,
sockunion2str(peer->update_source, buf,
SU_ADDRSTRLEN));
- }
+ else if (peer->update_if)
+ vty_out(vty, " neighbor %s update-source %s\n", addr,
+ peer->update_if);
}
/* advertisement-interval */
- if (CHECK_FLAG(peer->config, PEER_CONFIG_ROUTEADV)
- && ((!peer_group_active(peer)
- && peer->v_routeadv != BGP_DEFAULT_EBGP_ROUTEADV)
- || (peer_group_active(peer)
- && peer->v_routeadv != g_peer->v_routeadv))) {
+ if (peergroup_flag_check(peer, PEER_FLAG_ROUTEADV))
vty_out(vty, " neighbor %s advertisement-interval %u\n", addr,
- peer->v_routeadv);
- }
+ peer->routeadv);
/* timers */
- if ((PEER_OR_GROUP_TIMER_SET(peer))
- && ((!peer_group_active(peer)
- && (peer->keepalive != BGP_DEFAULT_KEEPALIVE
- || peer->holdtime != BGP_DEFAULT_HOLDTIME))
- || (peer_group_active(peer)
- && (peer->keepalive != g_peer->keepalive
- || peer->holdtime != g_peer->holdtime)))) {
+ if (peergroup_flag_check(peer, PEER_FLAG_TIMER))
vty_out(vty, " neighbor %s timers %u %u\n", addr,
peer->keepalive, peer->holdtime);
- }
-
- if (CHECK_FLAG(peer->config, PEER_CONFIG_CONNECT)
- && ((!peer_group_active(peer)
- && peer->connect != BGP_DEFAULT_CONNECT_RETRY)
- || (peer_group_active(peer)
- && peer->connect != g_peer->connect)))
- {
+ /* timers connect */
+ if (peergroup_flag_check(peer, PEER_FLAG_TIMER_CONNECT))
vty_out(vty, " neighbor %s timers connect %u\n", addr,
peer->connect);
- }
/* capability dynamic */
- if (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) {
- if (!peer_group_active(peer)
- || !CHECK_FLAG(g_peer->flags,
- PEER_FLAG_DYNAMIC_CAPABILITY)) {
- vty_out(vty, " neighbor %s capability dynamic\n", addr);
- }
- }
+ if (peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY))
+ vty_out(vty, " neighbor %s capability dynamic\n", addr);
/* capability extended-nexthop */
- if (peer->ifp && !CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)) {
- if (!peer_group_active(peer)
- || !CHECK_FLAG(g_peer->flags, PEER_FLAG_CAPABILITY_ENHE)) {
+ if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_ENHE)) {
+ if (CHECK_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE))
vty_out(vty,
" no neighbor %s capability extended-nexthop\n",
addr);
- }
- }
-
- if (!peer->ifp && CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)) {
- if (!peer_group_active(peer)
- || !CHECK_FLAG(g_peer->flags, PEER_FLAG_CAPABILITY_ENHE)) {
+ else
vty_out(vty,
" neighbor %s capability extended-nexthop\n",
addr);
- }
}
/* dont-capability-negotiation */
- if (CHECK_FLAG(peer->flags, PEER_FLAG_DONT_CAPABILITY)) {
- if (!peer_group_active(peer)
- || !CHECK_FLAG(g_peer->flags, PEER_FLAG_DONT_CAPABILITY)) {
- vty_out(vty, " neighbor %s dont-capability-negotiate\n",
- addr);
- }
- }
+ if (peergroup_flag_check(peer, PEER_FLAG_DONT_CAPABILITY))
+ vty_out(vty, " neighbor %s dont-capability-negotiate\n", addr);
/* override-capability */
- if (CHECK_FLAG(peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) {
- if (!peer_group_active(peer)
- || !CHECK_FLAG(g_peer->flags,
- PEER_FLAG_OVERRIDE_CAPABILITY)) {
- vty_out(vty, " neighbor %s override-capability\n",
- addr);
- }
- }
+ if (peergroup_flag_check(peer, PEER_FLAG_OVERRIDE_CAPABILITY))
+ vty_out(vty, " neighbor %s override-capability\n", addr);
/* strict-capability-match */
- if (CHECK_FLAG(peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) {
- if (!peer_group_active(peer)
- || !CHECK_FLAG(g_peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) {
- vty_out(vty, " neighbor %s strict-capability-match\n",
- addr);
- }
- }
+ if (peergroup_flag_check(peer, PEER_FLAG_STRICT_CAP_MATCH))
+ vty_out(vty, " neighbor %s strict-capability-match\n", addr);
}
/* BGP peer configuration display function. */
#define PEER_CAP_ENHE_AF_NEGO (1 << 14) /* Extended nexthop afi/safi negotiated */
/* Global configuration flags. */
+ /*
+ * Parallel array to flags that indicates whether each flag originates
+ * from a peer-group or if it is config that is specific to this
+ * individual peer. If a flag is set independent of the peer-group, the
+ * same bit should be set here. If this peer is a peer-group, this
+ * memory region should be all zeros.
+ *
+ * The assumption is that the default state for all flags is unset,
+ * so if a flag is unset, the corresponding override flag is unset too.
+ * However if a flag is set, the corresponding override flag is set.
+ */
+ uint32_t flags_override;
+ /*
+ * Parallel array to flags that indicates whether the default behavior
+ * of *flags_override* should be inverted. If a flag is unset and the
+ * corresponding invert flag is set, the corresponding override flag
+ * would be set. However if a flag is set and the corresponding invert
+ * flag is unset, the corresponding override flag would be unset.
+ *
+ * This can be used for attributes like *send-community*, which are
+ * implicitely enabled and have to be disabled explicitely, compared to
+ * 'normal' attributes like *next-hop-self* which are implicitely set.
+ *
+ * All operations dealing with flags should apply the following boolean
+ * logic to keep the internal flag system in a sane state:
+ *
+ * value=0 invert=0 Inherit flag if member, otherwise unset flag
+ * value=0 invert=1 Unset flag unconditionally
+ * value=1 invert=0 Set flag unconditionally
+ * value=1 invert=1 Inherit flag if member, otherwise set flag
+ *
+ * Contrary to the implementation of *flags_override*, the flag
+ * inversion state can be set either on the peer OR the peer *and* the
+ * peer-group. This was done on purpose, as the inversion state of a
+ * flag can be determined on either the peer or the peer-group.
+ *
+ * Example: Enabling the cisco configuration mode inverts all flags
+ * related to *send-community* unconditionally for both peer-groups and
+ * peers.
+ *
+ * This behavior is different for interface peers though, which enable
+ * the *extended-nexthop* flag by default, which regular peers do not.
+ * As the peer-group can contain both regular and interface peers, the
+ * flag inversion state must be set on the peer only.
+ *
+ * When a peer inherits the configuration from a peer-group and the
+ * inversion state of the flag differs between peer and peer-group, the
+ * newly set value must equal to the inverted state of the peer-group.
+ */
+ uint32_t flags_invert;
+ /*
+ * Effective array for storing the peer/peer-group flags. In case of a
+ * peer-group, the peer-specific overrides (see flags_override and
+ * flags_invert) must be respected.
+ */
uint32_t flags;
#define PEER_FLAG_PASSIVE (1 << 0) /* passive mode */
#define PEER_FLAG_SHUTDOWN (1 << 1) /* shutdown */
#define PEER_FLAG_IFPEER_V6ONLY (1 << 14) /* if-based peer is v6 only */
#define PEER_FLAG_IS_RFAPI_HD (1 << 15) /* attached to rfapi HD */
#define PEER_FLAG_ENFORCE_FIRST_AS (1 << 16) /* enforce-first-as */
+#define PEER_FLAG_ROUTEADV (1 << 17) /* route advertise */
+#define PEER_FLAG_TIMER (1 << 18) /* keepalive & holdtime */
+#define PEER_FLAG_TIMER_CONNECT (1 << 19) /* connect timer */
+#define PEER_FLAG_PASSWORD (1 << 20) /* password */
+#define PEER_FLAG_LOCAL_AS (1 << 21) /* local-as */
+#define PEER_FLAG_UPDATE_SOURCE (1 << 22) /* update-source */
/* outgoing message sent in CEASE_ADMIN_SHUTDOWN notify */
char *tx_shutdown_message;
/* Peer Per AF flags */
/*
- * Parallel array to af_flags that indicates whether each flag
- * originates from a peer-group or if it is config that is specific to
- * this individual peer. If a flag is set independent of the
- * peer-group the same bit should be set here. If this peer is a
- * peer-group, this memory region should be all zeros. The assumption
- * is that the default state for all flags is unset.
- *
- * Notes:
- * - if a flag for an individual peer is unset, the corresponding
- * override flag is unset and the peer is considered to be back in
- * sync with the peer-group.
- * - This does *not* contain the flag values, rather it contains
- * whether the flag at the same position in af_flags is
- * *peer-specific*.
+ * Please consult the comments for *flags_override*, *flags_invert* and
+ * *flags* to understand what these three arrays do. The address-family
+ * specific attributes are being treated the exact same way as global
+ * peer attributes.
*/
uint32_t af_flags_override[AFI_MAX][SAFI_MAX];
- /*
- * Parallel array to af_flags that indicates whether each flag should
- * be treated as regular (defaults to 0) or inverted (defaults to 1).
- * If a flag is set to 1 by default, the same bit should be set here.
- *
- * Notes:
- * - This does *not* contain the flag values, rather it contains
- * whether the flag at the same position in af_flags is *regular* or
- * *inverted*.
- */
uint32_t af_flags_invert[AFI_MAX][SAFI_MAX];
- /*
- * Effective flags, computed by applying peer-group flags and then
- * overriding with individual flags
- */
uint32_t af_flags[AFI_MAX][SAFI_MAX];
#define PEER_FLAG_SEND_COMMUNITY (1 << 0) /* send-community */
#define PEER_FLAG_SEND_EXT_COMMUNITY (1 << 1) /* send-community ext. */
#define PEER_STATUS_EOR_SEND (1 << 4) /* end-of-rib send to peer */
#define PEER_STATUS_EOR_RECEIVED (1 << 5) /* end-of-rib received from peer */
- /* Default attribute value for the peer. */
- uint32_t config;
-#define PEER_CONFIG_TIMER (1 << 0) /* keepalive & holdtime */
-#define PEER_CONFIG_CONNECT (1 << 1) /* connect */
-#define PEER_CONFIG_ROUTEADV (1 << 2) /* route advertise */
-#define PEER_GROUP_CONFIG_TIMER (1 << 3) /* timers from peer-group */
-
-#define PEER_OR_GROUP_TIMER_SET(peer) \
- (CHECK_FLAG(peer->config, PEER_CONFIG_TIMER) \
- || CHECK_FLAG(peer->config, PEER_GROUP_CONFIG_TIMER))
-
+ /* Configured timer values. */
_Atomic uint32_t holdtime;
_Atomic uint32_t keepalive;
_Atomic uint32_t connect;
DECLARE_QOBJ_TYPE(peer)
/* Inherit peer attribute from peer-group. */
-#define PEER_ATTR_INHERIT(peer, attr) ((peer)->attr = (peer)->group->conf->attr)
-#define PEER_STR_ATTR_INHERIT(mt, peer, attr) \
+#define PEER_ATTR_INHERIT(peer, group, attr) \
+ ((peer)->attr = (group)->conf->attr)
+#define PEER_STR_ATTR_INHERIT(peer, group, attr, mt) \
do { \
if ((peer)->attr) \
XFREE(mt, (peer)->attr); \
- if ((peer)->group->conf->attr) \
- (peer)->attr = XSTRDUP(mt, (peer)->group->conf->attr); \
+ if ((group)->conf->attr) \
+ (peer)->attr = XSTRDUP(mt, (group)->conf->attr); \
+ else \
+ (peer)->attr = NULL; \
+ } while (0)
+#define PEER_SU_ATTR_INHERIT(peer, group, attr) \
+ do { \
+ if ((peer)->attr) \
+ sockunion_free((peer)->attr); \
+ if ((group)->conf->attr) \
+ (peer)->attr = sockunion_dup((group)->conf->attr); \
else \
(peer)->attr = NULL; \
} while (0)
extern int peer_flag_set(struct peer *, uint32_t);
extern int peer_flag_unset(struct peer *, uint32_t);
+extern void peer_flag_inherit(struct peer *peer, uint32_t flag);
extern int peer_af_flag_set(struct peer *, afi_t, safi_t, uint32_t);
extern int peer_af_flag_unset(struct peer *, afi_t, safi_t, uint32_t);
vnc_import_bgp_exterior_redist_enable((bgp), (afi)); \
break; \
default: \
- vnc_redistribute_set((bgp), (afi), (type)); \
+ if ((type) < ZEBRA_ROUTE_MAX) \
+ vnc_redistribute_set((bgp), (afi), (type)); \
break; \
} \
} while (0)
vnc_import_bgp_exterior_redist_disable((bgp), (afi)); \
break; \
default: \
- vnc_redistribute_unset((bgp), (afi), (type)); \
+ if ((type) < ZEBRA_ROUTE_MAX) \
+ vnc_redistribute_unset((bgp), (afi), (type)); \
break; \
} \
} while (0)
if (rfg_new == NULL) {
rfg_new = bgp_rfapi_cfg_match_byname(bgp, argv[5]->arg,
RFAPI_GROUP_CFG_VRF);
- vnc_add_vrf_opener(bgp, rfg_new);
+ if (rfg_new)
+ vnc_add_vrf_opener(bgp, rfg_new);
}
if (rfg_new == NULL) {
if (VNC_EXPORT_ZEBRA_GRP_ENABLED(hc)) {
redist++;
vty_out(vty, "%sToZebra Groups={", (redist == 1 ? "" : " "));
- if (hc->rfg_export_direct_bgp_l) {
+ if (hc->rfg_export_zebra_l) {
int cnt = 0;
struct listnode *node, *nnode;
struct rfapi_rfg_name *rfgn;
{
struct rfapi_ip_addr vn;
struct rfapi_ip_addr un;
- struct rfapi_ip_addr target;
- rfapi_handle handle;
int rc;
- struct rfapi_next_hop_entry *pNextHopEntry;
- struct rfapi_l2address_option l2o_buf;
- struct bgp_tea_options hopt;
- uint8_t valbuf[14];
/*
* Get VN addr
if ((rc = rfapiCliGetRfapiIpAddr(vty, argv[6]->arg, &un)))
return rc;
-
-#if 0 /* there is no IP target arg here ?????? */
- /*
- * Get target addr
- */
- if ((rc = rfapiCliGetRfapiIpAddr (vty, argv[2], &target)))
- return rc;
-#else
vty_out(vty, "%% This command is broken.\n");
return CMD_WARNING_CONFIG_FAILED;
-#endif
-
- if (rfapi_find_handle_vty(vty, &vn, &un, &handle)) {
- vty_out(vty, "can't locate handle matching vn=%s, un=%s\n",
- argv[4]->arg, argv[6]->arg);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- /*
- * Set up L2 parameters
- */
- memset(&l2o_buf, 0, sizeof(l2o_buf));
- if (rfapiStr2EthAddr(argv[10]->arg, &l2o_buf.macaddr)) {
- vty_out(vty, "Bad mac address \"%s\"\n", argv[10]->arg);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- l2o_buf.logical_net_id = strtoul(argv[8]->arg, NULL, 10);
-
- /* construct option chain */
-
- memset(valbuf, 0, sizeof(valbuf));
- memcpy(valbuf, &l2o_buf.macaddr.octet, ETH_ALEN);
- valbuf[11] = (l2o_buf.logical_net_id >> 16) & 0xff;
- valbuf[12] = (l2o_buf.logical_net_id >> 8) & 0xff;
- valbuf[13] = l2o_buf.logical_net_id & 0xff;
-
- memset(&hopt, 0, sizeof(hopt));
- hopt.options_count = 1;
- hopt.options_length = sizeof(valbuf); /* is this right? */
- hopt.type = RFAPI_VN_OPTION_TYPE_L2ADDR;
- hopt.length = sizeof(valbuf);
- hopt.value = valbuf;
-
-
- /*
- * options parameter not used? Set to NULL for now
- */
- rc = rfapi_query(handle, &target, &l2o_buf, &pNextHopEntry);
-
- if (rc) {
- vty_out(vty, "rfapi_query failed with rc=%d (%s)\n", rc,
- strerror(rc));
- } else {
- /*
- * print nexthop list
- */
- /* TBD enhance to print L2 information */
- test_nexthops_callback(/*&target, */ pNextHopEntry,
- vty); /* frees nh list! */
- }
-
- return CMD_SUCCESS;
}
return 1;
}
- if (stream) {
- *vty = stream; /* VTYNL requires vty to be legit */
- *fp = (int (*)(void *, const char *, ...))vty_out;
- *outstream = stream;
- *vty_newline = str_vty_newline(*vty);
- return 1;
- }
-
- return 0;
+ *vty = stream; /* VTYNL requires vty to be legit */
+ *fp = (int (*)(void *, const char *, ...))vty_out;
+ *outstream = stream;
+ *vty_newline = str_vty_newline(*vty);
+ return 1;
}
/* called from bgpd/bgp_vty.c'route_vty_out() */
int rfapiCliGetPrefixAddr(struct vty *vty, const char *str, struct prefix *p)
{
if (!str2prefix(str, p)) {
- vty_out(vty, "Malformed address \"%s\"%s", str, HVTYNL);
+ vty_out(vty, "Malformed address \"%s\"%s", str ? str : "null",
+ HVTYNL);
return CMD_WARNING;
}
switch (p->family) {
* match un, vn addresses of NVEs
*/
if (pUn && (rfapi_ip_addr_cmp(pUn, &rfd->un_addr)))
- continue;
+ break;
if (pVn && (rfapi_ip_addr_cmp(pVn, &rfd->vn_addr)))
- continue;
+ break;
#if DEBUG_L2_EXTRA
vnc_zlog_debug_verbose("%s: un, vn match", __func__);
Process & Workflow
*******************
+.. highlight:: none
+
FRR is a large project developed by many different groups. This section
documents standards for code style & quality, commit messages, pull requests
and best practices that all contributors are asked to follow.
+----------------------------------+--------------------------------+
The Development list is used to discuss and document general issues related to
-project development and governance. The public Slack instance,
-frrouting.slack.com, and weekly technical meetings provide a higher bandwidth
-channel for discussions. The results of such discussions must be reflected in
-updates, as appropriate, to code (i.e., merges), `Github issues`_, and for
-governance or process changes, updates to the Development list and either this
-file or information posted at https://frrouting.org/.
+project development and governance. The public
+`Slack instance <https://frrouting.slack.com>`_ and weekly technical meetings
+provide a higher bandwidth channel for discussions. The results of such
+discussions must be reflected in updates, as appropriate, to code (i.e.,
+merges), `GitHub issues`_, and for governance or process changes, updates to
+the Development list and either this file or information posted at
+https://frrouting.org/.
+
+Development & Release Cycle
+===========================
+
+Development
+-----------
+
+.. figure:: ../figures/git_branches.png
+ :align: center
+ :scale: 55%
+ :alt: Merging Git branches into a central trunk
+
+ Rough outline of FRR development workflow
+
+The master Git for FRR resides on `GitHub`_.
+
+There is one main branch for development, ``master``. For each major release
+(2.0, 3.0 etc) a new release branch is created based on the master. Significant
+bugfixes should be backported to upcoming and existing release branches no more
+than 1 year old. As a general rule new features are not backported to release
+branches.
-Release Process & Schedule
-==========================
+Subsequent point releases based on a major branch are handled with git tags.
-FRR employs a <MAJOR>.<MINOR>.<BUGFIX> versioning scheme.
+Releases
+--------
+FRR employs a ``<MAJOR>.<MINOR>.<BUGFIX>`` versioning scheme.
-MAJOR
+``MAJOR``
Significant new features or multiple minor features. The addition of a new
routing protocol or daemon would fall under this class.
-MINOR
+``MINOR``
Small features, e.g. options for automatic BGP shutdown.
-BUGFIX
+``BUGFIX``
Fixes for actual bugs and/or security issues.
We will pull a new development branch for the next release every 4 months. The
-current schedule is Feb/June/October 1. The decision for a MAJOR/MINOR release
-is made at the time of branch pull based on what has been received the previous
-4 months. The branch name will be dev/MAJOR.MINOR. At this point in time the
-master branch, :file:`configure.ac`, documentation and packaging systems will
-be updated to reflect the next possible release name to allow for easy
-distinguishing. Additionally the new dev branch will have these files updated
-too.
-
-After one month the development branch will be renamed to stable/MAJOR.MINOR.
-This process is not held up unless a crash or security issue has been found and
-needs to be addressed. Issues being fixed will not cause a delay.
+current schedule is Feb/June/October 1. The decision for a ``MAJOR/MINOR``
+release is made at the time of branch pull based on what has been received the
+previous 4 months. The branch name will be ``dev/MAJOR.MINOR``. At this point
+in time the master branch and this new branch, :file:`configure.ac`,
+documentation and packaging systems will be updated to reflect the next
+possible release name to allow for easy distinguishing.
+
+After one month the development branch will be renamed to
+``stable/MAJOR.MINOR``. This process is not held up unless a crash or security
+issue has been found and needs to be addressed. Issues being fixed will not
+cause a delay.
Bugfix releases are made as needed at 1 month intervals until the next
-MAJOR.MINOR relese branch is pulled. Depending on the severity of the bugs,
+``MAJOR.MINOR`` relese branch is pulled. Depending on the severity of the bugs,
bugfix releases may occur sooner.
Bugfixes are applied to the two most recent releases. Security fixes are
may also be backported to older releases depending on severity.
Changelog
-=========
-
+---------
The changelog will be the base for the release notes. A changelog entry for
your changes is usually not required and will be added based on your commit
messages by the maintainers. However, you are free to include an update to the
FRR accepts patches from two sources:
- Email (git format-patch)
-- Github pull request
+- GitHub pull request
-Contributors are highly encouraged to use Github's fork-and-pr workflow. It is
-easier for us to review it, test it, try it and discuss it on Github than it is
-via email, thus your patch will get more attention more quickly on Github.
+Contributors are highly encouraged to use GitHub's fork-and-PR workflow. It is
+easier for us to review it, test it, try it and discuss it on GitHub than it is
+via email, thus your patch will get more attention more quickly on GitHub.
The base branch for new contributions and non-critical bug fixes should be
``master``. Please ensure your pull request is based on this branch when you
submit it.
-Pre-submission Checklist
-------------------------
-
-- Format code (see `Code Formatting <#code-formatting>`__)
-- Verify and acknowledge license (see `License for
- contributions <#license-for-contributions>`__)
-- Ensure you have properly signed off (see `Signing
- Off <#signing-off>`__)
-- Test building with various configurations:
-
- - ``buildtest.sh``
-
-- Verify building source distribution:
-
- - ``make dist`` (and try rebuilding from the resulting tar file)
-
-- Run unit tests:
+GitHub Pull Requests
+--------------------
- - ``make test``
+The preferred method of submitting changes is a GitHub pull request. Code
+submitted by pull request will be automatically tested by one or more CI
+systems. Once the automated tests succeed, other developers will review your
+code for quality and correctness. After any concerns are resolved, your code
+will be merged into the branch it was submitted against.
-- Document Regression Runs and plans for continued maintenance of the
- feature
+Patch Submission via Mailing List
+---------------------------------
-License for contributions
--------------------------
+As an alternative submission method, a patch can be mailed to the
+development mailing list. Patches received on the mailing list will be
+picked up by Patchwork and tested against the latest development branch.
-FRR is under a “GPLv2 or later” license. Any code submitted must
-be released under the same license (preferred) or any license which
-allows redistribution under this GPLv2 license (eg MIT License).
+The recommended way to send the patch (or series of NN patches) to the
+list is by using ``git send-email`` as follows (assuming they are the N
+most recent commit(s) in your git history)::
-Signing Off
------------
+ git send-email -NN --annotate --to=dev@lists.frrouting.org
-Code submitted to FRR must be signed off. We have the same
-requirements for using the signed-off-by process as the Linux kernel. In
-short, you must include a signed-off-by tag in every patch.
+If your commits do not already contain a ``Signed-off-by`` line, then
+use the following command to add it (after making sure you agree to the
+Developer Certificate of Origin as outlined above)::
-``Signed-off-by:`` this is a developer's certification that he or she
-has the right to submit the patch for inclusion into the project. It is
-an agreement to the Developer's Certificate of Origin (below). Code
-without a proper signoff can not and will not be merged.
+ git send-email -NN --annotate --signoff --to=dev@lists.frrouting.org
-If you are unfamiliar with this process, you should read the `official
-policy at
-kernel.org <https://www.kernel.org/doc/html/latest/process/submitting-patches.html>`__
-and you might find this article about `participating in the Linux
-community on the Linux Foundation
-website <http://www.linuxfoundation.org/content/how-participate-linux-community-0>`__
-to be a helpful resource.
+Submitting multi-commit patches as a GitHub pull request is **strongly
+encouraged** and increases the probability of your patch getting reviewed and
+merged in a timely manner.
-In short, when you sign off on a commit, you assert your agreement to
-all of the following:
+.. _license-for-contributions:
-::
+License for Contributions
+-------------------------
+FRR is under a “GPLv2 or later” license. Any code submitted must be released
+under the same license (preferred) or any license which allows redistribution
+under this GPLv2 license (eg MIT License).
- Developer's Certificate of Origin 1.1
+Pre-submission Checklist
+------------------------
+- Format code (see `Code Formatting <#code-formatting>`__)
+- Verify and acknowledge license (see :ref:`license-for-contributions`)
+- Ensure you have properly signed off (see :ref:`signing-off`)
+- Test building with various configurations:
- By making a contribution to this project, I certify that:
+ - ``buildtest.sh``
- (a) The contribution was created in whole or in part by me and I
- have the right to submit it under the open source license
- indicated in the file; or
+- Verify building source distribution:
- (b) The contribution is based upon previous work that, to the best
- of my knowledge, is covered under an appropriate open source
- license and I have the right under that license to submit that
- work with modifications, whether created in whole or in part by
- me, under the same open source license (unless I am permitted to
- submit under a different license), as indicated in the file; or
+ - ``make dist`` (and try rebuilding from the resulting tar file)
- (c) The contribution was provided directly to me by some other
- person who certified (a), (b) or (c) and I have not modified it.
+- Run unit tests:
- (d) I understand and agree that this project and the contribution
- are public and that a record of the contribution (including all
- personal information I submit with it, including my sign-off) is
- maintained indefinitely and may be redistributed consistent with
- this project or the open source license(s) involved.
+ - ``make test``
-What do I submit my changes against?
-------------------------------------
+- In the case of a major new feature or other significant change, document
+ plans for continued maintenance of the feature
-We've documented where we would like to have the different fixes applied
-at
-https://github.com/FRRouting/frr/wiki/Where-Do-I-create-a-Pull-Request-against%3F
-If you are unsure where your submission goes, look at that document or
-ask a project maintainer.
+.. _signing-off:
-Github pull requests
---------------------
+Signing Off
+-----------
+Code submitted to FRR must be signed off. We have the same requirements for
+using the signed-off-by process as the Linux kernel. In short, you must include
+a ``Signed-off-by`` tag in every patch.
-The preferred method of submitting changes is a Github pull request.
-Code submitted by pull request will be automatically tested by one or
-more CI systems. Once the automated tests succeed, other developers will
-review your code for quality and correctness. After any concerns are
-resolved, your code will be merged into the branch it was submitted
-against.
+``Signed-off-by`` is a developer's certification that they have the right to
+submit the patch for inclusion into the project. It is an agreement to the
+:ref:`Developer's Certificate of Origin <developers-certificate-of-origin>`.
+Code without a proper ``Signed-off-by`` line cannot and will not be merged.
-Patch submission via mailing list
----------------------------------
+If you are unfamiliar with this process, you should read the
+`official policy at kernel.org <https://www.kernel.org/doc/html/latest/process/submitting-patches.html>`_.
+You might also find
+`this article <http://www.linuxfoundation.org/content/how-participate-linux-community-0>`_
+about participating in the Linux community on the Linux Foundation website to
+be a helpful resource.
-As an alternative submission method, a patch can be mailed to the
-development mailing list. Patches received on the mailing list will be
-picked up by Patchwork and tested against the latest development branch.
+.. _developers-certificate-of-origin:
-The recommended way to send the patch (or series of NN patches) to the
-list is by using ``git send-email`` as follows (assuming they are the N
-most recent commit(s) in your git history:
+In short, when you sign off on a commit, you assert your agreement to all of
+the following::
-::
+ Developer's Certificate of Origin 1.1
- git send-email -NN --annotate --to=dev@lists.frrouting.org
+ By making a contribution to this project, I certify that:
-If your commits do not already contain a ``Signed-off-by`` line, then
-use the following command to add it (after making sure you agree to the
-Developer Certificate of Origin as outlined above):
+ (a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
-::
+ (b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part by
+ me, under the same open source license (unless I am permitted to
+ submit under a different license), as indicated in the file; or
- git send-email -NN --annotate --signoff --to=dev@lists.frrouting.org
+ (c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified it.
-Submitting multi-commit patches as a Github pull request is **strongly
-encouraged** and increases the probability of your patch getting
-reviewed and merged in a timely manner.
+ (d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
-After submitting your changes
+After Submitting Your Changes
-----------------------------
-- Watch for Continuous Integration (CI) Test results
+- Watch for Continuous Integration (CI) test results
- You should automatically receive an email with the test results
within less than 2 hrs of the submission. If you don’t get the
- email, then check status on the Github pull request.
+ email, then check status on the GitHub pull request.
- Please notify the development mailing list if you think something
doesn't work.
community members.
- Your submission is done once it is merged to the master branch.
-Git Structure
-=============
-
-.. figure:: ../figures/git_branches.png
- :align: center
- :scale: 55%
- :alt: Merging Git branches into a central trunk
-
- Rough outline of FRR development workflow
-
-The master Git for FRR resides on `GitHub`_.
-
-There is one main branch for development, ``master``. For each major release
-(2.0, 3.0 etc) a new release branch is created based on the master. Subsequent
-point releases based on a major branch are marked by tagging.
-
Programming Languages, Tools and Libraries
==========================================
utilized but pure ReST is preferred where possible. See
:ref:`documentation`.
-
Coding Practices & Style
========================
---------------
Commit messages should be formatted in the same way as Linux kernel
-commit messages. The format is roughly
-
-::
+commit messages. The format is roughly::
dir: short summary
extended summary
-``dir`` should be the top level source directory under which the change
-was made. For example, a change in bgpd/rfapi would be formatted as:::
+``dir`` should be the top level source directory under which the change was
+made. For example, a change in :file:`bgpd/rfapi` would be formatted as::
bgpd: short summary
-The first line should be no longer than 50 characters. Subsequent lines
-should be wrapped to 72 characters.
+ ...
+
+The first line should be no longer than 50 characters. Subsequent lines should
+be wrapped to 72 characters.
-Source file header
+You must also sign off on your commit.
+
+.. seealso:: :ref:`signing-off`
+
+Source File Header
------------------
-New files need to have a Copyright header (see `License for
-contributions <#license-for-contributions>`__ above) added to the file.
-Preferred form of the header is as follows:
+New files must have a copyright header (see :ref:`license-for-contributions`
+above) added to the file. The header should be:
-::
+.. code-block:: c
/*
* Title/Function of file
#include <zebra.h>
-Adding copyright claims to existing files
+Please copy-paste this header verbatim. In particular:
+
+- Do not replace "This program" with "FRR"
+- Do not change the address of the FSF
+
+Adding Copyright Claims to Existing Files
-----------------------------------------
-When adding copyright claims for modifications to an existing file,
-please preface the claim with "Portions: " on a line before it and
-indent the "Copyright ..." string. If such a case already exists, add
-your indented claim immediately after. E.g.:
+When adding copyright claims for modifications to an existing file, please
+add a ``Portions:`` section as shown below. If this section already exists, add
+your new claim at the end of the list.
-::
+.. code-block:: c
- Portions:
- Copyright (C) 2010 Entity A ....
- Copyright (C) 2016 Your name [optional brief change description]
+ /*
+ * Title/Function of file
+ * Copyright (C) YEAR Author’s Name
+ * Portions:
+ * Copyright (C) 2010 Entity A ....
+ * Copyright (C) 2016 Your name [optional brief change description]
+ * ...
+ */
Code Formatting
---------------
-FRR uses Linux kernel style except where noted below. Code which does
-not comply with these style guidelines will not be accepted.
+FRR uses Linux kernel style except where noted below. Code which does not
+comply with these style guidelines will not be accepted.
The project provides multiple tools to allow you to correctly style your code
as painlessly as possible, primarily built around ``clang-format``.
submission is highly recommended. The CI system runs this script as well and
will comment on the PR with the results if style errors are found.
- It is run like this:
-
- ::
+ It is run like this::
- checkpatch.sh <patch> <tree>
+ ./checkpatch.sh <patch> <tree>
Reports are generated on ``stderr`` and the exit code indicates whether
issues were found (2, 1) or not (0).
frobnicate ();
#endif /* SOME_SYMBOL */
-Note that the former approach requires ensuring that ``SOME_SYMBOL``
-will be defined (watch your ``AC_DEFINE``\ s).
+Note that the former approach requires ensuring that ``SOME_SYMBOL`` will be
+defined (watch your ``AC_DEFINE``\ s).
Debug-guards in code
--------------------
-Debugging statements are an important methodology to allow developers to
-fix issues found in the code after it has been released. The caveat here
-is that the developer must remember that people will be using the code
-at scale and in ways that can be unexpected for the original
-implementor. As such debugs **MUST** be guarded in such a way that they
-can be turned off. FRR has the ability to turn on/off debugs from the
-CLI and it is expected that the developer will use this convention to
-allow control of their debugs.
+Debugging statements are an important methodology to allow developers to fix
+issues found in the code after it has been released. The caveat here is that
+the developer must remember that people will be using the code at scale and in
+ways that can be unexpected for the original implementor. As such debugs
+**MUST** be guarded in such a way that they can be turned off. FRR has the
+ability to turn on/off debugs from the CLI and it is expected that the
+developer will use this convention to allow control of their debugs.
Static Analysis and Sanitizers
------------------------------
CLI changes
-----------
-CLI's are a complicated ugly beast. Additions or changes to the CLI
-should use a DEFUN to encapsulate one setting as much as is possible.
-Additionally as new DEFUN's are added to the system, documentation
-should be provided for the new commands.
+CLI's are a complicated ugly beast. Additions or changes to the CLI should use
+a DEFUN to encapsulate one setting as much as is possible. Additionally as new
+DEFUN's are added to the system, documentation should be provided for the new
+commands.
Backwards Compatibility
-----------------------
-As a general principle, changes to CLI and code in the lib/ directory
-should be made in a backwards compatible fashion. This means that
-changes that are purely stylistic in nature should be avoided, e.g.,
-renaming an existing macro or library function name without any
-functional change. When adding new parameters to common functions, it is
-also good to consider if this too should be done in a backward
-compatible fashion, e.g., by preserving the old form in addition to
+As a general principle, changes to CLI and code in the lib/ directory should be
+made in a backwards compatible fashion. This means that changes that are purely
+stylistic in nature should be avoided, e.g., renaming an existing macro or
+library function name without any functional change. When adding new parameters
+to common functions, it is also good to consider if this too should be done in
+a backward compatible fashion, e.g., by preserving the old form in addition to
adding the new form.
-This is not to say that minor or even major functional changes to CLI
-and common code should be avoided, but rather that the benefit gained
-from a change should be weighed against the added cost/complexity to
-existing code. Also, that when making such changes, it is good to
-preserve compatibility when possible to do so without introducing
-maintenance overhead/cost. It is also important to keep in mind,
-existing code includes code that may reside in private repositories (and
-is yet to be submitted) or code that has yet to be migrated from Quagga
-to FRR.
-
-That said, compatibility measures can (and should) be removed when
-either:
-
-- they become a significant burden, e.g. when data structures change
- and the compatibility measure would need a complex adaptation layer
- or becomes flat-out impossible
-- some measure of time (dependent on the specific case) has passed, so
- that the compatibility grace period is considered expired.
-
-In all cases, compatibility pieces should be marked with
-compiler/preprocessor annotations to print warnings at compile time,
-pointing to the appropriate update path. A ``-Werror`` build should fail
-if compatibility bits are used. To avoid compilation issues in released
-code, such compiler/preprocessor annotations must be ignored
-non-development branches. For example:
-
- #if defined(VERSION_TYPE_DEV) && CONFDATE > 20180403
- CPP_NOTICE("Use of <XYZ> is deprecated, please use <ABC>")
- #endif
+This is not to say that minor or even major functional changes to CLI and
+common code should be avoided, but rather that the benefit gained from a change
+should be weighed against the added cost/complexity to existing code. Also,
+that when making such changes, it is good to preserve compatibility when
+possible to do so without introducing maintenance overhead/cost. It is also
+important to keep in mind, existing code includes code that may reside in
+private repositories (and is yet to be submitted) or code that has yet to be
+migrated from Quagga to FRR.
+That said, compatibility measures can (and should) be removed when either:
+
+- they become a significant burden, e.g. when data structures change and the
+ compatibility measure would need a complex adaptation layer or becomes
+ flat-out impossible
+- some measure of time (dependent on the specific case) has passed, so that
+ the compatibility grace period is considered expired.
+
+In all cases, compatibility pieces should be marked with compiler/preprocessor
+annotations to print warnings at compile time, pointing to the appropriate
+update path. A ``-Werror`` build should fail if compatibility bits are used. To
+avoid compilation issues in released code, such compiler/preprocessor
+annotations must be ignored non-development branches. For example:
+
+.. code-block:: c
+
+ #if defined(VERSION_TYPE_DEV) && CONFDATE > 20180403
+ CPP_NOTICE("Use of <XYZ> is deprecated, please use <ABC>")
+ #endif
Preferably, the shell script :file:`tools/fixup-deprecated.py` will be
updated along with making non-backwards compatible code changes, or an
Miscellaneous
-------------
-When in doubt, follow the guidelines in the Linux kernel style guide, or
-ask on the development mailing list / public Slack instance.
+When in doubt, follow the guidelines in the Linux kernel style guide, or ask on
+the development mailing list / public Slack instance.
.. _documentation:
/*
* Determines whether or not a string is cool.
*
- * @param text - the string to check for coolness
- * @param is_clccfc - whether capslock is cruise control for cool
- * @return 7 if the text is cool, 0 otherwise
+ * text
+ * the string to check for coolness
+ *
+ * is_clccfc
+ * whether capslock is cruise control for cool
+ *
+ * Returns:
+ * 7 if the text is cool, 0 otherwise
*/
int check_coolness(const char *text, bool is_clccfc);
- The Javadoc-style annotations are not required, but you should still strive
- to make it equally clear what parameters and return values are used for.
+ Function comments should make it clear what parameters and return values are
+ used for.
- Static functions should have descriptive comments in the same form as above
if what they do is not immediately obvious. Use good engineering judgement
Print program version.
+.. option:: --log <stdout|syslog|file:/path/to/log/file>
+
+ When initializing the daemon, setup the log to go to either stdout,
+ syslog or to a file. These values will be displayed as part of
+ a show run. Additionally they can be overridden at runtime if
+ desired via the normal log commands.
+
+.. option:: --log-level <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>
+
+ When initializing the daemon, allow the specification of a default
+ log level at startup from one of the specified levels.
+
.. _loadable-module-support:
Loadable Module Support
Nexthop groups are a way to encapsulate ECMP information together. It's a
listing of ECMP nexthops used to forward packets for when a pbr-map is matched.
-.. index:: nexthop-group
.. clicmd:: nexthop-group NAME
Create a nexthop-group with an associated NAME. This will put you into a
are used to are allowed here. The syntax was intentionally kept the same as
creating nexthops as you would for static routes.
+.. clicmd:: [no] pbr table range (10000-4294966272) (10000-4294966272)
+
+ Set or unset the range used to assign numeric table ID's to new
+ nexthop-group tables. Existing tables will not be modified to fit in this
+ range, so it is recommended to configure this before adding nexthop groups.
+
+ .. seealso:: :ref:`pbr-details`
+
+Showing Nexthop Group Information
+---------------------------------
+
+.. clicmd:: show pbr nexthop-groups [NAME]
+
+ Display information on a PBR nexthop-group. If ``NAME`` is omitted, all
+ nexthop groups are shown.
+
.. _pbr-maps:
PBR Maps
========
-PBR maps are a way to group policies that we would like to apply
-to individual interfaces. These policies when applied are matched
-against incoming packets. If matched the nexthop-group or nexthop
-is used to forward the packets to the end destination
+PBR maps are a way to group policies that we would like to apply to individual
+interfaces. These policies when applied are matched against incoming packets.
+If matched the nexthop-group or nexthop is used to forward the packets to the
+end destination.
-.. index:: pbr-map
.. clicmd:: pbr-map NAME seq (1-700)
Create a pbr-map with NAME and sequence number specified. This command puts
you into a new submode for pbr-map specification. To exit this mode type
exit or end as per normal conventions for leaving a sub-mode.
-.. index:: match
.. clicmd:: match src-ip PREFIX
When a incoming packet matches the source prefix specified, take the packet
Tell pim to receive IGMP reports and Query on this interface. The default
version is v3. This command is useful on the LHR.
-.. index:: ip igmp join
-.. clicmd:: ip igmp join
+.. index:: ip igmp join A.B.C.D A.B.C.D
+.. clicmd:: ip igmp join A.B.C.D A.B.C.D
Join multicast source-group on an interface.
Display the multicast RIB created in zebra.
-.. index:: mtrace
-.. clicmd:: mtrace
+.. index:: mtrace A.B.C.D [A.B.C.D]
+.. clicmd:: mtrace A.B.C.D [A.B.C.D]
- Display multicast traceroute towards source.
+ Display multicast traceroute towards source, optionally for particular group.
PIM Debug Commands
==================
int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
{
+ struct eigrp *eigrp;
struct eigrp_prefix_entry *prefix = msg->prefix;
struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
if (msg->packet_type == EIGRP_OPC_QUERY)
eigrp_send_reply(msg->adv_router, prefix);
prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
- listnode_add(
- (eigrp_lookup())->topology_changes_internalIPV4,
- prefix);
+ eigrp = eigrp_lookup();
+ assert(eigrp);
+ listnode_add(eigrp->topology_changes_internalIPV4,
+ prefix);
}
eigrp_topology_update_node_flags(prefix);
eigrp_update_routing_table(prefix);
struct eigrp_prefix_entry *pe;
struct eigrp *eigrp = eigrp_lookup();
+ if (!eigrp)
+ return;
+
if (source == INTERFACE_DOWN_BY_VTY) {
THREAD_OFF(ei->t_hello);
eigrp_hello_send(ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL);
int eigrp_sock_init(void)
{
int eigrp_sock;
- int ret, hincl = 1;
+ int ret;
+#ifdef IP_HDRINCL
+ int hincl = 1;
+#endif
if (eigrpd_privs.change(ZPRIVS_RAISE))
zlog_err("eigrp_sock_init: could not raise privs, %s",
THREAD_OFF(ep->t_retrans_timer);
XFREE(MTYPE_EIGRP_PACKET, ep);
-
- ep = NULL;
}
/* EIGRP Header verification. */
struct listnode *node, *nnode, *node2, *nnode2;
struct eigrp_interface *ei;
struct eigrp_neighbor *nbr;
- struct route_node *rn;
struct eigrp_neighbor *min = NULL;
struct eigrp *eigrp;
first = 0;
len = *length - v->namelen;
- if (len <= 0)
+ if (len == 0)
first = 1;
if (len > IN_ADDR_SIZE)
WriteMethod **write_method)
{
struct eigrp *eigrp;
- struct eigrp_interface *ei;
- struct listnode *node, *nnode;
eigrp = eigrp_lookup();
{
struct eigrp *eigrp;
struct eigrp_interface *ei;
- struct listnode *node, *nnode;
struct eigrp_neighbor *nbr;
struct in_addr nbr_addr;
unsigned int ifindex;
WriteMethod **write_method)
{
struct eigrp *eigrp;
- struct eigrp_interface *ei;
struct listnode *node, *nnode;
struct keychain *keychain;
struct list *keylist;
- int counter;
eigrp = eigrp_lookup();
struct eigrp *eigrp = eigrp_lookup();
struct route_node *rn;
+ if (!eigrp)
+ return;
+
rn = route_node_lookup(table, pe->destination);
if (!rn)
return;
struct eigrp_prefix_entry *pe;
struct route_node *rn;
+ if (!eigrp)
+ return;
+
for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
pe = rn->info;
struct eigrp_nexthop_entry *entry;
struct eigrp *eigrp = eigrp_lookup();
+ assert(eigrp);
+
for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry)) {
if (entry->reported_distance < dest->fdistance) {
// is feasible successor, can be successor
void eigrp_update_routing_table(struct eigrp_prefix_entry *prefix)
{
struct eigrp *eigrp = eigrp_lookup();
- struct list *successors =
- eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
+ struct list *successors;
struct listnode *node;
struct eigrp_nexthop_entry *entry;
+ if (!eigrp)
+ return;
+
+ successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
+
if (successors) {
eigrp_zebra_route_add(prefix->destination, successors);
for (ALL_LIST_ELEMENTS_RO(successors, node, entry))
prefixes = nbr->nbr_gr_prefixes_send;
send_prefixes = 0;
- length = EIGRP_HEADER_LEN;
/* if there already were last packet chunk, we won't continue */
if (nbr->nbr_gr_packet_type == EIGRP_PACKET_PART_LAST)
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_NETLINK_H
+#define __LINUX_NETLINK_H
+
+#include <linux/kernel.h>
+#include <linux/socket.h> /* for __kernel_sa_family_t */
+#include <linux/types.h>
+
+#define NETLINK_ROUTE 0 /* Routing/device hook */
+#define NETLINK_UNUSED 1 /* Unused number */
+#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
+#define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */
+#define NETLINK_SOCK_DIAG 4 /* socket monitoring */
+#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
+#define NETLINK_XFRM 6 /* ipsec */
+#define NETLINK_SELINUX 7 /* SELinux event notifications */
+#define NETLINK_ISCSI 8 /* Open-iSCSI */
+#define NETLINK_AUDIT 9 /* auditing */
+#define NETLINK_FIB_LOOKUP 10
+#define NETLINK_CONNECTOR 11
+#define NETLINK_NETFILTER 12 /* netfilter subsystem */
+#define NETLINK_IP6_FW 13
+#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
+#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
+#define NETLINK_GENERIC 16
+/* leave room for NETLINK_DM (DM Events) */
+#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */
+#define NETLINK_ECRYPTFS 19
+#define NETLINK_RDMA 20
+#define NETLINK_CRYPTO 21 /* Crypto layer */
+#define NETLINK_SMC 22 /* SMC monitoring */
+
+#define NETLINK_INET_DIAG NETLINK_SOCK_DIAG
+
+#define MAX_LINKS 32
+
+struct sockaddr_nl {
+ __kernel_sa_family_t nl_family; /* AF_NETLINK */
+ unsigned short nl_pad; /* zero */
+ __u32 nl_pid; /* port ID */
+ __u32 nl_groups; /* multicast groups mask */
+};
+
+struct nlmsghdr {
+ __u32 nlmsg_len; /* Length of message including header */
+ __u16 nlmsg_type; /* Message content */
+ __u16 nlmsg_flags; /* Additional flags */
+ __u32 nlmsg_seq; /* Sequence number */
+ __u32 nlmsg_pid; /* Sending process port ID */
+};
+
+/* Flags values */
+
+#define NLM_F_REQUEST 0x01 /* It is request message. */
+#define NLM_F_MULTI 0x02 /* Multipart message, terminated by NLMSG_DONE */
+#define NLM_F_ACK 0x04 /* Reply with ack, with zero or error code */
+#define NLM_F_ECHO 0x08 /* Echo this request */
+#define NLM_F_DUMP_INTR 0x10 /* Dump was inconsistent due to sequence change */
+#define NLM_F_DUMP_FILTERED 0x20 /* Dump was filtered as requested */
+
+/* Modifiers to GET request */
+#define NLM_F_ROOT 0x100 /* specify tree root */
+#define NLM_F_MATCH 0x200 /* return all matching */
+#define NLM_F_ATOMIC 0x400 /* atomic GET */
+#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
+
+/* Modifiers to NEW request */
+#define NLM_F_REPLACE 0x100 /* Override existing */
+#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */
+#define NLM_F_CREATE 0x400 /* Create, if it does not exist */
+#define NLM_F_APPEND 0x800 /* Add to end of list */
+
+/* Modifiers to DELETE request */
+#define NLM_F_NONREC 0x100 /* Do not delete recursively */
+
+/* Flags for ACK message */
+#define NLM_F_CAPPED 0x100 /* request was capped */
+#define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */
+
+/*
+ 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL
+ 4.4BSD CHANGE NLM_F_REPLACE
+
+ True CHANGE NLM_F_CREATE|NLM_F_REPLACE
+ Append NLM_F_CREATE
+ Check NLM_F_EXCL
+ */
+
+#define NLMSG_ALIGNTO 4U
+#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
+#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
+#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
+#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+ (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
+#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
+ (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
+ (nlh)->nlmsg_len <= (len))
+#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
+
+#define NLMSG_NOOP 0x1 /* Nothing. */
+#define NLMSG_ERROR 0x2 /* Error */
+#define NLMSG_DONE 0x3 /* End of a dump */
+#define NLMSG_OVERRUN 0x4 /* Data lost */
+
+#define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */
+
+struct nlmsgerr {
+ int error;
+ struct nlmsghdr msg;
+ /*
+ * followed by the message contents unless NETLINK_CAP_ACK was set
+ * or the ACK indicates success (error == 0)
+ * message length is aligned with NLMSG_ALIGN()
+ */
+ /*
+ * followed by TLVs defined in enum nlmsgerr_attrs
+ * if NETLINK_EXT_ACK was set
+ */
+};
+
+/**
+ * enum nlmsgerr_attrs - nlmsgerr attributes
+ * @NLMSGERR_ATTR_UNUSED: unused
+ * @NLMSGERR_ATTR_MSG: error message string (string)
+ * @NLMSGERR_ATTR_OFFS: offset of the invalid attribute in the original
+ * message, counting from the beginning of the header (u32)
+ * @NLMSGERR_ATTR_COOKIE: arbitrary subsystem specific cookie to
+ * be used - in the success case - to identify a created
+ * object or operation or similar (binary)
+ * @__NLMSGERR_ATTR_MAX: number of attributes
+ * @NLMSGERR_ATTR_MAX: highest attribute number
+ */
+enum nlmsgerr_attrs {
+ NLMSGERR_ATTR_UNUSED,
+ NLMSGERR_ATTR_MSG,
+ NLMSGERR_ATTR_OFFS,
+ NLMSGERR_ATTR_COOKIE,
+
+ __NLMSGERR_ATTR_MAX,
+ NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
+};
+
+#define NETLINK_ADD_MEMBERSHIP 1
+#define NETLINK_DROP_MEMBERSHIP 2
+#define NETLINK_PKTINFO 3
+#define NETLINK_BROADCAST_ERROR 4
+#define NETLINK_NO_ENOBUFS 5
+#define NETLINK_RX_RING 6
+#define NETLINK_TX_RING 7
+#define NETLINK_LISTEN_ALL_NSID 8
+#define NETLINK_LIST_MEMBERSHIPS 9
+#define NETLINK_CAP_ACK 10
+#define NETLINK_EXT_ACK 11
+
+struct nl_pktinfo {
+ __u32 group;
+};
+
+struct nl_mmap_req {
+ unsigned int nm_block_size;
+ unsigned int nm_block_nr;
+ unsigned int nm_frame_size;
+ unsigned int nm_frame_nr;
+};
+
+struct nl_mmap_hdr {
+ unsigned int nm_status;
+ unsigned int nm_len;
+ __u32 nm_group;
+ /* credentials */
+ __u32 nm_pid;
+ __u32 nm_uid;
+ __u32 nm_gid;
+};
+
+enum nl_mmap_status {
+ NL_MMAP_STATUS_UNUSED,
+ NL_MMAP_STATUS_RESERVED,
+ NL_MMAP_STATUS_VALID,
+ NL_MMAP_STATUS_COPY,
+ NL_MMAP_STATUS_SKIP,
+};
+
+#define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO
+#define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT)
+#define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr))
+
+#define NET_MAJOR 36 /* Major 36 is reserved for networking */
+
+enum {
+ NETLINK_UNCONNECTED = 0,
+ NETLINK_CONNECTED,
+};
+
+/*
+ * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ * | Header | Pad | Payload | Pad |
+ * | (struct nlattr) | ing | | ing |
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ * <-------------- nlattr->nla_len -------------->
+ */
+
+struct nlattr {
+ __u16 nla_len;
+ __u16 nla_type;
+};
+
+/*
+ * nla_type (16 bits)
+ * +---+---+-------------------------------+
+ * | N | O | Attribute Type |
+ * +---+---+-------------------------------+
+ * N := Carries nested attributes
+ * O := Payload stored in network byte order
+ *
+ * Note: The N and O flag are mutually exclusive.
+ */
+#define NLA_F_NESTED (1 << 15)
+#define NLA_F_NET_BYTEORDER (1 << 14)
+#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
+
+#define NLA_ALIGNTO 4
+#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
+#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
+
+/* Generic 32 bitflags attribute content sent to the kernel.
+ *
+ * The value is a bitmap that defines the values being set
+ * The selector is a bitmask that defines which value is legit
+ *
+ * Examples:
+ * value = 0x0, and selector = 0x1
+ * implies we are selecting bit 1 and we want to set its value to 0.
+ *
+ * value = 0x2, and selector = 0x2
+ * implies we are selecting bit 2 and we want to set its value to 1.
+ *
+ */
+struct nla_bitfield32 {
+ __u32 value;
+ __u32 selector;
+};
+
+#endif /* __LINUX_NETLINK_H */
include/linux/lwtunnel.h \
include/linux/mpls_iptunnel.h \
include/linux/neighbour.h \
+ include/linux/netlink.h \
include/linux/rtnetlink.h \
include/linux/socket.h \
include/linux/net_namespace.h \
if (del)
isis_delete_adj(adj);
- adj = NULL;
} else if (circuit->circ_type == CIRCUIT_T_P2P) {
del = false;
for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
if (del)
isis_delete_adj(adj);
-
- adj = NULL;
}
return;
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node,
ip6)) {
prefix2str((struct prefix *)ip6, (char *)buf,
- BUFSIZ);
+ sizeof(buf));
zlog_warn(" %s", buf);
}
zlog_warn(" -----");
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node,
ip6)) {
prefix2str((struct prefix *)ip6, (char *)buf,
- BUFSIZ);
+ sizeof(buf));
zlog_warn(" %s", buf);
}
zlog_warn("End of addresses");
#include "isisd/isis_mt.h"
#include "isisd/isis_tlvs.h"
-/* staticly assigned vars for printing purposes */
-char lsp_bits_string[200]; /* FIXME: enough ? */
-
static int lsp_l1_refresh(struct thread *thread);
static int lsp_l2_refresh(struct thread *thread);
static int lsp_l1_refresh_pseudo(struct thread *thread);
}
/* Convert the lsp attribute bits to attribute string */
-static const char *lsp_bits2string(uint8_t lsp_bits)
+static const char *lsp_bits2string(uint8_t lsp_bits, char *buf, size_t buf_size)
{
- char *pos = lsp_bits_string;
+ char *pos = buf;
if (!lsp_bits)
return " none";
+ if (buf_size < 2 * 3)
+ return " error";
+
/* we only focus on the default metric */
pos += sprintf(pos, "%d/",
ISIS_MASK_LSP_ATT_DEFAULT_BIT(lsp_bits) ? 1 : 0);
pos += sprintf(pos, "%d/",
ISIS_MASK_LSP_PARTITION_BIT(lsp_bits) ? 1 : 0);
- pos += sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0);
-
- *(pos) = '\0';
+ sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0);
- return lsp_bits_string;
+ return buf;
}
/* this function prints the lsp on show isis database */
{
uint8_t LSPid[255];
char age_out[8];
+ char b[200];
lspid_print(lsp->hdr.lsp_id, LSPid, dynhost, 1);
vty_out(vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' ');
vty_out(vty, "%7s ", age_out);
} else
vty_out(vty, " %5" PRIu16 " ", lsp->hdr.rem_lifetime);
- vty_out(vty, "%s\n", lsp_bits2string(lsp->hdr.lsp_bits));
+ vty_out(vty, "%s\n", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b)));
}
void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost)
uint8_t subtlv_len;
if (IS_MPLS_TE(isisMplsTE)
+ && circuit->interface != NULL
&& HAS_LINK_PARAMS(
circuit->interface))
/* Update Local and Remote IP
addr_len = sizeof(s_addr);
/* we can read directly to the stream */
- stream_recvfrom(circuit->rcv_stream, circuit->fd,
- circuit->interface->mtu, 0, (struct sockaddr *)&s_addr,
- (socklen_t *)&addr_len);
+ (void)stream_recvfrom(
+ circuit->rcv_stream, circuit->fd, circuit->interface->mtu, 0,
+ (struct sockaddr *)&s_addr, (socklen_t *)&addr_len);
if (s_addr.sll_pkttype == PACKET_OUTGOING) {
/* Read the packet into discard buff */
/*
* Triple <N, d(N), {Adj(N)}>
*/
+union isis_N {
+ uint8_t id[ISIS_SYS_ID_LEN + 1];
+ struct prefix prefix;
+};
struct isis_vertex {
enum vertextype type;
-
- union {
- uint8_t id[ISIS_SYS_ID_LEN + 1];
- struct prefix prefix;
- } N;
-
+ union isis_N N;
uint32_t d_N; /* d(N) Distance from this IS */
uint16_t depth; /* The depth in the imaginary tree */
struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */
return "UNKNOWN";
}
-static void isis_vertex_id_init(struct isis_vertex *vertex, void *id,
+static void isis_vertex_id_init(struct isis_vertex *vertex, union isis_N *n,
enum vertextype vtype)
{
vertex->type = vtype;
if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) {
- memcpy(vertex->N.id, (uint8_t *)id, ISIS_SYS_ID_LEN + 1);
+ memcpy(vertex->N.id, n->id, ISIS_SYS_ID_LEN + 1);
} else if (VTYPE_IP(vtype)) {
- memcpy(&vertex->N.prefix, (struct prefix *)id,
- sizeof(struct prefix));
+ memcpy(&vertex->N.prefix, &n->prefix, sizeof(struct prefix));
} else {
zlog_err("WTF!");
}
}
-static struct isis_vertex *isis_vertex_new(void *id, enum vertextype vtype)
+static struct isis_vertex *isis_vertex_new(union isis_N *n,
+ enum vertextype vtype)
{
struct isis_vertex *vertex;
vertex = XCALLOC(MTYPE_ISIS_VERTEX, sizeof(struct isis_vertex));
- isis_vertex_id_init(vertex, id, vtype);
+ isis_vertex_id_init(vertex, n, vtype);
vertex->Adj_N = list_new();
vertex->parents = list_new();
#ifdef EXTREME_DEBUG
char buff[PREFIX2STR_BUFFER];
#endif /* EXTREME_DEBUG */
- uint8_t id[ISIS_SYS_ID_LEN + 1];
+ union isis_N n;
- memcpy(id, sysid, ISIS_SYS_ID_LEN);
- LSP_PSEUDO_ID(id) = 0;
+ memcpy(n.id, sysid, ISIS_SYS_ID_LEN);
+ LSP_PSEUDO_ID(n.id) = 0;
lsp = isis_root_system_lsp(spftree->area, spftree->level, sysid);
if (lsp == NULL)
zlog_warn("ISIS-Spf: could not find own l%d LSP!",
spftree->level);
- vertex = isis_vertex_new(id,
+ vertex = isis_vertex_new(&n,
spftree->area->oldmetric
? VTYPE_NONPSEUDO_IS
: VTYPE_NONPSEUDO_TE_IS);
}
static struct isis_vertex *isis_find_vertex(struct isis_vertex_queue *queue,
- void *id, enum vertextype vtype)
+ union isis_N *n,
+ enum vertextype vtype)
{
struct isis_vertex querier;
- isis_vertex_id_init(&querier, id, vtype);
+ isis_vertex_id_init(&querier, n, vtype);
return hash_lookup(queue->hash, &querier);
}
{
char buff[PREFIX2STR_BUFFER];
- if (isis_find_vertex(&spftree->paths, vertex->N.id, vertex->type))
+ if (isis_find_vertex(&spftree->paths, &vertex->N, vertex->type))
return;
isis_vertex_queue_append(&spftree->paths, vertex);
vty_out(vty, "%-20s %-12s %-6u ",
vid2string(vertex, buff, sizeof(buff)),
vtype2string(vertex->type), vertex->d_N);
- for (unsigned int i = 0; i < MAX(listcount(vertex->Adj_N),
- listcount(vertex->parents));
+ for (unsigned int i = 0;
+ i < MAX(vertex->Adj_N ? listcount(vertex->Adj_N) : 0,
+ vertex->parents ? listcount(vertex->parents) : 0);
i++) {
if (anode) {
adj = listgetdata(anode);
static uint8_t print_unknown_tlv(struct sbuf *buf, int indent,
struct subtlv_header *tlvh)
{
- int i, rtn = 1;
+ int i, rtn;
uint8_t *v = (uint8_t *)tlvh;
if (tlvh->length != 0) {
struct isis_area *area;
struct isis_lsp *lsp;
struct isis_dynhn *dynhn;
- const char *pos = argv;
+ const char *pos;
uint8_t lspid[ISIS_SYS_ID_LEN + 2];
char sysid[255];
uint8_t number[3];
ldp_vty_debug(struct vty *vty, const char *negate, const char *type_str,
const char *dir_str, const char *all)
{
+ if (type_str == NULL)
+ return (CMD_WARNING_CONFIG_FAILED);
+
if (strcmp(type_str, "discovery") == 0) {
if (dir_str == NULL)
return (CMD_WARNING_CONFIG_FAILED);
int
ldp_get_address(const char *str, int *af, union ldpd_addr *addr)
{
+ if (!str || !af || !addr)
+ return (-1);
+
memset(addr, 0, sizeof(*addr));
if (inet_pton(AF_INET, str, &addr->v4) == 1) {
struct ldpd_af_conf *af_conf;
int af;
+ if (af_str == NULL)
+ return (CMD_WARNING_CONFIG_FAILED);
+
if (strcmp(af_str, "ipv4") == 0) {
af = AF_INET;
af_conf = &vty_conf->ipv4;
struct iface *iface;
struct iface_af *ia;
+ if (ifname == NULL) {
+ vty_out (vty, "%% Missing IF name\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
+
af = ldp_vty_get_af(vty);
iface = if_lookup_name(vty_conf, ifname);
if (negate)
memset(&af_conf->trans_addr, 0, sizeof(af_conf->trans_addr));
else {
- if (inet_pton(af, addr_str, &af_conf->trans_addr) != 1 ||
- bad_addr(af, &af_conf->trans_addr)) {
+ if (addr_str == NULL
+ || inet_pton(af, addr_str, &af_conf->trans_addr) != 1
+ || bad_addr(af, &af_conf->trans_addr)) {
vty_out (vty, "%% Malformed address\n");
return (CMD_SUCCESS);
}
af = ldp_vty_get_af(vty);
- if (inet_pton(af, addr_str, &addr) != 1 ||
+ if (addr_str == NULL || inet_pton(af, addr_str, &addr) != 1 ||
bad_addr(af, &addr)) {
vty_out (vty, "%% Malformed address\n");
return (CMD_WARNING_CONFIG_FAILED);
size_t password_len;
struct nbr_params *nbrp;
+ if (password_str == NULL) {
+ vty_out (vty, "%% Missing password\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
+
if (bad_addr_v4(lsr_id)) {
vty_out (vty, "%% Malformed address\n");
return (CMD_WARNING_CONFIG_FAILED);
struct l2vpn_if *lif;
struct l2vpn_pw *pw;
+ if (name_str == NULL) {
+ vty_out (vty, "%% Missing name\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
+
l2vpn = l2vpn_find(vty_conf, name_str);
if (negate) {
if (negate)
memset(l2vpn->br_ifname, 0, sizeof(l2vpn->br_ifname));
- else
+ else {
+ if (ifname == NULL) {
+ vty_out (vty, "%% Missing IF name\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
strlcpy(l2vpn->br_ifname, ifname, sizeof(l2vpn->br_ifname));
+ }
ldp_config_apply(vty, vty_conf);
VTY_DECLVAR_CONTEXT(l2vpn, l2vpn);
int pw_type;
+ if (type_str == NULL) {
+ vty_out (vty, "%% Missing type\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
+
if (strcmp(type_str, "ethernet") == 0)
pw_type = PW_TYPE_ETHERNET;
else
VTY_DECLVAR_CONTEXT(l2vpn, l2vpn);
struct l2vpn_if *lif;
+ if (ifname == NULL) {
+ vty_out (vty, "%% Missing IF name\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
+
lif = l2vpn_if_find(l2vpn, ifname);
if (negate) {
VTY_DECLVAR_CONTEXT(l2vpn, l2vpn);
struct l2vpn_pw *pw;
+ if (ifname == NULL) {
+ vty_out (vty, "%% Missing IF name\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
+
pw = l2vpn_pw_find(l2vpn, ifname);
if (negate) {
if (negate)
pw->flags |= F_PW_CWORD_CONF;
else {
+ if (!preference_str) {
+ vty_out (vty, "%% Missing preference\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
if (preference_str[0] == 'e')
pw->flags &= ~F_PW_CWORD_CONF;
else
.privs = &ldpd_privs,
)
+static int ldp_config_fork_apply(struct thread *t)
+{
+ /*
+ * So the frr_config_fork() function schedules
+ * the read of the vty config( if there is a
+ * non-integrated config ) to be after the
+ * end of startup and we are starting the
+ * main process loop. We need to schedule
+ * the application of this if necessary
+ * after the read in of the config.
+ */
+ ldp_config_apply(NULL, vty_conf);
+
+ return 0;
+}
+
int
main(int argc, char *argv[])
{
int pipe_parent2ldpe[2], pipe_parent2ldpe_sync[2];
int pipe_parent2lde[2], pipe_parent2lde_sync[2];
char *ctl_sock_name;
+ struct thread *thread = NULL;
ldpd_process = PROC_MAIN;
log_procname = log_procnames[ldpd_process];
frr_config_fork();
/* apply configuration */
- ldp_config_apply(NULL, vty_conf);
+ thread_add_event(master, ldp_config_fork_apply, NULL, 0, &thread);
/* setup pipes to children */
if ((iev_ldpe = calloc(1, sizeof(struct imsgev))) == NULL ||
free(vty_conf);
log_debug("waiting for children to terminate");
- do {
+
+ while (true) {
+ /* Wait for child process. */
pid = wait(&status);
if (pid == -1) {
- if (errno != EINTR && errno != ECHILD)
- fatal("wait");
- } else if (WIFSIGNALED(status))
+ /* We got interrupted, try again. */
+ if (errno == EINTR)
+ continue;
+ /* No more processes were found. */
+ if (errno != ECHILD)
+ break;
+
+ /* Unhandled errno condition. */
+ fatal("wait");
+ /* UNREACHABLE */
+ }
+
+ /* We found something, lets announce it. */
+ if (WIFSIGNALED(status))
log_warnx("%s terminated; signal %d",
- (pid == lde_pid) ? "label decision engine" :
- "ldp engine", WTERMSIG(status));
- } while (pid != -1 || (pid == -1 && errno == EINTR));
+ (pid == lde_pid ? "label decision engine"
+ : "ldp engine"),
+ WTERMSIG(status));
+
+ /* Repeat until there are no more child processes. */
+ }
free(iev_ldpe);
free(iev_lde);
/* reschedule read */
*threadp = NULL;
- thread_add_read(master, disc_recv_packet, threadp, fd, &*threadp);
+ thread_add_read(master, disc_recv_packet, threadp, fd, threadp);
/* setup buffer */
memset(&m, 0, sizeof(m));
#define pychar wchar_t
static wchar_t *wconv(const char *s)
{
- size_t outlen = mbstowcs(NULL, s, 0);
+ size_t outlen = s ? mbstowcs(NULL, s, 0) : 0;
wchar_t *out = malloc((outlen + 1) * sizeof(wchar_t));
- mbstowcs(out, s, outlen + 1);
+
+ if (outlen > 0)
+ mbstowcs(out, s, outlen);
out[outlen] = 0;
return out;
}
char *argv_concat(struct cmd_token **argv, int argc, int shift)
{
- int cnt = argc - shift;
- const char *argstr[cnt];
+ int cnt = MAX(argc - shift, 0);
+ const char *argstr[cnt + 1];
+
+ if (!cnt)
+ return NULL;
for (int i = 0; i < cnt; i++)
argstr[i] = argv[i + shift]->arg;
host.enable);
}
- if (zlog_default->default_lvl != LOG_DEBUG) {
- vty_out(vty,
- "! N.B. The 'log trap' command is deprecated.\n");
- vty_out(vty, "log trap %s\n",
- zlog_priority[zlog_default->default_lvl]);
- }
-
if (host.logfile
&& (zlog_default->maxlvl[ZLOG_DEST_FILE]
!= ZLOG_DISABLED)) {
XFREE(MTYPE_TMP, p);
if (!ret) {
- vty_out(vty, "can't open logfile %s\n", fname);
+ if (vty)
+ vty_out(vty, "can't open logfile %s\n", fname);
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
}
+void command_setup_early_logging(const char *dest, const char *level)
+{
+ char *token;
+
+ if (level) {
+ int nlevel = level_match(level);
+
+ if (nlevel != ZLOG_DISABLED)
+ zlog_default->default_lvl = nlevel;
+ }
+
+ if (!dest)
+ return;
+
+ if (strcmp(dest, "stdout") == 0) {
+ zlog_set_level(ZLOG_DEST_STDOUT, zlog_default->default_lvl);
+ return;
+ }
+
+ if (strcmp(dest, "syslog") == 0) {
+ zlog_set_level(ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
+ return;
+ }
+
+ token = strstr(dest, ":");
+ if (token == NULL)
+ return;
+
+ token++;
+
+ set_log_file(NULL, token, zlog_default->default_lvl);
+}
+
DEFUN (config_log_file,
config_log_file_cmd,
"log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
return CMD_SUCCESS;
}
-DEFUN_DEPRECATED(
- config_log_trap, config_log_trap_cmd,
- "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
- "Logging control\n"
- "(Deprecated) Set logging level and default for all destinations\n" LOG_LEVEL_DESC)
-{
- int new_level;
- int i;
-
- if ((new_level = level_match(argv[2]->arg)) == ZLOG_DISABLED)
- return CMD_ERR_NO_MATCH;
-
- zlog_default->default_lvl = new_level;
- for (i = 0; i < ZLOG_NUM_DESTS; i++)
- if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
- zlog_default->maxlvl[i] = new_level;
- return CMD_SUCCESS;
-}
-
-DEFUN_DEPRECATED(
- no_config_log_trap, no_config_log_trap_cmd,
- "no log trap [emergencies|alerts|critical|errors|warnings|notifications|informational|debugging]",
- NO_STR
- "Logging control\n"
- "Permit all logging information\n" LOG_LEVEL_DESC)
-{
- zlog_default->default_lvl = LOG_DEBUG;
- return CMD_SUCCESS;
-}
-
DEFUN (config_log_record_priority,
config_log_record_priority_cmd,
"log record-priority",
install_element(CONFIG_NODE, &no_config_log_syslog_cmd);
install_element(CONFIG_NODE, &config_log_facility_cmd);
install_element(CONFIG_NODE, &no_config_log_facility_cmd);
- install_element(CONFIG_NODE, &config_log_trap_cmd);
- install_element(CONFIG_NODE, &no_config_log_trap_cmd);
install_element(CONFIG_NODE, &config_log_record_priority_cmd);
install_element(CONFIG_NODE,
&no_config_log_record_priority_cmd);
#define DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
-#define DEFUN_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \
- DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED)
-
/* DEFUN_NOSH for commands that vtysh should ignore */
#define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \
DEFUN(funcname, cmdname, cmdstr, helpstr)
cmd_variable_handler_register(const struct cmd_variable_handler *cvh);
extern char *cmd_variable_comp2str(vector comps, unsigned short cols);
+extern void command_setup_early_logging(const char *dest, const char *level);
#endif /* _ZEBRA_COMMAND_H */
static struct list *disambiguate(struct list *first, struct list *second,
vector vline, unsigned int n)
{
+ assert(first != NULL);
+ assert(second != NULL);
// doesn't make sense for these to be inequal length
assert(first->count == second->count);
assert(first->count == vector_active(vline) - n + 1);
- struct listnode *fnode = listhead(first), *snode = listhead(second);
+ struct listnode *fnode = listhead_unchecked(first),
+ *snode = listhead_unchecked(second);
struct cmd_token *ftok = listgetdata(fnode), *stok = listgetdata(snode),
*best = NULL;
log_verbose("Mem: %d\n", get_memory_usage(getpid()));
csv_init(&csv, buf, 256);
- sprintf(hdr1, "%4u", 0);
- sprintf(hdr2, "%4u", 1);
+ sprintf(hdr1, "%4d", 0);
+ sprintf(hdr2, "%4d", 1);
log_verbose("(%zu/%zu/%d/%d)\n", strlen(hdr1), strlen(hdr2), atoi(hdr1),
atoi(hdr2));
rec = csv_encode(&csv, 2, hdr1, hdr2);
}
csv_encode(&csv, 2, "pdfadfadfadsadsaddfdfdsfdsd", "35444554545454545");
log_verbose("%s\n", buf);
- sprintf(hdr1, "%4u", csv.csv_len);
- sprintf(hdr2, "%4u", 1);
+ sprintf(hdr1, "%4d", csv.csv_len);
+ sprintf(hdr2, "%4d", 1);
log_verbose("(%zu/%zu/%d/%d)\n", strlen(hdr1), strlen(hdr2), atoi(hdr1),
atoi(hdr2));
rec = csv_encode_record(&csv, rec, 2, hdr1, hdr2);
{
thread_add_event(fpt->master, &fpt_finish, fpt, 0, NULL);
pthread_join(fpt->thread, res);
- fpt = NULL;
return 0;
}
cb = *cbp;
else {
cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
- cb->write.cancelled = 1;
if (!cb)
return -1;
+
+ cb->write.cancelled = 1;
*cbp = cb;
}
cb = *cbp;
else {
cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
- cb->read.cancelled = 1;
if (!cb)
return -1;
+
+ cb->read.cancelled = 1;
*cbp = cb;
}
size_t len = 0;
size_t joinlen = join ? strlen(join) : 0;
+ if (!argc)
+ return NULL;
+
for (i = 0; i < argc; i++)
len += strlen(parts[i]);
len += argc * joinlen + 1;
return strncmp(str, prefix, lenprefix) == 0;
}
+
+int all_digit(const char *str)
+{
+ for (; *str != '\0'; str++)
+ if (!isdigit((int)*str))
+ return 0;
+ return 1;
+}
*/
bool begins_with(const char *str, const char *prefix);
+/*
+ * Check the string only contains digit characters.
+ *
+ * str
+ * string to check for digits
+ *
+ * Returns:
+ * 1 str only contains digit characters, 0 otherwise
+ */
+int all_digit(const char *str);
+
#endif /* _FRRSTR_H_ */
unsigned int i;
struct hash_backet *hb;
struct hash_backet *hbnext;
+ uint32_t count = 0;
- for (i = 0; i < hash->size; i++)
+ for (i = 0; i < hash->size; i++) {
for (hb = hash->index[i]; hb; hb = hbnext) {
/* get pointer to next hash backet here, in case (*func)
* decides to delete hb by calling hash_release
*/
hbnext = hb->next;
(*func)(hb, arg);
+ count++;
+
}
+ if (count == hash->count)
+ return;
+ }
}
void hash_walk(struct hash *hash, int (*func)(struct hash_backet *, void *),
struct hash_backet *hb;
struct hash_backet *hbnext;
int ret = HASHWALK_CONTINUE;
+ uint32_t count = 0;
for (i = 0; i < hash->size; i++) {
for (hb = hash->index[i]; hb; hb = hbnext) {
ret = (*func)(hb, arg);
if (ret == HASHWALK_ABORT)
return;
+ count++;
}
+ if (count == hash->count)
+ return;
}
}
char buf[CMSG_SPACE(sizeof(int) * 1)];
} cmsgbuf;
struct iovec iov;
- ssize_t n = -1;
+ ssize_t n;
int fd;
struct imsg_fd *ifd;
return (-1);
}
- if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
+ n = recvmsg(ibuf->fd, &msg, 0);
+ if (n == -1) {
if (errno == EINTR)
goto again;
goto fail;
#define OPTION_VTYSOCK 1000
#define OPTION_MODULEDIR 1002
+#define OPTION_LOG 1003
+#define OPTION_LOGLEVEL 1004
static const struct option lo_always[] = {
{"help", no_argument, NULL, 'h'},
{"module", no_argument, NULL, 'M'},
{"vty_socket", required_argument, NULL, OPTION_VTYSOCK},
{"moduledir", required_argument, NULL, OPTION_MODULEDIR},
+ {"log", required_argument, NULL, OPTION_LOG},
+ {"log-level", required_argument, NULL, OPTION_LOGLEVEL},
{NULL}};
static const struct optspec os_always = {
"hvdM:",
" -d, --daemon Runs in daemon mode\n"
" -M, --module Load specified module\n"
" --vty_socket Override vty socket path\n"
- " --moduledir Override modules directory\n",
+ " --moduledir Override modules directory\n"
+ " --log Set Logging to stdout, syslog, or file:<name>\n"
+ " --log-level Set Logging Level to use, debug, info, warn, etc\n",
lo_always};
return 1;
di->privs->group = optarg;
break;
+ case OPTION_LOG:
+ di->early_logging = optarg;
+ break;
+ case OPTION_LOGLEVEL:
+ di->early_loglevel = optarg;
+ break;
default:
return 1;
}
openzlog(di->progname, di->logname, di->instance,
LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
-#if defined(HAVE_CUMULUS)
- zlog_set_level(ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
-#endif
+
+ command_setup_early_logging(di->early_logging, di->early_loglevel);
if (!frr_zclient_addr(&zclient_addr, &zclient_addr_len,
frr_zclientpath)) {
frr_daemon_wait(fds[0]);
}
+/*
+ * Why is this a thread?
+ *
+ * The read in of config for integrated config happens *after*
+ * thread execution starts( because it is passed in via a vtysh -b -n )
+ * While if you are not using integrated config we want the ability
+ * to read the config in after thread execution starts, so that
+ * we can match this behavior.
+ */
+static int frr_config_read_in(struct thread *t)
+{
+ if (!vty_read_config(di->config_file, config_default) &&
+ di->backup_config_file) {
+ zlog_info("Attempting to read backup config file: %s specified",
+ di->backup_config_file);
+ vty_read_config(di->backup_config_file, config_default);
+ }
+ return 0;
+}
+
void frr_config_fork(void)
{
hook_call(frr_late_init, master);
- vty_read_config(di->config_file, config_default);
-
/* Don't start execution if we are in dry-run mode */
- if (di->dryrun)
+ if (di->dryrun) {
+ frr_config_read_in(NULL);
exit(0);
+ }
+
+ thread_add_event(master, frr_config_read_in, NULL, 0, &di->read_in);
if (di->daemon_mode || di->terminal)
frr_daemonize();
switch (buf[0]) {
case 'S': /* SIGTSTP */
vty_stdio_suspend();
- send(daemon_ctl_sock, "s", 1, 0);
+ if (send(daemon_ctl_sock, "s", 1, 0) < 0)
+ zlog_err("%s send(\"s\") error (SIGTSTP propagation)",
+ (di && di->name ? di->name : ""));
break;
case 'R': /* SIGTCNT [implicit] */
vty_stdio_resume();
bool dryrun;
bool daemon_mode;
bool terminal;
+
+ struct thread *read_in;
const char *config_file;
+ const char *backup_config_file;
const char *pid_file;
const char *vty_path;
const char *module_path;
const char *pathspace;
+ const char *early_logging;
+ const char *early_loglevel;
const char *proghelp;
void (*printhelp)(FILE *target);
void listnode_delete(struct list *list, void *val)
{
- struct listnode *node;
+ struct listnode *node = listnode_lookup(list, val);
- assert(list);
- for (node = list->head; node; node = node->next) {
- if (node->data == val) {
- if (node->prev)
- node->prev->next = node->next;
- else
- list->head = node->next;
-
- if (node->next)
- node->next->prev = node->prev;
- else
- list->tail = node->prev;
-
- list->count--;
- listnode_free(node);
- return;
- }
- }
+ if (node)
+ list_delete_node(list, node);
}
void *listnode_head(struct list *list)
};
#define listnextnode(X) ((X) ? ((X)->next) : NULL)
+#define listnextnode_unchecked(X) ((X)->next)
#define listhead(X) ((X) ? ((X)->head) : NULL)
+#define listhead_unchecked(X) ((X)->head)
#define listtail(X) ((X) ? ((X)->tail) : NULL)
#define listcount(X) ((X)->count)
#define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL)
#ifndef _PBR_H
#define _PBR_H
+#include <zebra.h>
+#include "stream.h"
+#include "prefix.h"
+
+#define PBR_STR "Policy Based Routing\n"
+
/*
* A PBR filter
*
uint32_t ifindex;
};
+/* TCP flags value shared
+ * those are values of byte 13 of TCP header
+ * as mentioned in rfc793
+ */
+#define TCP_HEADER_FIN (0x01)
+#define TCP_HEADER_SYN (0x02)
+#define TCP_HEADER_RST (0x04)
+#define TCP_HEADER_PSH (0x08)
+#define TCP_HEADER_ACK (0x10)
+#define TCP_HEADER_URG (0x20)
+#define TCP_HEADER_ALL_FLAGS (TCP_HEADER_FIN | TCP_HEADER_SYN \
+ | TCP_HEADER_RST | TCP_HEADER_PSH \
+ | TCP_HEADER_ACK | TCP_HEADER_URG)
+
+/* Pbr IPTable defines
+ * those are common flags shared between BGP and Zebra
+ */
+#define MATCH_IP_SRC_SET (1 << 0)
+#define MATCH_IP_DST_SET (1 << 1)
+#define MATCH_PORT_SRC_SET (1 << 2)
+#define MATCH_PORT_DST_SET (1 << 3)
+#define MATCH_PORT_SRC_RANGE_SET (1 << 4)
+#define MATCH_PORT_DST_RANGE_SET (1 << 5)
+#define MATCH_DSCP_SET (1 << 6)
+#define MATCH_DSCP_INVERSE_SET (1 << 7)
+#define MATCH_PKT_LEN_INVERSE_SET (1 << 8)
+#define MATCH_FRAGMENT_INVERSE_SET (1 << 9)
+#define MATCH_ICMP_SET (1 << 10)
+
extern int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s,
struct pbr_rule *zrule);
int lenum = 0;
int genum = 0;
+ if (name == NULL || prefix == NULL || typestr == NULL) {
+ vty_out(vty, "%% Missing prefix or type\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
/* Sequential number. */
if (seq)
seqnum = (int64_t)atol(seq);
{
int ret;
+ if (!str || !p)
+ return 0;
+
/* First we try to convert string to struct prefix_ipv4. */
ret = str2prefix_ipv4(str, (struct prefix_ipv4 *)p);
if (ret)
XFREE(MTYPE_PREFIX, p);
}
-/* Utility function. Check the string only contains digit
- * character.
- * FIXME str.[c|h] would be better place for this function. */
-int all_digit(const char *str)
-{
- for (; *str != '\0'; str++)
- if (!isdigit((int)*str))
- return 0;
- return 1;
-}
-
/* Utility function to convert ipv4 prefixes to Classful prefixes */
void apply_classful_mask_ipv4(struct prefix_ipv4 *p)
{
return 0;
}
-extern int all_digit(const char *);
extern int macstr2prefix_evpn(const char *str, struct prefix_evpn *p);
/* NOTE: This routine expects the address argument in network byte order. */
#ifdef HAVE_CAPABILITIES
zprivs_caps_init(zprivs);
+
+ /*
+ * If we have initialized the system with no requested
+ * capabilities, change will not have been set
+ * to anything by zprivs_caps_init, As such
+ * we should make sure that when we attempt
+ * to raize privileges that we actually have
+ * a do nothing function to call instead of a
+ * crash :).
+ */
+ if (!zprivs->change)
+ zprivs->change = zprivs_change_null;
+
#else /* !HAVE_CAPABILITIES */
/* we dont have caps. we'll need to maintain rid and saved uid
* and change euid back to saved uid (who we presume has all neccessary
char client_buf[32];
csv_record_t *rec1;
- sprintf(msglen_buf, "%4u", msglen);
- sprintf(vers_buf, "%4u", version);
- sprintf(type_buf, "%4u", type);
- sprintf(cmdid_buf, "%4u", cmd_id);
+ sprintf(msglen_buf, "%4d", msglen);
+ sprintf(vers_buf, "%4d", version);
+ sprintf(type_buf, "%4d", type);
+ sprintf(cmdid_buf, "%4d", cmd_id);
snprintf(client_buf, 17, "%16.16s", client_name);
if (rec) {
rec1 = csv_encode_record(csv, rec, 5, msglen_buf, vers_buf,
return map;
}
-int route_map_mark_updated(const char *name, int del_later)
+int route_map_mark_updated(const char *name)
{
struct route_map *map;
int ret = -1;
return (ret);
}
-int route_map_clear_updated(struct route_map *map)
+static int route_map_clear_updated(struct route_map *map)
{
int ret = -1;
return map;
}
-void route_map_walk_update_list(int (*route_map_update_fn)(char *name))
+void route_map_walk_update_list(void (*route_map_update_fn)(char *name))
{
struct route_map *node;
struct route_map *nnode = NULL;
extern void route_map_add_hook(void (*func)(const char *));
extern void route_map_delete_hook(void (*func)(const char *));
extern void route_map_event_hook(void (*func)(route_map_event_t, const char *));
-extern int route_map_mark_updated(const char *name, int deleted);
-extern int route_map_clear_updated(struct route_map *rmap);
-extern void route_map_walk_update_list(int (*update_fn)(char *name));
+extern int route_map_mark_updated(const char *name);
+extern void route_map_walk_update_list(void (*update_fn)(char *name));
extern void route_map_upd8_dependency(route_map_event_t type, const char *arg,
const char *rmap_name);
extern void route_map_notify_dependencies(const char *affected_name,
int written;
if (!buf->fixed) {
- char dummy;
int written1, written2;
size_t new_size;
- written1 = snprintf(&dummy, 0, "%*s", indent, "");
+ written1 = indent;
va_start(args, format);
- written2 = vsnprintf(&dummy, 0, format, args);
+ written2 = vsnprintf(NULL, 0, format, args);
va_end(args);
new_size = buf->size;
int quagga_signal_timer(struct thread *t)
{
struct quagga_sigevent_master_t *sigm;
- struct quagga_signal_t *sig;
- int i;
sigm = THREAD_ARG(t);
sigm->t = NULL;
*/
static ifindex_t getsockopt_ipv4_ifindex(struct msghdr *msgh)
{
- /* XXX: initialize to zero? (Always overwritten, so just cosmetic.) */
- ifindex_t ifindex = -1;
+ ifindex_t ifindex;
#if defined(IP_PKTINFO)
/* Linux pktinfo based ifindex retrieval */
pktinfo = (struct in_pktinfo *)getsockopt_cmsg_data(msgh, IPPROTO_IP,
IP_PKTINFO);
- /* XXX Can pktinfo be NULL? Clean up post 0.98. */
+
+ /* getsockopt_ifindex() will forward this, being 0 "not found" */
+ if (pktinfo == NULL)
+ return 0;
+
ifindex = pktinfo->ipi_ifindex;
#elif defined(IP_RECVIF)
{
int ret;
+ if (str == NULL)
+ return -1;
+
memset(su, 0, sizeof(union sockunion));
ret = inet_pton(AF_INET, str, &su->sin.sin_addr);
/* Add new stream to fifo. */
void stream_fifo_push(struct stream_fifo *fifo, struct stream *s)
{
+#if defined DEV_BUILD
+ size_t max, curmax;
+#endif
+
if (fifo->tail)
fifo->tail->next = s;
else
fifo->tail = s;
fifo->tail->next = NULL;
-
+#if !defined DEV_BUILD
atomic_fetch_add_explicit(&fifo->count, 1, memory_order_release);
+#else
+ max = atomic_fetch_add_explicit(&fifo->count, 1, memory_order_release);
+ curmax = atomic_load_explicit(&fifo->max_count, memory_order_relaxed);
+ if (max > curmax)
+ atomic_store_explicit(&fifo->max_count, max,
+ memory_order_relaxed);
+#endif
}
void stream_fifo_push_safe(struct stream_fifo *fifo, struct stream *s)
/* number of streams in this fifo */
_Atomic size_t count;
+#if defined DEV_BUILD
+ _Atomic size_t max_count;
+#endif
struct stream *head;
struct stream *tail;
lib/libfrr.la
lib_clippy_CPPFLAGS = $(AM_CPPFLAGS) -D_GNU_SOURCE -DBUILDING_CLIPPY @SAN_CLIPPY_FLAGS@
-lib_clippy_CFLAGS = $(PYTHON_CFLAGS) $(AM_CFLAGS) @SAN_CLIPPY_FLAGS@
+lib_clippy_CFLAGS = $(PYTHON_CFLAGS) @SAN_CLIPPY_FLAGS@
lib_clippy_LDADD = $(PYTHON_LIBS)
lib_clippy_SOURCES = \
lib/clippy.c \
return CMD_SUCCESS;
}
+static void show_thread_poll_helper(struct vty *vty, struct thread_master *m)
+{
+ const char *name = m->name ? m->name : "main";
+ char underline[strlen(name) + 1];
+ uint32_t i;
+
+ memset(underline, '-', sizeof(underline));
+ underline[sizeof(underline) - 1] = '\0';
+
+ vty_out(vty, "\nShowing poll FD's for %s\n", name);
+ vty_out(vty, "----------------------%s\n", underline);
+ vty_out(vty, "Count: %u\n", (uint32_t)m->handler.pfdcount);
+ for (i = 0; i < m->handler.pfdcount; i++)
+ vty_out(vty, "\t%6d fd:%6d events:%2d revents:%2d\n", i,
+ m->handler.pfds[i].fd,
+ m->handler.pfds[i].events,
+ m->handler.pfds[i].revents);
+}
+
+DEFUN (show_thread_poll,
+ show_thread_poll_cmd,
+ "show thread poll",
+ SHOW_STR
+ "Thread information\n"
+ "Show poll FD's and information\n")
+{
+ struct listnode *node;
+ struct thread_master *m;
+
+ pthread_mutex_lock(&masters_mtx);
+ {
+ for (ALL_LIST_ELEMENTS_RO(masters, node, m)) {
+ show_thread_poll_helper(vty, m);
+ }
+ }
+ pthread_mutex_unlock(&masters_mtx);
+
+ return CMD_SUCCESS;
+}
+
+
DEFUN (clear_thread_cpu,
clear_thread_cpu_cmd,
"clear thread cpu [FILTER]",
void thread_cmd_init(void)
{
install_element(VIEW_NODE, &show_thread_cpu_cmd);
+ install_element(VIEW_NODE, &show_thread_poll_cmd);
install_element(ENABLE_NODE, &clear_thread_cpu_cmd);
}
/* CLI end ------------------------------------------------------------------ */
}
/* Read up configuration file from file_name. */
-void vty_read_config(const char *config_file, char *config_default_dir)
+bool vty_read_config(const char *config_file, char *config_default_dir)
{
char cwd[MAXPATHLEN];
FILE *confp = NULL;
const char *fullpath;
char *tmp = NULL;
+ bool read_success = false;
/* If -f flag specified. */
if (config_file != NULL) {
if (strstr(config_default_dir, "vtysh") == NULL) {
ret = stat(integrate_default, &conf_stat);
- if (ret >= 0)
+ if (ret >= 0) {
+ read_success = true;
goto tmp_free_and_out;
+ }
}
#endif /* VTYSH */
confp = fopen(config_default_dir, "r");
}
vty_read_file(confp);
+ read_success = true;
fclose(confp);
tmp_free_and_out:
if (tmp)
XFREE(MTYPE_TMP, tmp);
+
+ return read_success;
}
/* Small utility function which output log to the VTY. */
extern void vty_endframe(struct vty *, const char *);
bool vty_set_include(struct vty *vty, const char *regexp);
-extern void vty_read_config(const char *, char *);
+extern bool 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 *);
extern void vty_close(struct vty *);
#define SET_FLAG(V,F) (V) |= (F)
#define UNSET_FLAG(V,F) (V) &= ~(F)
#define RESET_FLAG(V) (V) = 0
+#define COND_FLAG(V, F, C) ((C) ? (SET_FLAG(V, F)) : (UNSET_FLAG(V, F)))
/* Atomic flag manipulation macros. */
#define CHECK_FLAG_ATOMIC(PV, F) \
return;
}
- for (i = 0; he->h_addr_list[i] != NULL && i < ZEBRA_NUM_OF(addr); i++) {
+ for (i = 0; i < ZEBRA_NUM_OF(addr) && he->h_addr_list[i] != NULL; i++) {
memset(&addr[i], 0, sizeof(addr[i]));
addr[i].sa.sa_family = he->h_addrtype;
switch (he->h_addrtype) {
char buf[32];
struct handle_sa_ctx ctx = {
.event = event,
+ .msgctx.nsections = 0
};
vici_parse_message(vici, msg, parse_sa_message, &ctx.msgctx);
&& route->type != OSPF6_DEST_TYPE_RANGE
&& ((route->type != OSPF6_DEST_TYPE_ROUTER)
|| !CHECK_FLAG(route->path.router_bits, OSPF6_ROUTER_BIT_E))) {
- if (is_debug)
- zlog_debug(
- "Route type is none of network, range nor ASBR, ignore");
+#if 0
+ zlog_debug(
+ "Route type is none of network, range nor ASBR, ignore");
+#endif
return 0;
}
/* do not generate if the path's area is the same as target area */
if (route->path.area_id == area->area_id) {
- if (is_debug)
- zlog_debug("The route is in the area itself, ignore");
+#if 0
+ zlog_debug("The route is in the area itself, ignore");
+#endif
return 0;
}
/* do not generate if the nexthops belongs to the target area */
if (ospf6_abr_nexthops_belong_to_area(route, area)) {
- if (is_debug)
- zlog_debug(
- "The route's nexthop is in the same area, ignore");
+#if 0
+ zlog_debug("The route's nexthop is in the same area, ignore");
+#endif
return 0;
}
if (route->type == OSPF6_DEST_TYPE_NETWORK) {
oa = ospf6_area_lookup(route->path.area_id, ospf6);
+ if (!oa) {
+ zlog_err("OSPFv6 area lookup failed");
+ return;
+ }
+
range = ospf6_route_lookup_bestmatch(&route->prefix,
oa->range_table);
if (range) {
lsa->header);
prefix.family = AF_INET6;
prefix.prefixlen = prefix_lsa->prefix.prefix_length;
- ospf6_prefix_in6_addr(&prefix.u.prefix6, &prefix_lsa->prefix);
+ ospf6_prefix_in6_addr(&prefix.u.prefix6, prefix_lsa,
+ &prefix_lsa->prefix);
if (is_debug)
prefix2str(&prefix, buf, sizeof(buf));
table = oa->ospf6->route_table;
(struct ospf6_inter_prefix_lsa *)OSPF6_LSA_HEADER_END(
lsa->header);
- ospf6_prefix_in6_addr(&in6, &prefix_lsa->prefix);
+ ospf6_prefix_in6_addr(&in6, prefix_lsa, &prefix_lsa->prefix);
if (buf) {
inet_ntop(AF_INET6, &in6, buf, buflen);
sprintf(&buf[strlen(buf)], "/%d",
route->type = OSPF6_DEST_TYPE_NETWORK;
route->prefix.family = AF_INET6;
route->prefix.prefixlen = external->prefix.prefix_length;
- ospf6_prefix_in6_addr(&route->prefix.u.prefix6, &external->prefix);
+ ospf6_prefix_in6_addr(&route->prefix.u.prefix6, external,
+ &external->prefix);
route->path.area_id = asbr_entry->path.area_id;
route->path.origin.type = lsa->header->type;
route_to_del->type = OSPF6_DEST_TYPE_NETWORK;
route_to_del->prefix.family = AF_INET6;
route_to_del->prefix.prefixlen = external->prefix.prefix_length;
- ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6,
+ ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6, external,
&external->prefix);
route_to_del->path.origin.type = lsa->header->type;
memset(&prefix, 0, sizeof(struct prefix));
prefix.family = AF_INET6;
prefix.prefixlen = external->prefix.prefix_length;
- ospf6_prefix_in6_addr(&prefix.u.prefix6, &external->prefix);
+ ospf6_prefix_in6_addr(&prefix.u.prefix6, external, &external->prefix);
route = ospf6_route_lookup(&prefix, ospf6->route_table);
if (route == NULL) {
lsa->header);
if (pos == 0) {
- ospf6_prefix_in6_addr(&in6, &external->prefix);
+ ospf6_prefix_in6_addr(&in6, external,
+ &external->prefix);
prefix_length = external->prefix.prefix_length;
} else {
in6 = *((struct in6_addr
"Received is newer, remove requesting");
if (req == on->last_ls_req) {
ospf6_lsa_unlock(req);
+ req = NULL;
on->last_ls_req = NULL;
}
if (req)
g_route = ospf6_route_lookup(&oa_route->prefix,
ospf6->route_table);
+ assert(g_route);
+
for (ospf6_route_lock(g_route); g_route &&
ospf6_route_is_prefix(&oa_route->prefix, g_route);
g_route = nroute) {
memset(&route->prefix, 0, sizeof(struct prefix));
route->prefix.family = AF_INET6;
route->prefix.prefixlen = op->prefix_length;
- ospf6_prefix_in6_addr(&route->prefix.u.prefix6, op);
+ ospf6_prefix_in6_addr(&route->prefix.u.prefix6,
+ intra_prefix_lsa, op);
route->type = OSPF6_DEST_TYPE_NETWORK;
route->path.origin.type = lsa->header->type;
memset(&prefix, 0, sizeof(struct prefix));
prefix.family = AF_INET6;
prefix.prefixlen = op->prefix_length;
- ospf6_prefix_in6_addr(&prefix.u.prefix6, op);
+ ospf6_prefix_in6_addr(&prefix.u.prefix6, intra_prefix_lsa, op);
route = ospf6_route_lookup(&prefix, oa->route_table);
if (route == NULL)
#include "ospf6_proto.h"
+void ospf6_prefix_in6_addr(struct in6_addr *in6, const void *prefix_buf,
+ const struct ospf6_prefix *p)
+{
+ ptrdiff_t in6_off = (caddr_t)p->addr - (caddr_t)prefix_buf;
+
+ memset(in6, 0, sizeof(struct in6_addr));
+ memcpy(in6, (uint8_t *)prefix_buf + in6_off,
+ OSPF6_PREFIX_SPACE(p->prefix_length));
+}
+
void ospf6_prefix_apply_mask(struct ospf6_prefix *op)
{
uint8_t *pnt, mask;
#define OSPF6_PREFIX_NEXT(x) \
((struct ospf6_prefix *)((caddr_t)(x) + OSPF6_PREFIX_SIZE(x)))
-#define ospf6_prefix_in6_addr(in6, op) \
- do { \
- memset(in6, 0, sizeof(struct in6_addr)); \
- memcpy(in6, (caddr_t)(op) + sizeof(struct ospf6_prefix), \
- OSPF6_PREFIX_SPACE((op)->prefix_length)); \
- } while (0)
-
+extern void ospf6_prefix_in6_addr(struct in6_addr *in6, const void *prefix_buf,
+ const struct ospf6_prefix *p);
extern void ospf6_prefix_apply_mask(struct ospf6_prefix *op);
extern void ospf6_prefix_options_printbuf(uint8_t prefix_options, char *buf,
int size);
{
unsigned long delay, elapsed, ht;
+ /* OSPF instance does not exist. */
+ if (ospf6 == NULL)
+ return;
+
ospf6_set_spf_reason(ospf6, reason);
if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME)) {
rbuf);
}
- /* OSPF instance does not exist. */
- if (ospf6 == NULL)
- return;
-
/* SPF calculation timer is already scheduled. */
if (ospf6->t_spf_calc) {
if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME))
struct msg_originate_request *omsg;
unsigned int omsglen;
char buf[OSPF_API_MAX_MSG_SIZE];
+ size_t off_data = offsetof(struct msg_originate_request, data);
+ size_t data_maxs = sizeof(buf) - off_data;
+ struct lsa_header *omsg_data = (struct lsa_header *)&buf[off_data];
omsg = (struct msg_originate_request *)buf;
omsg->ifaddr = ifaddr;
omsg->area_id = area_id;
omsglen = ntohs(data->length);
- if (omsglen
- > sizeof(buf) - offsetof(struct msg_originate_request, data))
- omsglen = sizeof(buf)
- - offsetof(struct msg_originate_request, data);
- memcpy(&omsg->data, data, omsglen);
+ if (omsglen > data_maxs)
+ omsglen = data_maxs;
+ memcpy(omsg_data, data, omsglen);
omsglen += sizeof(struct msg_originate_request)
- sizeof(struct lsa_header);
uint8_t buf[OSPF_API_MAX_MSG_SIZE];
struct msg_lsa_change_notify *nmsg;
unsigned int len;
+ size_t off_data = offsetof(struct msg_lsa_change_notify, data);
+ size_t data_maxs = sizeof(buf) - off_data;
+ struct lsa_header *nmsg_data = (struct lsa_header *)&buf[off_data];
assert(data);
memset(&nmsg->pad, 0, sizeof(nmsg->pad));
len = ntohs(data->length);
- if (len > sizeof(buf) - offsetof(struct msg_lsa_change_notify, data))
- len = sizeof(buf)
- - offsetof(struct msg_lsa_change_notify, data);
- memcpy(&nmsg->data, data, len);
+ if (len > data_maxs)
+ len = data_maxs;
+ memcpy(nmsg_data, data, len);
len += sizeof(struct msg_lsa_change_notify) - sizeof(struct lsa_header);
return msg_new(msgtype, nmsg, seqnum, len);
struct ospf_lsa *new = NULL;
struct ospf *ospf;
+ assert(lsa);
+
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
assert(ospf);
dump_lsa_key(lsa));
lsa->data->ls_age =
htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */
+ goto out;
}
if (IS_LSA_MAXAGE(lsa)) {
/* Check each path. */
for (n1 = listhead(or->paths), n2 = listhead(newor->paths); n1 && n2;
- n1 = listnextnode(n1), n2 = listnextnode(n2)) {
+ n1 = listnextnode_unchecked(n1), n2 = listnextnode_unchecked(n2)) {
op = listgetdata(n1);
newop = listgetdata(n2);
else
state = ISM_DROther;
- memset(buf, 0, size);
-
snprintf(buf, size, "%s/%s",
lookup_msg(ospf_nsm_state_msg, nbr->state, NULL),
lookup_msg(ospf_ism_state_msg, state, NULL));
}
if (w > 99)
- snprintf(buf, size, "%ldw%1ldd", w, d);
+ snprintf(buf, size, "%luw%1lud", w, d);
else if (w)
- snprintf(buf, size, "%ldw%1ldd%02ldh", w, d, h);
+ snprintf(buf, size, "%luw%1lud%02luh", w, d, h);
else if (d)
- snprintf(buf, size, "%1ldd%02ldh%02ldm", d, h, m);
+ snprintf(buf, size, "%1lud%02luh%02lum", d, h, m);
else if (h)
- snprintf(buf, size, "%ldh%02ldm%02lds", h, m, (long)t->tv_sec);
+ snprintf(buf, size, "%luh%02lum%02lds", h, m, (long)t->tv_sec);
else if (m)
- snprintf(buf, size, "%ldm%02lds", m, (long)t->tv_sec);
+ snprintf(buf, size, "%lum%02lds", m, (long)t->tv_sec);
else if (ms)
- snprintf(buf, size, "%ld.%03lds", (long)t->tv_sec, ms);
+ snprintf(buf, size, "%ld.%03lus", (long)t->tv_sec, ms);
else
snprintf(buf, size, "%ld usecs", (long)t->tv_usec);
static char *ospf_dd_flags_dump(uint8_t flags, char *buf, size_t size)
{
- memset(buf, 0, size);
-
snprintf(buf, size, "%s|%s|%s", (flags & OSPF_DD_FLAG_I) ? "I" : "-",
(flags & OSPF_DD_FLAG_M) ? "M" : "-",
(flags & OSPF_DD_FLAG_MS) ? "MS" : "-");
static char *ospf_router_lsa_flags_dump(uint8_t flags, char *buf, size_t size)
{
- memset(buf, 0, size);
-
snprintf(buf, size, "%s|%s|%s",
(flags & ROUTER_LSA_VIRTUAL) ? "V" : "-",
(flags & ROUTER_LSA_EXTERNAL) ? "E" : "-",
return CMD_SUCCESS;
if (ospf->instance)
- sprintf(str, " %d", ospf->instance);
+ sprintf(str, " %u", ospf->instance);
/* debug ospf ism (status|events|timers). */
if (IS_CONF_DEBUG_OSPF(ism, ISM) == OSPF_DEBUG_ISM)
"ospf_vl_new(): creating pseudo zebra interface vrf id %u",
ospf->vrf_id);
- snprintf(ifname, sizeof(ifname), "VLINK%d", vlink_count);
+ snprintf(ifname, sizeof(ifname), "VLINK%u", vlink_count);
vi = if_create(ifname, ospf->vrf_id);
/*
* if_create sets ZEBRA_INTERFACE_LINKDETECTION
stream_free(op->s);
XFREE(MTYPE_OSPF_PACKET, op);
-
- op = NULL;
}
struct ospf_fifo *ospf_fifo_new()
TLV_LEN(OspfRI.sr_info.msd) = htons(0);
}
-static void unset_param(struct tlv_header *tlv)
+static void unset_param(void *tlv_buffer)
{
+ struct tlv_header *tlv = (struct tlv_header *)tlv_buffer;
tlv->type = 0;
/* Fill the Value to 0 */
- memset(TLV_DATA(tlv), 0, TLV_BODY_SIZE(tlv));
+ memset(TLV_DATA(tlv_buffer), 0, TLV_BODY_SIZE(tlv));
tlv->length = 0;
return;
"PCE address in IPv4 address format\n")
{
- unset_param(&OspfRI.pce_info.pce_address.header);
+ unset_param(&OspfRI.pce_info.pce_address);
/* Refresh RI LSA if already engaged */
if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
"32-bit Hexadecimal value\n")
{
- unset_param(&OspfRI.pce_info.pce_address.header);
+ unset_param(&OspfRI.pce_info.pce_address);
/* Refresh RI LSA if already engaged */
if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
"Disable PCE capabilities\n")
{
- unset_param(&OspfRI.pce_info.pce_cap_flag.header);
+ unset_param(&OspfRI.pce_info.pce_cap_flag);
/* Refresh RI LSA if already engaged */
if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
/* Check each path. */
for (n1 = listhead(or->paths),
n2 = listhead(newor->paths);
- n1 && n2;
- n1 = listnextnode(n1), n2 = listnextnode(n2)) {
+ n1 && n2; n1 = listnextnode_unchecked(n1),
+ n2 = listnextnode_unchecked(n2)) {
op = listgetdata(n1);
newop = listgetdata(n2);
#include "log.h"
#include "plist.h"
#include "vrf.h"
+#include "frrstr.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_asbr.h"
len = *length - v->namelen;
if (len >= IN_ADDR_SIZE)
len = IN_ADDR_SIZE;
- if (len <= 0)
+ if (len == 0)
ifaddr_next = 1;
oid2in_addr(name + v->namelen, len, ifaddr);
first = 0;
len = *length - v->namelen;
- if (len <= 0)
+ if (len == 0)
first = 1;
if (len > IN_ADDR_SIZE)
len = IN_ADDR_SIZE;
first = 0;
len = *length - v->namelen;
- if (len <= 0)
+ if (len == 0)
first = 1;
if (len > IN_ADDR_SIZE)
struct tlv_header *tlvh0,
uint16_t subtotal, uint16_t total)
{
- struct tlv_header *tlvh, *next;
+ struct tlv_header *tlvh;
uint16_t sum = subtotal;
for (tlvh = tlvh0; sum < total;
- tlvh = (next ? next : TLV_HDR_NEXT(tlvh))) {
- next = NULL;
+ tlvh = TLV_HDR_NEXT(tlvh)) {
switch (ntohs(tlvh->type)) {
case TE_LINK_SUBTLV_LINK_TYPE:
sum += show_vty_link_subtlv_link_type(vty, tlvh);
int idx_poll = 3;
int idx_pri = 5;
struct in_addr nbr_addr;
- unsigned int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT;
- unsigned int interval = OSPF_POLL_INTERVAL_DEFAULT;
+ unsigned int priority;
+ unsigned int interval;
if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) {
vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n");
interval = strtoul(argv[idx_poll]->arg, NULL, 10);
- if (argc > 4)
- priority = strtoul(argv[idx_pri]->arg, NULL, 10);
+ priority = argc > 4 ? strtoul(argv[idx_pri]->arg, NULL, 10)
+ : OSPF_NEIGHBOR_PRIORITY_DEFAULT;
ospf_nbr_nbma_set(ospf, nbr_addr);
ospf_nbr_nbma_poll_interval_set(ospf, nbr_addr, interval);
source = proto_redistnum(AFI_IP, argv[idx_ospf_table]->text);
+ if (source < 0) {
+ vty_out(vty, "Unknown instance redistribution\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
instance = strtoul(argv[idx_number]->arg, NULL, 10);
if ((source == ZEBRA_ROUTE_OSPF) && !ospf->instance) {
struct ospf_redist *red;
red = ospf_redist_lookup(ospf, type, instance);
+
+ if (red == NULL) {
+ zlog_err(
+ "Redistribute[%s][%d]: Lookup failed Type[%d] , Metric[%d]",
+ ospf_redist_string(type), instance,
+ metric_type(ospf, type, instance),
+ metric_value(ospf, type, instance));
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
if (ospf_is_type_redistributed(ospf, type, instance)) {
if (mtype != red->dmetric.type) {
red->dmetric.type = mtype;
zlog_debug(
"%s: Create new ospf instance with vrf_name %s vrf_id %u",
__PRETTY_FUNCTION__, name, new->vrf_id);
- if (vrf)
- ospf_vrf_link(new, vrf);
} else {
new->vrf_id = VRF_DEFAULT;
vrf = vrf_lookup_by_id(VRF_DEFAULT);
- ospf_vrf_link(new, vrf);
}
+
+ if (vrf)
+ ospf_vrf_link(new, vrf);
+
ospf_zebra_vrf_register(new);
new->abr_type = OSPF_ABR_DEFAULT;
new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new));
strcpy(new->name, pnhgc->name);
- new->table_id = pbr_nht_get_next_tableid();
+ new->table_id = pbr_nht_get_next_tableid(false);
DEBUGD(&pbr_dbg_nht, "%s: NHT: %s assigned Table ID: %u",
__PRETTY_FUNCTION__, new->name, new->table_id);
pnhgc = pbr_nht_add_group(name);
+ if (!pnhgc)
+ return;
+
DEBUGD(&pbr_dbg_nht, "%s: Added nexthop-group %s", __PRETTY_FUNCTION__,
name);
struct pbr_nexthop_cache pnhc_find = {};
struct pbr_nexthop_cache *pnhc;
+ if (!pbr_nht_get_next_tableid(true)) {
+ zlog_warn(
+ "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
+ __PRETTY_FUNCTION__, nhgc->name);
+ return;
+ }
+
/* find pnhgc by name */
strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
pnhgc = hash_get(pbr_nhg_hash, &pnhgc_find, pbr_nhgc_alloc);
/* find pnhgc by name */
strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
- pnhgc = hash_get(pbr_nhg_hash, &pnhgc_find, pbr_nhgc_alloc);
+ pnhgc = hash_lookup(pbr_nhg_hash, &pnhgc_find);
/* delete pnhc from pnhgc->nhh */
pnhc_find.nexthop = (struct nexthop *)nhop;
memset(&find, 0, sizeof(find));
pbr_nht_nexthop_make_name(pbrms->parent->name, PBR_NHC_NAMELEN,
pbrms->seqno, find.name);
+
+ if (!pbr_nht_get_next_tableid(true)) {
+ zlog_warn(
+ "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
+ __PRETTY_FUNCTION__, find.name);
+ return;
+ }
+
if (!pbrms->internal_nhg_name)
pbrms->internal_nhg_name = XSTRDUP(MTYPE_TMP, find.name);
struct pbr_nexthop_group_cache *pnhgc;
struct pbr_nexthop_group_cache lookup;
+ if (!pbr_nht_get_next_tableid(true)) {
+ zlog_warn(
+ "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
+ __PRETTY_FUNCTION__, name);
+ return NULL;
+ }
+
nhgc = nhgc_find(name);
if (!nhgc) {
- zlog_warn("%s: Could not find group %s to add",
- __PRETTY_FUNCTION__, name);
+ DEBUGD(&pbr_dbg_nht, "%s: Could not find nhgc with name: %s\n",
+ __PRETTY_FUNCTION__, name);
return NULL;
}
return !strcmp(nhgc1->name, nhgc2->name);
}
-
-uint32_t pbr_nht_get_next_tableid(void)
+uint32_t pbr_nht_get_next_tableid(bool peek)
{
uint32_t i;
bool found = false;
}
if (found) {
- nhg_tableid[i] = true;
+ nhg_tableid[i] = !peek;
return i;
} else
return 0;
extern void pbr_nht_set_tableid_range(uint32_t low, uint32_t high);
/*
- * Get the next tableid to use for installation
+ * Get the next tableid to use for installation.
+ *
+ * peek
+ * If set to true, retrieves the next ID without marking it used. The next
+ * call will return the same ID.
*/
-extern uint32_t pbr_nht_get_next_tableid(void);
+extern uint32_t pbr_nht_get_next_tableid(bool peek);
/*
* Get the next rule number to use for installation
*/
#include "nexthop.h"
#include "nexthop_group.h"
#include "log.h"
-#include "json.h"
#include "debug.h"
+#include "pbr.h"
#include "pbrd/pbr_nht.h"
#include "pbrd/pbr_map.h"
return CMD_SUCCESS;
}
+DEFPY(pbr_set_table_range,
+ pbr_set_table_range_cmd,
+ "[no] pbr table range (10000-4294966272)$lb (10000-4294966272)$ub",
+ NO_STR
+ PBR_STR
+ "Set table ID range\n"
+ "Set table ID range\n"
+ "Lower bound for table ID range\n"
+ "Upper bound for table ID range\n")
+{
+ /* upper bound is 2^32 - 2^10 */
+ int ret = CMD_WARNING;
+ const int minrange = 1000;
+
+ /* validate given bounds */
+ if (lb > ub)
+ vty_out(vty, "%% Lower bound must be less than upper bound\n");
+ else if (ub - lb < minrange)
+ vty_out(vty, "%% Range breadth must be at least %d\n", minrange);
+ else {
+ ret = CMD_SUCCESS;
+ pbr_nht_set_tableid_range((uint32_t) lb, (uint32_t) ub);
+ }
+
+ return ret;
+}
+
+
DEFPY(pbr_map_match_src, pbr_map_match_src_cmd,
"[no] match src-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
NO_STR
DEFPY (show_pbr,
show_pbr_cmd,
- "show pbr [json$json]",
+ "show pbr",
SHOW_STR
- "Policy Based Routing\n"
- JSON_STR)
+ PBR_STR)
{
pbr_nht_write_table_range(vty);
pbr_nht_write_rule_range(vty);
DEFPY (show_pbr_map,
show_pbr_map_cmd,
- "show pbr map [NAME$name] [detail$detail] [json$json]",
+ "show pbr map [NAME$name] [detail$detail]",
SHOW_STR
- "Policy Based Routing\n"
+ PBR_STR
"PBR Map\n"
"PBR Map Name\n"
- "Detailed information\n"
- JSON_STR)
+ "Detailed information\n")
{
struct pbr_map_sequence *pbrms;
struct pbr_map *pbrm;
show_pbr_nexthop_group_cmd,
"show pbr nexthop-groups [WORD$word]",
SHOW_STR
- "Policy Based Routing\n"
+ PBR_STR
"Nexthop Groups\n"
"Optional Name of the nexthop group\n")
{
DEFPY (show_pbr_interface,
show_pbr_interface_cmd,
- "show pbr interface [NAME$name] [json$json]",
+ "show pbr interface [NAME$name]",
SHOW_STR
- "Policy Based Routing\n"
+ PBR_STR
"PBR Interface\n"
- "PBR Interface Name\n"
- JSON_STR)
+ "PBR Interface Name\n")
{
struct interface *ifp;
struct vrf *vrf;
}
/* PBR debugging CLI ------------------------------------------------------- */
-/* clang-format off */
static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
"[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
NO_STR
DEBUG_STR
- "Policy Based Routing\n"
+ PBR_STR
"Policy maps\n"
"PBRD <-> Zebra communications\n"
"Nexthop tracking\n"
"show debugging [pbr]",
SHOW_STR
DEBUG_STR
- "Policy Based Routing\n")
+ PBR_STR)
{
vty_out(vty, "PBR debugging status:\n");
return CMD_SUCCESS;
}
-/* clang-format on */
/* ------------------------------------------------------------------------- */
install_element(CONFIG_NODE, &pbr_map_cmd);
install_element(CONFIG_NODE, &no_pbr_map_cmd);
+ install_element(CONFIG_NODE, &pbr_set_table_range_cmd);
install_element(INTERFACE_NODE, &pbr_policy_cmd);
install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
int mtrace_len;
int responses;
unsigned short sum;
+ size_t mtrace_off;
+ size_t ip_len;
recvd = recvfrom(fd, mtrace_buf, IP_AND_MTRACE_BUF_LEN, 0, NULL, 0);
if (sum != in_cksum(ip, ip->ip_hl * 4))
return -1;
- mtrace = (struct igmp_mtrace *)(mtrace_buf + (4 * ip->ip_hl));
-
- mtrace_len = ntohs(ip->ip_len) - ip->ip_hl * 4;
+ /* Header overflow check */
+ mtrace_off = 4 * ip->ip_hl;
+ if (mtrace_off > MTRACE_BUF_LEN)
+ return -1;
- if (mtrace_len < (int)MTRACE_HDR_SIZE)
+ /* Underflow/overflow check */
+ ip_len = ntohs(ip->ip_len);
+ if (ip_len < mtrace_off || ip_len < MTRACE_HDR_SIZE
+ || ip_len > MTRACE_BUF_LEN)
return -1;
+ mtrace_len = ip_len - mtrace_off;
+ mtrace = (struct igmp_mtrace *)(mtrace_buf + mtrace_off);
+
sum = mtrace->checksum;
mtrace->checksum = 0;
if (sum != in_cksum(mtrace, mtrace_len)) {
{
fd_set readfds;
struct timeval timeout;
- int ret = -1;
+ int ret;
long msec, rmsec, tmsec;
FD_ZERO(&readfds);
json_object *json_source = NULL;
json_object *json_oil = NULL;
json_object *json_ifp_out = NULL;
- int found_oif = 0;
- int first = 1;
+ int found_oif;
+ int first;
char grp_str[INET_ADDRSTRLEN];
char src_str[INET_ADDRSTRLEN];
char in_ifname[INTERFACE_NAMSIZ + 1];
* Previous-hop router not known,
* packet is sent to an appropriate multicast address
*/
- inet_aton(MCAST_ALL_ROUTERS, &nh_addr);
+ (void)inet_aton(MCAST_ALL_ROUTERS, &nh_addr);
}
/* 6.2.2 8. If this router is the Rendez-vous Point */
struct prefix_sg sg;
int i;
- memset(buf, 0, size);
sg.src = c_oil->oil.mfcc_origin;
sg.grp = c_oil->oil.mfcc_mcastgrp;
sprintf(buf, "%s IIF: %d, OIFS: ", pim_str_sg_dump(&sg),
socklen_t tolen;
unsigned char buffer[10000];
unsigned char *msg_start;
- uint8_t ttl = MAXTTL;
+ uint8_t ttl;
struct pim_msg_header *header;
struct ip *ip;
#include "pimd.h"
-
-static void pim_route_map_mark_update(const char *rmap_name)
-{
- // placeholder
- return;
-}
-
static void pim_route_map_add(const char *rmap_name)
{
- if (route_map_mark_updated(rmap_name, 0) == 0)
- pim_route_map_mark_update(rmap_name);
-
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
}
static void pim_route_map_delete(const char *rmap_name)
{
- if (route_map_mark_updated(rmap_name, 1) == 0)
- pim_route_map_mark_update(rmap_name);
-
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
}
static void pim_route_map_event(route_map_event_t event, const char *rmap_name)
{
- if (route_map_mark_updated(rmap_name, 0) == 0)
- pim_route_map_mark_update(rmap_name);
-
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
}
void pim_zebra_init(void)
{
- int i;
-
/* Socket for receiving updates from Zebra daemon */
zclient = zclient_new_notify(master, &zclient_options_default);
zclient_init(zclient, ZEBRA_ROUTE_PIM, 0, &pimd_privs);
if (PIM_DEBUG_PIM_TRACE) {
- zlog_info("zclient_init cleared redistribution request");
- }
-
- /* Request all redistribution */
- for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
- if (i == zclient->redist_default)
- continue;
- vrf_bitmap_set(zclient->redist[AFI_IP][i], pimg->vrf_id);
- ;
- if (PIM_DEBUG_PIM_TRACE) {
- zlog_debug("%s: requesting redistribution for %s (%i)",
- __PRETTY_FUNCTION__, zebra_route_string(i),
- i);
- }
- }
-
- /* Request default information */
- zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient,
- pimg->vrf_id);
-
- if (PIM_DEBUG_PIM_TRACE) {
- zlog_info("%s: requesting default information redistribution",
- __PRETTY_FUNCTION__);
-
- zlog_notice("%s: zclient update socket initialized",
+ zlog_notice("%s: zclient socket initialized",
__PRETTY_FUNCTION__);
}
#### Check for systemd or init.d (upstart)
# Check for init.d (upstart) as used in CentOS 6 or systemd (ie CentOS 7)
-%if 0%{?fedora} >= 15 || 0%{?rhel} >= 7 || 0%{?suse_version} >= 1210
+%if 0%{?fedora} || 0%{?rhel} >= 7 || 0%{?suse_version} >= 1210
%global initsystem systemd
%else
-%if (0%{?fedora} && 0%{?fedora} < 15) || (0%{?rhel} && 0%{?rhel} < 7)
+%if 0%{?rhel} && 0%{?rhel} < 7
%global initsystem upstart
%else
%{expand: %%global initsystem %(if [[ `/sbin/init --version 2> /dev/null` =~ upstart ]]; then echo upstart; elif [[ `readlink -f /sbin/init` = /usr/lib/systemd/systemd ]]; then echo systemd; elif [[ `systemctl` =~ -\.mount ]]; then echo systemd; fi)}
%endif
%endif
-#
-# If init system is systemd, then always disable watchfrr
-#
+
+# If init system is systemd, then always enable watchfrr
%if "%{initsystem}" == "systemd"
- # Note: For systems with systemd, watchfrr will NOT be built. Systemd
- # takes over the role of restarting crashed processes. Value will
- # be overwritten with 0 below for systemd independent on the setting here
%global with_watchfrr 1
%endif
-#### Check for RedHat 6.x or CentOS 6.x - they are too old to support PIM.
+#### Check for RedHat 6.x or CentOS 6.x - they are too old to support PIM.
#### Always disable it on these old systems unconditionally
#
# if CentOS / RedHat and version < 7, then disable PIMd (too old, won't work)
%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd
%if %{with_ldpd}
-%define daemon_ldpd ldpd
+%define daemon_ldpd ldpd
%else
-%define daemon_ldpd ""
+%define daemon_ldpd ""
%endif
%if %{with_pimd}
-%define daemon_pimd pimd
+%define daemon_pimd pimd
%else
-%define daemon_pimd ""
+%define daemon_pimd ""
%endif
%if %{with_pbrd}
-%define daemon_pbrd pbrd
+%define daemon_pbrd pbrd
%else
-%define daemon_pbrd ""
+%define daemon_pbrd ""
%endif
%if %{with_nhrpd}
-%define daemon_nhrpd nhrpd
+%define daemon_nhrpd nhrpd
%else
-%define daemon_nhrpd ""
+%define daemon_nhrpd ""
%endif
%if %{with_eigrpd}
-%define daemon_eigrpd eigrpd
+%define daemon_eigrpd eigrpd
%else
-%define daemon_eigrpd ""
+%define daemon_eigrpd ""
%endif
%if %{with_babeld}
-%define daemon_babeld babeld
+%define daemon_babeld babeld
%else
-%define daemon_babeld ""
+%define daemon_babeld ""
%endif
%if %{with_watchfrr}
-%define daemon_watchfrr watchfrr
+%define daemon_watchfrr watchfrr
%else
-%define daemon_watchfrr ""
+%define daemon_watchfrr ""
%endif
-%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd}
+%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd}
# allow build dir to be kept
%{!?keep_build: %global keep_build 0 }
Release: @CONFDATE@%{release_rev}%{?dist}
License: GPLv2+
Group: System Environment/Daemons
-Source0: http://www.frrouting.org/releases/frr/%{name}-%{frrversion}.tar.gz
-URL: http://www.frrouting.org
-Requires(pre): /sbin/install-info
-Requires(preun): /sbin/install-info
-Requires(post): /sbin/install-info
+Source0: https://github.com/FRRouting/frr/archive/%{name}-%{frrversion}.tar.gz
+URL: https://www.frrouting.org
+Requires(preun): info
+Requires(post): info
BuildRequires: gcc patch libcap-devel
-BuildRequires: readline readline-devel ncurses ncurses-devel
+BuildRequires: readline-devel ncurses-devel
BuildRequires: json-c-devel bison >= 2.7 flex make
BuildRequires: c-ares-devel texinfo
%if 0%{?rhel} && 0%{?rhel} < 7
%else
BuildRequires: python-devel >= 2.7 python-sphinx
%endif
-Requires: ncurses json-c initscripts
+Requires: json-c initscripts
%if %{with_pam}
BuildRequires: pam-devel
-Requires: pam
%endif
%if %{with_rpki}
BuildRequires: librtr-devel >= 0.5
-Requires: librtr >= 0.5
%endif
%if "%{initsystem}" == "systemd"
BuildRequires: systemd systemd-devel
Requires(preun): systemd
Requires(postun): systemd
%else
+Requires(post): chkconfig
+Requires(preun): chkconfig
# Initscripts > 5.60 is required for IPv6 support
Requires(pre): initscripts >= 5.60
%endif
%package pythontools
Summary: python tools for frr
BuildRequires: python
-Requires: python python-ipaddr
+Requires: python-ipaddr
Group: System Environment/Daemons
%description pythontools
--disable-ospfclient\
%endif
%if %{with_ospfapi}
- --enable-ospfapi=yes \
+ --enable-ospfapi \
%else
- --enable-ospfapi=no \
+ --disable-ospfapi \
%endif
%if %{with_rtadv}
- --enable-rtadv=yes \
+ --enable-rtadv \
%else
- --enable-rtadv=no \
+ --disable-rtadv \
%endif
%if %{with_ldpd}
--enable-ldpd \
--disable-pbrd \
%endif
%if %{with_nhrpd}
- --enable-nhrpd \
+ --enable-nhrpd \
%else
- --disable-nhrpd \
+ --disable-nhrpd \
%endif
%if %{with_eigrpd}
- --enable-eigrpd \
+ --enable-eigrpd \
%else
- --disable-eigrpd \
+ --disable-eigrpd \
%endif
%if %{with_babeld}
- --enable-babeld \
+ --enable-babeld \
%else
- --disable-babeld \
+ --disable-babeld \
%endif
%if %{with_pam}
--with-libpam \
%else
--disable-bgp-vnc \
%endif
- --enable-isisd=yes \
+ --enable-isisd \
%if "%{initsystem}" == "systemd"
- --enable-systemd=yes \
+ --enable-systemd \
%endif
%if %{with_rpki}
--enable-rpki \
%endif
- --enable-poll=yes
+ --enable-poll
make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" SPHINXBUILD=%{sphinx}
zebra_spec_add_service ()
{
- # Add port /etc/services entry if it isn't already there
+ # Add port /etc/services entry if it isn't already there
if [ -f /etc/services ] && \
! %__sed -e 's/#.*$//' /etc/services | %__grep -wq $1 ; then
echo "$1 $2 # $3" >> /etc/services
%doc ChangeLog NEWS README
%if 0%{?frr_user:1}
%dir %attr(751,%frr_user,%frr_user) %{_sysconfdir}
-%dir %attr(750,%frr_user,%frr_user) /var/log/frr
+%dir %attr(750,%frr_user,%frr_user) /var/log/frr
%dir %attr(751,%frr_user,%frr_user) /var/run/frr
%else
%dir %attr(750,root,root) %{_sysconfdir}
%config(noreplace) /etc/frr/[!v]*.conf*
%config(noreplace) %attr(750,%frr_user,%frr_user) /etc/frr/daemons
%if "%{initsystem}" == "systemd"
- %attr(644,root,root) %{_unitdir}/frr.service
- %{_sbindir}/frr
+ %{_unitdir}/frr.service
%else
/etc/rc.d/init.d/frr
- %{_sbindir}/frr
%endif
+%{_sbindir}/frr
%config(noreplace) /etc/pam.d/frr
-%config(noreplace) %attr(640,root,root) /etc/logrotate.d/*
+%config(noreplace) /etc/logrotate.d/frr
%{_sbindir}/frr-reload
%files contrib
- new subpackage frr-pythontools with python 2.7 restart script
- remove PIMd from CentOS/RedHat 6 RPM packages (won't work - too old)
- converted to single frr init script (not per daemon) based on debian init script
-- created systemd service file for systemd based systems (which uses init script)
+- created systemd service file for systemd based systems (which uses init script)
- Various other RPM package fixes for FRR 2.0
* Fri Jan 6 2017 Martin Winter <mwinter@opensourcerouting.org>
- Renamed to frr for FRRouting fork of Quagga
-* Thu Feb 11 2016 Paul Jakma <paul@jakma.org>
+* Thu Feb 11 2016 Paul Jakma <paul@jakma.org>
- remove with_ipv6 conditionals, always build v6
- Fix UTF-8 char in spec changelog
- remove quagga.pam.stack, long deprecated.
- Remove support for old fedora 4/5
- Fix for package nameing
- Fix Weekdays of previous changelogs (bogus dates)
-- Add conditional logic to only build tex footnotes with supported texi2html
+- Add conditional logic to only build tex footnotes with supported texi2html
- Added pimd to files section and fix double listing of /var/lib*/quagga
- Numerous fixes to unify upstart/systemd startup into same spec file
- Only allow use of watchfrr for non-systemd systems. no need with systemd
- walk up tree - 17218
- ospfd NSSA fixes - 16681
- ospfd nsm fixes - 16824
-- ospfd OLSA fixes and new feature - 16823
+- ospfd OLSA fixes and new feature - 16823
- KAME and ifindex fixes - 16525
- spec file changes to allow redhat files to be in tree
* Tue Feb 6 2001 Tim Powers <timp@redhat.com>
- built for Powertools
-* Sun Feb 4 2001 Pekka Savola <pekkas@netcore.fi>
+* Sun Feb 4 2001 Pekka Savola <pekkas@netcore.fi>
- Hacked up from PLD Linux 0.90-1, Mandrake 0.90-1mdk and one from zebra.org.
- Update to 0.91a
- Very heavy modifications to init.d/*, .spec, pam, i18n, logrotate, etc.
struct interface *ifp)
{
struct rip_interface *ri;
- char *auth_str = (char *)&rte->prefix;
+ char *auth_str = (char *)rte + offsetof(struct rte, prefix);
int i;
/* reject passwords with zeros in the middle of the string */
- for (i = strlen(auth_str); i < 16; i++) {
+ for (i = strnlen(auth_str, 16); i < 16; i++) {
if (auth_str[i] != '\0')
return 0;
}
uint32_t removed_routes = 0;
zebra_capabilities_t _caps_p[] = {
- ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN,
};
struct zebra_privs_t sharp_privs = {
PYTHON ?= python
AUTOMAKE_OPTIONS = subdir-objects
-AM_CPPFLAGS = \
+AM_CPPFLAGS += \
-I.. \
-I$(top_srcdir) \
-I$(top_srcdir)/lib \
isisd/test_fuzz_isis_tlv_tests.h: $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
gzip -d < $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz > "$@"
-isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \
- isisd/test_fuzz_isis_tlv_tests.h
noinst_HEADERS = \
./helpers/c/prng.h \
bgpd_test_mp_attr_SOURCES = bgpd/test_mp_attr.c
bgpd_test_mpath_SOURCES = bgpd/test_mpath.c
isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv.c
+nodist_isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv_tests.h
+BUILT_SOURCES=isisd/test_fuzz_isis_tlv_tests.h
+CLEANFILES=isisd/test_fuzz_isis_tlv_tests.h
isisd_test_fuzz_isis_tlv_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/tests/isisd
isisd_test_isis_vertex_queue_SOURCES = isisd/test_isis_vertex_queue.c
#include "bgpd/rfapi/rfapi_backend.h"
#endif
+#define OUT_SYMBOL_INFO "\u25ba"
+#define OUT_SYMBOL_OK "\u2714"
+#define OUT_SYMBOL_NOK "\u2716"
+
+#define TEST_ASSERT(T, C) \
+ do { \
+ if ((T)->state != TEST_SUCCESS || (C)) \
+ break; \
+ (T)->state = TEST_ASSERT_ERROR; \
+ (T)->error = str_printf("assertion failed: %s (%s:%d)", (#C), \
+ __FILE__, __LINE__); \
+ } while (0)
+
+#define TEST_ASSERT_EQ(T, A, B) \
+ do { \
+ if ((T)->state != TEST_SUCCESS || ((A) == (B))) \
+ break; \
+ (T)->state = TEST_ASSERT_ERROR; \
+ (T)->error = str_printf( \
+ "assertion failed: %s[%d] == [%d]%s (%s:%d)", (#A), \
+ (A), (B), (#B), __FILE__, __LINE__); \
+ } while (0)
+
+#define TEST_HANDLER_MAX 5
+#define TEST_HANDLER(name) _test_handler_##name
+#define TEST_HANDLER_DECL(name) \
+ static void _test_handler_##name( \
+ struct test *test, struct test_peer_attr *pa, \
+ struct peer *peer, struct peer *group, bool peer_set, \
+ bool group_set)
+
+#define TEST_ATTR_HANDLER_DECL(name, attr, pval, gval) \
+ TEST_HANDLER_DECL(name) \
+ { \
+ if (peer_set) \
+ TEST_ASSERT_EQ(test, peer->attr, (pval)); \
+ else if (peer_group_active(peer) && group_set) \
+ TEST_ASSERT_EQ(test, peer->attr, (gval)); \
+ if (group_set) \
+ TEST_ASSERT_EQ(test, group->attr, (gval)); \
+ } \
+ TEST_HANDLER_DECL(name)
+
+#define TEST_STR_ATTR_HANDLER_DECL(name, attr, pval, gval) \
+ TEST_HANDLER_DECL(name) \
+ { \
+ if (peer_set) { \
+ TEST_ASSERT(test, peer->attr != NULL); \
+ TEST_ASSERT(test, !strcmp(peer->attr, (pval))); \
+ } else if (peer_group_active(peer) && group_set) { \
+ TEST_ASSERT(test, peer->attr != NULL); \
+ TEST_ASSERT(test, !strcmp(peer->attr, (gval))); \
+ } \
+ if (group_set) { \
+ TEST_ASSERT(test, group->attr != NULL); \
+ TEST_ASSERT(test, !strcmp(group->attr, (gval))); \
+ } \
+ } \
+ TEST_HANDLER_DECL(name)
+
+#define TEST_SU_ATTR_HANDLER_DECL(name, attr, pval, gval) \
+ TEST_HANDLER_DECL(name) \
+ { \
+ union sockunion su; \
+ if (peer_set) { \
+ str2sockunion(pval, &su); \
+ TEST_ASSERT(test, !sockunion_cmp(peer->attr, &su)); \
+ } else if (peer_group_active(peer) && group_set) { \
+ str2sockunion(gval, &su); \
+ TEST_ASSERT(test, !sockunion_cmp(group->attr, &su)); \
+ } \
+ if (group_set) { \
+ str2sockunion(gval, &su); \
+ TEST_ASSERT(test, !sockunion_cmp(group->attr, &su)); \
+ } \
+ } \
+ TEST_HANDLER_DECL(name)
+
/* Required variables to link in libbgp */
struct zebra_privs_t bgpd_privs = {0};
struct thread_master *master;
enum test_state {
TEST_SUCCESS,
+ TEST_SKIPPING,
TEST_COMMAND_ERROR,
TEST_CONFIG_ERROR,
TEST_ASSERT_ERROR,
+ TEST_CUSTOM_ERROR,
TEST_INTERNAL_ERROR,
};
+enum test_peer_attr_type {
+ PEER_AT_AF_FLAG = 0,
+ PEER_AT_AF_FILTER = 1,
+ PEER_AT_AF_CUSTOM = 2,
+ PEER_AT_GLOBAL_FLAG = 3,
+ PEER_AT_GLOBAL_CUSTOM = 4
+};
+
struct test {
enum test_state state;
char *desc;
struct bgp *bgp;
struct peer *peer;
struct peer_group *group;
+
+ struct {
+ bool use_ibgp;
+ bool use_iface_peer;
+ } o;
};
struct test_config {
int local_asn;
int peer_asn;
const char *peer_address;
+ const char *peer_interface;
const char *peer_group;
};
const char *peer_cmd;
const char *group_cmd;
- enum { PEER_AT_AF_FLAG = 0,
- PEER_AT_AF_FILTER = 1,
- PEER_AT_GLOBAL_FLAG = 2 } type;
+ enum test_peer_attr_type type;
union {
uint32_t flag;
struct {
} filter;
} u;
struct {
- bool invert;
+ bool invert_peer;
+ bool invert_group;
bool use_ibgp;
+ bool use_iface_peer;
+ bool skip_xfer_cases;
} o;
afi_t afi;
safi_t safi;
struct test_peer_family families[AFI_MAX * SAFI_MAX];
-};
-
-#define OUT_SYMBOL_INFO "\u25ba"
-#define OUT_SYMBOL_OK "\u2714"
-#define OUT_SYMBOL_NOK "\u2716"
-#define TEST_ASSERT_EQ(T, A, B) \
- do { \
- if ((T)->state != TEST_SUCCESS || ((A) == (B))) \
- break; \
- (T)->state = TEST_ASSERT_ERROR; \
- (T)->error = str_printf( \
- "assertion failed: %s[%d] == [%d]%s (%s:%d)", (#A), \
- (A), (B), (#B), __FILE__, __LINE__); \
- } while (0)
+ void (*handlers[TEST_HANDLER_MAX])(struct test *test,
+ struct test_peer_attr *pa,
+ struct peer *peer,
+ struct peer *group, bool peer_set,
+ bool group_set);
+};
static struct test_config cfg = {
.local_asn = 100,
.peer_asn = 200,
.peer_address = "1.1.1.1",
+ .peer_interface = "IP-TEST",
.peer_group = "PG-TEST",
};
{.afi = AFI_IP6, .safi = SAFI_MULTICAST},
};
+static char *str_vprintf(const char *fmt, va_list ap)
+{
+ int ret;
+ int buf_size = 0;
+ char *buf = NULL;
+ va_list apc;
+
+ while (1) {
+ va_copy(apc, ap);
+ ret = vsnprintf(buf, buf_size, fmt, apc);
+ va_end(apc);
+
+ if (ret >= 0 && ret < buf_size)
+ break;
+
+ if (ret >= 0)
+ buf_size = ret + 1;
+ else
+ buf_size *= 2;
+
+ buf = XREALLOC(MTYPE_TMP, buf, buf_size);
+ }
+
+ return buf;
+}
+
+static char *str_printf(const char *fmt, ...)
+{
+ char *buf;
+ va_list ap;
+
+ va_start(ap, fmt);
+ buf = str_vprintf(fmt, ap);
+ va_end(ap);
+
+ return buf;
+}
+
+TEST_ATTR_HANDLER_DECL(advertisement_interval, v_routeadv, 10, 20);
+TEST_STR_ATTR_HANDLER_DECL(password, password, "FRR-Peer", "FRR-Group");
+TEST_ATTR_HANDLER_DECL(local_as, change_local_as, 1, 2);
+TEST_ATTR_HANDLER_DECL(timers_1, keepalive, 10, 20);
+TEST_ATTR_HANDLER_DECL(timers_2, holdtime, 30, 60);
+TEST_SU_ATTR_HANDLER_DECL(update_source_su, update_source, "255.255.255.1",
+ "255.255.255.2");
+TEST_STR_ATTR_HANDLER_DECL(update_source_if, update_if, "IF-PEER", "IF-GROUP");
+
+TEST_ATTR_HANDLER_DECL(allowas_in, allowas_in[pa->afi][pa->safi], 1, 2);
+TEST_STR_ATTR_HANDLER_DECL(default_originate_route_map,
+ default_rmap[pa->afi][pa->safi].name, "RM-PEER",
+ "RM-GROUP");
+TEST_STR_ATTR_HANDLER_DECL(
+ distribute_list,
+ filter[pa->afi][pa->safi].dlist[pa->u.filter.direct].name, "DL-PEER",
+ "DL-GROUP");
+TEST_STR_ATTR_HANDLER_DECL(
+ filter_list, filter[pa->afi][pa->safi].aslist[pa->u.filter.direct].name,
+ "FL-PEER", "FL-GROUP");
+TEST_ATTR_HANDLER_DECL(maximum_prefix, pmax[pa->afi][pa->safi], 10, 20);
+TEST_ATTR_HANDLER_DECL(maximum_prefix_threshold,
+ pmax_threshold[pa->afi][pa->safi], 1, 2);
+TEST_ATTR_HANDLER_DECL(maximum_prefix_restart, pmax_restart[pa->afi][pa->safi],
+ 100, 200);
+TEST_STR_ATTR_HANDLER_DECL(
+ prefix_list, filter[pa->afi][pa->safi].plist[pa->u.filter.direct].name,
+ "PL-PEER", "PL-GROUP");
+TEST_STR_ATTR_HANDLER_DECL(
+ route_map, filter[pa->afi][pa->safi].map[pa->u.filter.direct].name,
+ "RM-PEER", "RM-GROUP");
+TEST_STR_ATTR_HANDLER_DECL(unsuppress_map, filter[pa->afi][pa->safi].usmap.name,
+ "UM-PEER", "UM-GROUP");
+TEST_ATTR_HANDLER_DECL(weight, weight[pa->afi][pa->safi], 100, 200);
+
/* clang-format off */
static struct test_peer_attr test_peer_attrs[] = {
+ /* Peer Attributes */
+ {
+ .cmd = "advertisement-interval",
+ .peer_cmd = "advertisement-interval 10",
+ .group_cmd = "advertisement-interval 20",
+ .u.flag = PEER_FLAG_ROUTEADV,
+ .type = PEER_AT_GLOBAL_FLAG,
+ .handlers[0] = TEST_HANDLER(advertisement_interval),
+ },
+ {
+ .cmd = "capability dynamic",
+ .u.flag = PEER_FLAG_DYNAMIC_CAPABILITY,
+ .type = PEER_AT_GLOBAL_FLAG,
+ },
+ {
+ .cmd = "capability extended-nexthop",
+ .u.flag = PEER_FLAG_CAPABILITY_ENHE,
+ .type = PEER_AT_GLOBAL_FLAG,
+ },
+ {
+ .cmd = "capability extended-nexthop",
+ .u.flag = PEER_FLAG_CAPABILITY_ENHE,
+ .type = PEER_AT_GLOBAL_FLAG,
+ .o.invert_peer = true,
+ .o.use_iface_peer = true,
+ },
+ {
+ .cmd = "description",
+ .peer_cmd = "description FRR Peer",
+ .group_cmd = "description FRR Group",
+ .type = PEER_AT_GLOBAL_CUSTOM,
+ },
+ {
+ .cmd = "disable-connected-check",
+ .u.flag = PEER_FLAG_DISABLE_CONNECTED_CHECK,
+ .type = PEER_AT_GLOBAL_FLAG,
+ },
+ {
+ .cmd = "dont-capability-negotiate",
+ .u.flag = PEER_FLAG_DONT_CAPABILITY,
+ .type = PEER_AT_GLOBAL_FLAG,
+ },
+ {
+ .cmd = "enforce-first-as",
+ .u.flag = PEER_FLAG_ENFORCE_FIRST_AS,
+ .type = PEER_AT_GLOBAL_FLAG,
+ },
+ {
+ .cmd = "local-as",
+ .peer_cmd = "local-as 1",
+ .group_cmd = "local-as 2",
+ .u.flag = PEER_FLAG_LOCAL_AS,
+ .type = PEER_AT_GLOBAL_FLAG,
+ .handlers[0] = TEST_HANDLER(local_as),
+ },
+ {
+ .cmd = "local-as 1 no-prepend",
+ .u.flag = PEER_FLAG_LOCAL_AS | PEER_FLAG_LOCAL_AS_NO_PREPEND,
+ .type = PEER_AT_GLOBAL_FLAG,
+ },
+ {
+ .cmd = "local-as 1 no-prepend replace-as",
+ .u.flag = PEER_FLAG_LOCAL_AS | PEER_FLAG_LOCAL_AS_REPLACE_AS,
+ .type = PEER_AT_GLOBAL_FLAG,
+ },
+ {
+ .cmd = "override-capability",
+ .u.flag = PEER_FLAG_OVERRIDE_CAPABILITY,
+ .type = PEER_AT_GLOBAL_FLAG,
+ },
+ {
+ .cmd = "passive",
+ .u.flag = PEER_FLAG_PASSIVE,
+ .type = PEER_AT_GLOBAL_FLAG,
+ },
+ {
+ .cmd = "password",
+ .peer_cmd = "password FRR-Peer",
+ .group_cmd = "password FRR-Group",
+ .u.flag = PEER_FLAG_PASSWORD,
+ .type = PEER_AT_GLOBAL_FLAG,
+ .handlers[0] = TEST_HANDLER(password),
+ },
+ {
+ .cmd = "shutdown",
+ .u.flag = PEER_FLAG_SHUTDOWN,
+ .type = PEER_AT_GLOBAL_FLAG,
+ },
+ {
+ .cmd = "strict-capability-match",
+ .u.flag = PEER_FLAG_STRICT_CAP_MATCH,
+ .type = PEER_AT_GLOBAL_FLAG,
+ },
+ {
+ .cmd = "timers",
+ .peer_cmd = "timers 10 30",
+ .group_cmd = "timers 20 60",
+ .u.flag = PEER_FLAG_TIMER,
+ .type = PEER_AT_GLOBAL_FLAG,
+ .handlers[0] = TEST_HANDLER(timers_1),
+ .handlers[1] = TEST_HANDLER(timers_2),
+ },
+ {
+ .cmd = "timers connect",
+ .peer_cmd = "timers connect 10",
+ .group_cmd = "timers connect 20",
+ .u.flag = PEER_FLAG_TIMER_CONNECT,
+ .type = PEER_AT_GLOBAL_FLAG,
+ },
+ {
+ .cmd = "update-source",
+ .peer_cmd = "update-source 255.255.255.1",
+ .group_cmd = "update-source 255.255.255.2",
+ .u.flag = PEER_FLAG_UPDATE_SOURCE,
+ .type = PEER_AT_GLOBAL_FLAG,
+ .handlers[0] = TEST_HANDLER(update_source_su),
+ },
+ {
+ .cmd = "update-source",
+ .peer_cmd = "update-source IF-PEER",
+ .group_cmd = "update-source IF-GROUP",
+ .u.flag = PEER_FLAG_UPDATE_SOURCE,
+ .type = PEER_AT_GLOBAL_FLAG,
+ .handlers[0] = TEST_HANDLER(update_source_if),
+ },
+
+ /* Address Family Attributes */
{
.cmd = "addpath-tx-all-paths",
.u.flag = PEER_FLAG_ADDPATH_TX_ALL_PATHS,
.peer_cmd = "allowas-in 1",
.group_cmd = "allowas-in 2",
.u.flag = PEER_FLAG_ALLOWAS_IN,
+ .handlers[0] = TEST_HANDLER(allowas_in),
},
{
.cmd = "allowas-in origin",
.peer_cmd = "default-originate route-map RM-PEER",
.group_cmd = "default-originate route-map RM-GROUP",
.u.flag = PEER_FLAG_DEFAULT_ORIGINATE,
+ .handlers[0] = TEST_HANDLER(default_originate_route_map),
+ },
+ {
+ .cmd = "distribute-list",
+ .peer_cmd = "distribute-list DL-PEER in",
+ .group_cmd = "distribute-list DL-GROUP in",
+ .type = PEER_AT_AF_FILTER,
+ .u.filter.flag = PEER_FT_DISTRIBUTE_LIST,
+ .u.filter.direct = FILTER_IN,
+ .handlers[0] = TEST_HANDLER(distribute_list),
+ },
+ {
+ .cmd = "distribute-list",
+ .peer_cmd = "distribute-list DL-PEER out",
+ .group_cmd = "distribute-list DL-GROUP out",
+ .type = PEER_AT_AF_FILTER,
+ .u.filter.flag = PEER_FT_DISTRIBUTE_LIST,
+ .u.filter.direct = FILTER_OUT,
+ .handlers[0] = TEST_HANDLER(distribute_list),
},
{
.cmd = "filter-list",
.type = PEER_AT_AF_FILTER,
.u.filter.flag = PEER_FT_FILTER_LIST,
.u.filter.direct = FILTER_IN,
+ .handlers[0] = TEST_HANDLER(filter_list),
},
{
.cmd = "filter-list",
.type = PEER_AT_AF_FILTER,
.u.filter.flag = PEER_FT_FILTER_LIST,
.u.filter.direct = FILTER_OUT,
+ .handlers[0] = TEST_HANDLER(filter_list),
},
{
.cmd = "maximum-prefix",
.peer_cmd = "maximum-prefix 10",
.group_cmd = "maximum-prefix 20",
.u.flag = PEER_FLAG_MAX_PREFIX,
+ .handlers[0] = TEST_HANDLER(maximum_prefix),
},
{
.cmd = "maximum-prefix",
.peer_cmd = "maximum-prefix 10 restart 100",
.group_cmd = "maximum-prefix 20 restart 200",
.u.flag = PEER_FLAG_MAX_PREFIX,
+ .handlers[0] = TEST_HANDLER(maximum_prefix),
+ .handlers[1] = TEST_HANDLER(maximum_prefix_restart),
},
{
.cmd = "maximum-prefix",
.peer_cmd = "maximum-prefix 10 1 restart 100",
.group_cmd = "maximum-prefix 20 2 restart 200",
.u.flag = PEER_FLAG_MAX_PREFIX,
+ .handlers[0] = TEST_HANDLER(maximum_prefix),
+ .handlers[1] = TEST_HANDLER(maximum_prefix_threshold),
+ .handlers[2] = TEST_HANDLER(maximum_prefix_restart),
},
{
.cmd = "maximum-prefix",
.peer_cmd = "maximum-prefix 10 warning-only",
.group_cmd = "maximum-prefix 20 warning-only",
.u.flag = PEER_FLAG_MAX_PREFIX | PEER_FLAG_MAX_PREFIX_WARNING,
+ .handlers[0] = TEST_HANDLER(maximum_prefix),
},
{
.cmd = "maximum-prefix",
.peer_cmd = "maximum-prefix 10 1 warning-only",
.group_cmd = "maximum-prefix 20 2 warning-only",
.u.flag = PEER_FLAG_MAX_PREFIX | PEER_FLAG_MAX_PREFIX_WARNING,
+ .handlers[0] = TEST_HANDLER(maximum_prefix),
+ .handlers[1] = TEST_HANDLER(maximum_prefix_threshold),
},
{
.cmd = "next-hop-self",
.type = PEER_AT_AF_FILTER,
.u.filter.flag = PEER_FT_PREFIX_LIST,
.u.filter.direct = FILTER_IN,
+ .handlers[0] = TEST_HANDLER(prefix_list),
},
{
.cmd = "prefix-list",
.type = PEER_AT_AF_FILTER,
.u.filter.flag = PEER_FT_PREFIX_LIST,
.u.filter.direct = FILTER_OUT,
+ .handlers[0] = TEST_HANDLER(prefix_list),
},
{
.cmd = "remove-private-AS",
.type = PEER_AT_AF_FILTER,
.u.filter.flag = PEER_FT_ROUTE_MAP,
.u.filter.direct = FILTER_IN,
+ .handlers[0] = TEST_HANDLER(route_map),
},
{
.cmd = "route-map",
.type = PEER_AT_AF_FILTER,
.u.filter.flag = PEER_FT_ROUTE_MAP,
.u.filter.direct = FILTER_OUT,
+ .handlers[0] = TEST_HANDLER(route_map),
},
{
.cmd = "route-reflector-client",
.u.flag = PEER_FLAG_REFLECTOR_CLIENT,
.o.use_ibgp = true,
+ .o.skip_xfer_cases = true,
},
{
.cmd = "route-server-client",
{
.cmd = "send-community",
.u.flag = PEER_FLAG_SEND_COMMUNITY,
- .o.invert = true,
+ .o.invert_peer = true,
+ .o.invert_group = true,
},
{
.cmd = "send-community extended",
.u.flag = PEER_FLAG_SEND_EXT_COMMUNITY,
- .o.invert = true,
+ .o.invert_peer = true,
+ .o.invert_group = true,
},
{
.cmd = "send-community large",
.u.flag = PEER_FLAG_SEND_LARGE_COMMUNITY,
- .o.invert = true,
+ .o.invert_peer = true,
+ .o.invert_group = true,
},
{
.cmd = "soft-reconfiguration inbound",
.type = PEER_AT_AF_FILTER,
.u.filter.flag = PEER_FT_UNSUPPRESS_MAP,
.u.filter.direct = 0,
+ .handlers[0] = TEST_HANDLER(unsuppress_map),
},
{
.cmd = "weight",
.peer_cmd = "weight 100",
.group_cmd = "weight 200",
.u.flag = PEER_FLAG_WEIGHT,
+ .handlers[0] = TEST_HANDLER(weight),
},
{NULL}
};
/* clang-format on */
-static char *str_vprintf(const char *fmt, va_list ap)
-{
- int ret;
- int buf_size = 0;
- char *buf = NULL;
- va_list apc;
-
- while (1) {
- va_copy(apc, ap);
- ret = vsnprintf(buf, buf_size, fmt, apc);
- va_end(apc);
-
- if (ret >= 0 && ret < buf_size)
- break;
-
- if (ret >= 0)
- buf_size = ret + 1;
- else
- buf_size *= 2;
-
- buf = XREALLOC(MTYPE_TMP, buf, buf_size);
- }
-
- return buf;
-}
-
-static char *str_printf(const char *fmt, ...)
-{
- char *buf;
- va_list ap;
-
- va_start(ap, fmt);
- buf = str_vprintf(fmt, ap);
- va_end(ap);
-
- return buf;
-}
-
static const char *str_from_afi(afi_t afi)
{
switch (afi) {
}
}
+static const char *str_from_attr_type(enum test_peer_attr_type at)
+{
+ switch (at) {
+ case PEER_AT_GLOBAL_FLAG:
+ return "peer-flag";
+ case PEER_AT_AF_FLAG:
+ return "af-flag";
+ case PEER_AT_AF_FILTER:
+ return "af-filter";
+ case PEER_AT_GLOBAL_CUSTOM:
+ case PEER_AT_AF_CUSTOM:
+ return "custom";
+ default:
+ return NULL;
+ }
+}
+
+static bool is_attr_type_global(enum test_peer_attr_type at)
+{
+ return at == PEER_AT_GLOBAL_FLAG || at == PEER_AT_GLOBAL_CUSTOM;
+}
+
+static void test_log(struct test *test, const char *fmt, ...)
+{
+ va_list ap;
+
+ /* Skip logging if test instance has previously failed. */
+ if (test->state != TEST_SUCCESS)
+ return;
+
+ /* Store formatted log message. */
+ va_start(ap, fmt);
+ listnode_add(test->log, str_vprintf(fmt, ap));
+ va_end(ap);
+}
+
static void test_execute(struct test *test, const char *fmt, ...)
{
int ret;
va_end(ap);
}
-static struct test *test_new(const char *desc, bool use_ibgp)
+static void test_initialize(struct test *test)
{
- struct test *test;
union sockunion su;
- test = XCALLOC(MTYPE_TMP, sizeof(struct test));
- test->state = TEST_SUCCESS;
- test->desc = XSTRDUP(MTYPE_TMP, desc);
- test->log = list_new();
+ /* Skip execution if test instance has previously failed. */
+ if (test->state != TEST_SUCCESS)
+ return;
- test->vty = vty_new();
- test->vty->type = VTY_TERM;
- test->vty->node = CONFIG_NODE;
+ /* Log message about (re)-initialization */
+ test_log(test, "prepare: %sinitialize bgp test environment",
+ test->bgp ? "re-" : "");
/* Attempt gracefully to purge previous BGP configuration. */
test_execute(test, "no router bgp");
test_execute(test, "router bgp %d", cfg.local_asn);
test_execute(test, "no bgp default ipv4-unicast");
test_execute(test, "neighbor %s peer-group", cfg.peer_group);
- test_execute(test, "neighbor %s remote-as %d", cfg.peer_address,
- use_ibgp ? cfg.local_asn : cfg.peer_asn);
+ if (test->o.use_iface_peer) {
+ test_execute(test, "neighbor %s interface", cfg.peer_interface);
+ test_execute(test, "neighbor %s remote-as %d",
+ cfg.peer_interface,
+ test->o.use_ibgp ? cfg.local_asn : cfg.peer_asn);
+ } else {
+ test_execute(test, "neighbor %s remote-as %d", cfg.peer_address,
+ test->o.use_ibgp ? cfg.local_asn : cfg.peer_asn);
+ }
+
if (test->state != TEST_SUCCESS)
- return test;
+ return;
/* Fetch default BGP instance. */
test->bgp = bgp_get_default();
test->state = TEST_INTERNAL_ERROR;
test->error =
str_printf("could not retrieve default bgp instance");
- return test;
+ return;
}
/* Fetch peer instance. */
- str2sockunion(cfg.peer_address, &su);
- test->peer = peer_lookup(test->bgp, &su);
+ if (test->o.use_iface_peer) {
+ test->peer =
+ peer_lookup_by_conf_if(test->bgp, cfg.peer_interface);
+ } else {
+ str2sockunion(cfg.peer_address, &su);
+ test->peer = peer_lookup(test->bgp, &su);
+ }
if (!test->peer) {
test->state = TEST_INTERNAL_ERROR;
test->error = str_printf(
"could not retrieve instance of bgp peer [%s]",
cfg.peer_address);
- return test;
+ return;
}
/* Fetch peer-group instance. */
test->error = str_printf(
"could not retrieve instance of bgp peer-group [%s]",
cfg.peer_group);
- return test;
+ return;
}
+}
- return test;
-};
-
-static void test_log(struct test *test, const char *fmt, ...)
+static struct test *test_new(const char *desc, bool use_ibgp,
+ bool use_iface_peer)
{
- va_list ap;
+ struct test *test;
- /* Skip logging if test instance has previously failed. */
- if (test->state != TEST_SUCCESS)
- return;
+ test = XCALLOC(MTYPE_TMP, sizeof(struct test));
+ test->state = TEST_SUCCESS;
+ test->desc = XSTRDUP(MTYPE_TMP, desc);
+ test->log = list_new();
+ test->o.use_ibgp = use_ibgp;
+ test->o.use_iface_peer = use_iface_peer;
- /* Store formatted log message. */
- va_start(ap, fmt);
- listnode_add(test->log, str_vprintf(fmt, ap));
- va_end(ap);
-}
+ test->vty = vty_new();
+ test->vty->type = VTY_TERM;
+ test->vty->node = CONFIG_NODE;
+
+ test_initialize(test);
+
+ return test;
+};
static void test_finish(struct test *test)
{
XFREE(MTYPE_TMP, test);
}
-static void test_af_flags(struct test *test, struct peer *peer,
- struct test_peer_attr *attr, bool exp_val,
- bool exp_ovrd)
+static void test_peer_flags(struct test *test, struct test_peer_attr *pa,
+ struct peer *peer, bool exp_val, bool exp_ovrd)
{
bool exp_inv, cur_val, cur_ovrd, cur_inv;
- /* Flip expected values for inverted flags. */
- exp_inv = attr->o.invert;
+ /* Skip execution if test instance has previously failed. */
+ if (test->state != TEST_SUCCESS)
+ return;
+
+ /* Detect if flag is meant to be inverted. */
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ exp_inv = pa->o.invert_group;
+ else
+ exp_inv = pa->o.invert_peer;
+
+ /* Flip expected value if flag is inverted. */
exp_val ^= exp_inv;
/* Fetch current state of value, override and invert flags. */
- cur_val = !!CHECK_FLAG(peer->af_flags[attr->afi][attr->safi],
- attr->u.flag);
- cur_ovrd = !!CHECK_FLAG(peer->af_flags_override[attr->afi][attr->safi],
- attr->u.flag);
- cur_inv = !!CHECK_FLAG(peer->af_flags_invert[attr->afi][attr->safi],
- attr->u.flag);
+ if (pa->type == PEER_AT_GLOBAL_FLAG) {
+ cur_val = !!CHECK_FLAG(peer->flags, pa->u.flag);
+ cur_ovrd = !!CHECK_FLAG(peer->flags_override, pa->u.flag);
+ cur_inv = !!CHECK_FLAG(peer->flags_invert, pa->u.flag);
+ } else /* if (pa->type == PEER_AT_AF_FLAG) */ {
+ cur_val = !!CHECK_FLAG(peer->af_flags[pa->afi][pa->safi],
+ pa->u.flag);
+ cur_ovrd = !!CHECK_FLAG(
+ peer->af_flags_override[pa->afi][pa->safi], pa->u.flag);
+ cur_inv = !!CHECK_FLAG(peer->af_flags_invert[pa->afi][pa->safi],
+ pa->u.flag);
+ }
/* Assert expected flag states. */
TEST_ASSERT_EQ(test, cur_val, exp_val);
TEST_ASSERT_EQ(test, cur_inv, exp_inv);
}
-static void test_af_filter(struct test *test, struct peer *peer,
- struct test_peer_attr *attr, bool exp_state,
- bool exp_ovrd)
+static void test_af_filter(struct test *test, struct test_peer_attr *pa,
+ struct peer *peer, bool exp_state, bool exp_ovrd)
{
bool cur_ovrd;
struct bgp_filter *filter;
+ /* Skip execution if test instance has previously failed. */
+ if (test->state != TEST_SUCCESS)
+ return;
+
/* Fetch and assert current state of override flag. */
- cur_ovrd = !!CHECK_FLAG(peer->filter_override[attr->afi][attr->safi]
- [attr->u.filter.direct],
- attr->u.filter.flag);
+ cur_ovrd = !!CHECK_FLAG(
+ peer->filter_override[pa->afi][pa->safi][pa->u.filter.direct],
+ pa->u.filter.flag);
TEST_ASSERT_EQ(test, cur_ovrd, exp_ovrd);
/* Assert that map/list matches expected state (set/unset). */
- filter = &peer->filter[attr->afi][attr->safi];
+ filter = &peer->filter[pa->afi][pa->safi];
- switch (attr->u.filter.flag) {
+ switch (pa->u.filter.flag) {
case PEER_FT_DISTRIBUTE_LIST:
TEST_ASSERT_EQ(test,
- !!(filter->dlist[attr->u.filter.direct].name),
+ !!(filter->dlist[pa->u.filter.direct].name),
exp_state);
break;
case PEER_FT_FILTER_LIST:
TEST_ASSERT_EQ(test,
- !!(filter->aslist[attr->u.filter.direct].name),
+ !!(filter->aslist[pa->u.filter.direct].name),
exp_state);
break;
case PEER_FT_PREFIX_LIST:
TEST_ASSERT_EQ(test,
- !!(filter->plist[attr->u.filter.direct].name),
+ !!(filter->plist[pa->u.filter.direct].name),
exp_state);
break;
case PEER_FT_ROUTE_MAP:
- TEST_ASSERT_EQ(test,
- !!(filter->map[attr->u.filter.direct].name),
+ TEST_ASSERT_EQ(test, !!(filter->map[pa->u.filter.direct].name),
exp_state);
break;
case PEER_FT_UNSUPPRESS_MAP:
}
}
+static void test_custom(struct test *test, struct test_peer_attr *pa,
+ struct peer *peer, struct peer *group, bool peer_set,
+ bool group_set)
+{
+ int i;
+ char *handler_error;
+
+ for (i = 0; i < TEST_HANDLER_MAX; i++) {
+ /* Skip execution if test instance has previously failed. */
+ if (test->state != TEST_SUCCESS)
+ return;
+
+ /* Skip further execution if handler is undefined. */
+ if (!pa->handlers[i])
+ return;
+
+ /* Execute custom handler. */
+ pa->handlers[i](test, pa, peer, group, peer_set, group_set);
+ if (test->state != TEST_SUCCESS) {
+ test->state = TEST_CUSTOM_ERROR;
+ handler_error = test->error;
+ test->error = str_printf("custom handler failed: %s",
+ handler_error);
+ XFREE(MTYPE_TMP, handler_error);
+ }
+ }
+}
+
+
+static void test_process(struct test *test, struct test_peer_attr *pa,
+ struct peer *peer, struct peer *group, bool peer_set,
+ bool group_set)
+{
+ switch (pa->type) {
+ case PEER_AT_GLOBAL_FLAG:
+ case PEER_AT_AF_FLAG:
+ test_peer_flags(
+ test, pa, peer,
+ peer_set || (peer_group_active(peer) && group_set),
+ peer_set);
+ test_peer_flags(test, pa, group, group_set, false);
+ break;
+
+ case PEER_AT_AF_FILTER:
+ test_af_filter(
+ test, pa, peer,
+ peer_set || (peer_group_active(peer) && group_set),
+ peer_set);
+ test_af_filter(test, pa, group, group_set, false);
+ break;
+
+ case PEER_AT_GLOBAL_CUSTOM:
+ case PEER_AT_AF_CUSTOM:
+ /*
+ * Do nothing here - a custom handler can be executed, but this
+ * is not required. This will allow defining peer attributes
+ * which shall not be checked for flag/filter/other internal
+ * states.
+ */
+ break;
+
+ default:
+ test->state = TEST_INTERNAL_ERROR;
+ test->error =
+ str_printf("invalid attribute type: %d", pa->type);
+ break;
+ }
+
+ /* Attempt to call a custom handler if set for further processing. */
+ test_custom(test, pa, peer, group, peer_set, group_set);
+}
+
static void test_peer_attr(struct test *test, struct test_peer_attr *pa)
{
int tc = 1;
const char *type;
- const char *ec = pa->o.invert ? "no " : "";
- const char *dc = pa->o.invert ? "" : "no ";
+ const char *ecp = pa->o.invert_peer ? "no " : "";
+ const char *dcp = pa->o.invert_peer ? "" : "no ";
+ const char *ecg = pa->o.invert_group ? "no " : "";
+ const char *dcg = pa->o.invert_group ? "" : "no ";
const char *peer_cmd = pa->peer_cmd ?: pa->cmd;
const char *group_cmd = pa->group_cmd ?: pa->cmd;
struct peer *p = test->peer;
struct peer_group *g = test->group;
- if (pa->type == PEER_AT_AF_FLAG)
- type = "af-flag";
- else /* if (pa->type == PEER_AT_AF_FILTER) */
- type = "af-filter";
+ /* Determine type and if test is address-family relevant */
+ type = str_from_attr_type(pa->type);
+ if (!type) {
+ test->state = TEST_INTERNAL_ERROR;
+ test->error =
+ str_printf("invalid attribute type: %d", pa->type);
+ return;
+ }
- /* Test Case: Switch active address-family. */
- if (pa->type == PEER_AT_AF_FLAG || pa->type == PEER_AT_AF_FILTER) {
+ /*
+ * =====================================================================
+ * Test Case Suite 1: Config persistence after adding peer to group
+ *
+ * Example: If a peer attribute has value [1] and a group attribute has
+ * value [2], the peer attribute value should be persisted when the peer
+ * gets added to the peer-group.
+ *
+ * This test suite is meant to test the group2peer functions which can
+ * be found inside bgpd/bgpd.c, which are related to initial peer-group
+ * inheritance.
+ * =====================================================================
+ */
+
+ /* Test Preparation: Switch and activate address-family. */
+ if (!is_attr_type_global(pa->type)) {
test_log(test, "prepare: switch address-family to [%s]",
afi_safi_print(pa->afi, pa->safi));
test_execute(test, "address-family %s %s",
str_from_afi(pa->afi), str_from_safi(pa->safi));
+ test_execute(test, "neighbor %s activate", g->name);
+ test_execute(test, "neighbor %s activate", p->host);
}
+ /* Skip peer-group to peer transfer test cases if requested. */
+ if (pa->o.skip_xfer_cases && test->state == TEST_SUCCESS)
+ test->state = TEST_SKIPPING;
+
/* Test Case: Set flag on BGP peer. */
test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, peer_cmd,
p->host);
- test_execute(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
- test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+ test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
- if (pa->type == PEER_AT_AF_FLAG) {
- test_af_flags(test, p, pa, true, true);
- test_af_flags(test, g->conf, pa, false, false);
- } else if (pa->type == PEER_AT_AF_FILTER) {
- test_af_filter(test, p, pa, true, true);
- test_af_filter(test, g->conf, pa, false, false);
- }
+ test_process(test, pa, p, g->conf, true, false);
+
+ /* Test Case: Set flag on BGP peer-group. */
+ test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd,
+ g->name);
+ test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+ test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+ test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+ test_process(test, pa, p, g->conf, true, true);
/* Test Case: Add BGP peer to peer-group. */
test_log(test, "case %02d: add peer [%s] to group [%s]", tc++, p->host,
g->name);
test_execute(test, "neighbor %s peer-group %s", p->host, g->name);
- test_config_present(test, "neighbor %s peer-group %s", p->host,
- g->name);
- test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_config_present(test, "neighbor %s %speer-group %s", p->host,
+ p->conf_if ? "interface " : "", g->name);
+ test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+ test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+ test_process(test, pa, p, g->conf, true, true);
+
+ /* Test Case: Unset flag on BGP peer-group. */
+ test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type,
+ group_cmd, g->name);
+ test_execute(test, "%sneighbor %s %s", dcg, g->name, group_cmd);
+ test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
- if (pa->type == PEER_AT_AF_FLAG) {
- test_af_flags(test, p, pa, true, true);
- test_af_flags(test, g->conf, pa, false, false);
- } else if (pa->type == PEER_AT_AF_FILTER) {
- test_af_filter(test, p, pa, true, true);
- test_af_filter(test, g->conf, pa, false, false);
+ test_process(test, pa, p, g->conf, true, false);
+
+ /*
+ * =====================================================================
+ * Test Case Suite 2: Config inheritance after adding peer to group
+ *
+ * Example: If a peer attribute has not been set and a group attribute
+ * has a value of [2], the group attribute should be inherited to the
+ * peer without flagging the newly set value as overridden.
+ *
+ * This test suite is meant to test the group2peer functions which can
+ * be found inside bgpd/bgpd.c, which are related to initial peer-group
+ * inheritance.
+ * =====================================================================
+ */
+
+ /* Test Preparation: Re-initialize test environment. */
+ test_initialize(test);
+ p = test->peer;
+ g = test->group;
+
+ /* Test Preparation: Switch and activate address-family. */
+ if (!is_attr_type_global(pa->type)) {
+ test_log(test, "prepare: switch address-family to [%s]",
+ afi_safi_print(pa->afi, pa->safi));
+ test_execute(test, "address-family %s %s",
+ str_from_afi(pa->afi), str_from_safi(pa->safi));
+ test_execute(test, "neighbor %s activate", g->name);
+ test_execute(test, "neighbor %s activate", p->host);
+ }
+
+ /* Test Case: Set flag on BGP peer-group. */
+ test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd,
+ g->name);
+ test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+ test_config_absent(test, "neighbor %s %s", p->host, pa->cmd);
+ test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+ test_process(test, pa, p, g->conf, false, true);
+
+ /* Test Case: Add BGP peer to peer-group. */
+ test_log(test, "case %02d: add peer [%s] to group [%s]", tc++, p->host,
+ g->name);
+ test_execute(test, "neighbor %s peer-group %s", p->host, g->name);
+ test_config_present(test, "neighbor %s %speer-group %s", p->host,
+ p->conf_if ? "interface " : "", g->name);
+ test_config_absent(test, "neighbor %s %s", p->host, pa->cmd);
+ test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+ test_process(test, pa, p, g->conf, false, true);
+
+ /* Stop skipping test cases if previously enabled. */
+ if (pa->o.skip_xfer_cases && test->state == TEST_SKIPPING)
+ test->state = TEST_SUCCESS;
+
+ /*
+ * =====================================================================
+ * Test Case Suite 3: Miscellaneous flag checks
+ *
+ * This test suite does not focus on initial peer-group inheritance and
+ * instead executes various different commands to set/unset attributes
+ * on both peer- and group-level. These checks should always be executed
+ * and must pass.
+ * =====================================================================
+ */
+
+ /* Test Preparation: Re-initialize test environment. */
+ test_initialize(test);
+ p = test->peer;
+ g = test->group;
+
+ /* Test Preparation: Switch and activate address-family. */
+ if (!is_attr_type_global(pa->type)) {
+ test_log(test, "prepare: switch address-family to [%s]",
+ afi_safi_print(pa->afi, pa->safi));
+ test_execute(test, "address-family %s %s",
+ str_from_afi(pa->afi), str_from_safi(pa->safi));
+ test_execute(test, "neighbor %s activate", g->name);
+ test_execute(test, "neighbor %s activate", p->host);
}
+ /* Test Case: Set flag on BGP peer. */
+ test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, peer_cmd,
+ p->host);
+ test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+ test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+ test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
+ test_process(test, pa, p, g->conf, true, false);
+
+ /* Test Case: Add BGP peer to peer-group. */
+ test_log(test, "case %02d: add peer [%s] to group [%s]", tc++, p->host,
+ g->name);
+ test_execute(test, "neighbor %s peer-group %s", p->host, g->name);
+ test_config_present(test, "neighbor %s %speer-group %s", p->host,
+ p->conf_if ? "interface " : "", g->name);
+ test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+ test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
+ test_process(test, pa, p, g->conf, true, false);
+
/* Test Case: Re-add BGP peer to peer-group. */
test_log(test, "case %02d: re-add peer [%s] to group [%s]", tc++,
p->host, g->name);
test_execute(test, "neighbor %s peer-group %s", p->host, g->name);
- test_config_present(test, "neighbor %s peer-group %s", p->host,
- g->name);
- test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_config_present(test, "neighbor %s %speer-group %s", p->host,
+ p->conf_if ? "interface " : "", g->name);
+ test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
- if (pa->type == PEER_AT_AF_FLAG) {
- test_af_flags(test, p, pa, true, true);
- test_af_flags(test, g->conf, pa, false, false);
- } else if (pa->type == PEER_AT_AF_FILTER) {
- test_af_filter(test, p, pa, true, true);
- test_af_filter(test, g->conf, pa, false, false);
- }
+ test_process(test, pa, p, g->conf, true, false);
/* Test Case: Set flag on BGP peer-group. */
test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd,
g->name);
- test_execute(test, "%sneighbor %s %s", ec, g->name, group_cmd);
- test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
- test_config_present(test, "%sneighbor %s %s", ec, g->name, group_cmd);
- if (pa->type == PEER_AT_AF_FLAG) {
- test_af_flags(test, p, pa, true, true);
- test_af_flags(test, g->conf, pa, true, false);
- } else if (pa->type == PEER_AT_AF_FILTER) {
- test_af_filter(test, p, pa, true, true);
- test_af_filter(test, g->conf, pa, true, false);
- }
+ test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+ test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+ test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+ test_process(test, pa, p, g->conf, true, true);
/* Test Case: Unset flag on BGP peer-group. */
test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type,
group_cmd, g->name);
- test_execute(test, "%sneighbor %s %s", dc, g->name, group_cmd);
- test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_execute(test, "%sneighbor %s %s", dcg, g->name, group_cmd);
+ test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
- if (pa->type == PEER_AT_AF_FLAG) {
- test_af_flags(test, p, pa, true, true);
- test_af_flags(test, g->conf, pa, false, false);
- } else if (pa->type == PEER_AT_AF_FILTER) {
- test_af_filter(test, p, pa, true, true);
- test_af_filter(test, g->conf, pa, false, false);
- }
+ test_process(test, pa, p, g->conf, true, false);
/* Test Case: Set flag on BGP peer-group. */
test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd,
g->name);
- test_execute(test, "%sneighbor %s %s", ec, g->name, group_cmd);
- test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
- test_config_present(test, "%sneighbor %s %s", ec, g->name, group_cmd);
- if (pa->type == PEER_AT_AF_FLAG) {
- test_af_flags(test, p, pa, true, true);
- test_af_flags(test, g->conf, pa, true, false);
- } else if (pa->type == PEER_AT_AF_FILTER) {
- test_af_filter(test, p, pa, true, true);
- test_af_filter(test, g->conf, pa, true, false);
- }
+ test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+ test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+ test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+ test_process(test, pa, p, g->conf, true, true);
/* Test Case: Re-set flag on BGP peer. */
test_log(test, "case %02d: re-set %s [%s] on [%s]", tc++, type,
peer_cmd, p->host);
- test_execute(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
- test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
- test_config_present(test, "%sneighbor %s %s", ec, g->name, group_cmd);
- if (pa->type == PEER_AT_AF_FLAG) {
- test_af_flags(test, p, pa, true, true);
- test_af_flags(test, g->conf, pa, true, false);
- } else if (pa->type == PEER_AT_AF_FILTER) {
- test_af_filter(test, p, pa, true, true);
- test_af_filter(test, g->conf, pa, true, false);
- }
+ test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+ test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+ test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+ test_process(test, pa, p, g->conf, true, true);
/* Test Case: Unset flag on BGP peer. */
test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type, peer_cmd,
p->host);
- test_execute(test, "%sneighbor %s %s", dc, p->host, peer_cmd);
+ test_execute(test, "%sneighbor %s %s", dcp, p->host, peer_cmd);
test_config_absent(test, "neighbor %s %s", p->host, pa->cmd);
- test_config_present(test, "%sneighbor %s %s", ec, g->name, group_cmd);
- if (pa->type == PEER_AT_AF_FLAG) {
- test_af_flags(test, p, pa, true, false);
- test_af_flags(test, g->conf, pa, true, false);
- } else if (pa->type == PEER_AT_AF_FILTER) {
- test_af_filter(test, p, pa, true, false);
- test_af_filter(test, g->conf, pa, true, false);
- }
+ test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+ test_process(test, pa, p, g->conf, false, true);
/* Test Case: Unset flag on BGP peer-group. */
test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type,
group_cmd, g->name);
- test_execute(test, "%sneighbor %s %s", dc, g->name, group_cmd);
+ test_execute(test, "%sneighbor %s %s", dcg, g->name, group_cmd);
test_config_absent(test, "neighbor %s %s", p->host, pa->cmd);
test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
- if (pa->type == PEER_AT_AF_FLAG) {
- test_af_flags(test, p, pa, false, false);
- test_af_flags(test, g->conf, pa, false, false);
- } else if (pa->type == PEER_AT_AF_FILTER) {
- test_af_filter(test, p, pa, false, false);
- test_af_filter(test, g->conf, pa, false, false);
- }
+ test_process(test, pa, p, g->conf, false, false);
/* Test Case: Set flag on BGP peer. */
test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, peer_cmd,
p->host);
- test_execute(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
- test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+ test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
- if (pa->type == PEER_AT_AF_FLAG) {
- test_af_flags(test, p, pa, true, true);
- test_af_flags(test, g->conf, pa, false, false);
- } else if (pa->type == PEER_AT_AF_FILTER) {
- test_af_filter(test, p, pa, true, true);
- test_af_filter(test, g->conf, pa, false, false);
- }
+ test_process(test, pa, p, g->conf, true, false);
}
static void bgp_startup(void)
pa = &test_peer_attrs[i++];
/* Just copy the peer attribute structure for global flags. */
- if (pa->type == PEER_AT_GLOBAL_FLAG) {
+ if (is_attr_type_global(pa->type)) {
pac = XMALLOC(MTYPE_TMP, sizeof(struct test_peer_attr));
memcpy(pac, pa, sizeof(struct test_peer_attr));
listnode_add(pa_list, pac);
desc = str_printf("peer\\%s", pa->cmd);
/* Initialize new test instance. */
- test = test_new(desc, pa->o.use_ibgp);
+ test = test_new(desc, pa->o.use_ibgp, pa->o.use_iface_peer);
XFREE(MTYPE_TMP, desc);
/* Execute tests and finish test instance. */
# List of tests can be generated by executing:
# $> ./test_peer_attr 2>&1 | sed -n 's/\\/\\\\/g; s/\S\+ \[test\] \(.\+\)/TestFlag.okfail(\x27\1\x27)/pg'
#
+TestFlag.okfail('peer\\advertisement-interval')
+TestFlag.okfail('peer\\capability dynamic')
+TestFlag.okfail('peer\\capability extended-nexthop')
+TestFlag.okfail('peer\\capability extended-nexthop')
+TestFlag.okfail('peer\\description')
+TestFlag.okfail('peer\\disable-connected-check')
+TestFlag.okfail('peer\\dont-capability-negotiate')
+TestFlag.okfail('peer\\enforce-first-as')
+TestFlag.okfail('peer\\local-as')
+TestFlag.okfail('peer\\local-as 1 no-prepend')
+TestFlag.okfail('peer\\local-as 1 no-prepend replace-as')
+TestFlag.okfail('peer\\override-capability')
+TestFlag.okfail('peer\\passive')
+TestFlag.okfail('peer\\password')
+TestFlag.okfail('peer\\shutdown')
+TestFlag.okfail('peer\\strict-capability-match')
+TestFlag.okfail('peer\\timers')
+TestFlag.okfail('peer\\timers connect')
+TestFlag.okfail('peer\\update-source')
+TestFlag.okfail('peer\\update-source')
TestFlag.okfail('peer\\ipv4-unicast\\addpath-tx-all-paths')
TestFlag.okfail('peer\\ipv4-multicast\\addpath-tx-all-paths')
TestFlag.okfail('peer\\ipv6-unicast\\addpath-tx-all-paths')
TestFlag.okfail('peer\\ipv4-multicast\\default-originate route-map')
TestFlag.okfail('peer\\ipv6-unicast\\default-originate route-map')
TestFlag.okfail('peer\\ipv6-multicast\\default-originate route-map')
+TestFlag.okfail('peer\\ipv4-unicast\\distribute-list')
+TestFlag.okfail('peer\\ipv4-multicast\\distribute-list')
+TestFlag.okfail('peer\\ipv6-unicast\\distribute-list')
+TestFlag.okfail('peer\\ipv6-multicast\\distribute-list')
+TestFlag.okfail('peer\\ipv4-unicast\\distribute-list')
+TestFlag.okfail('peer\\ipv4-multicast\\distribute-list')
+TestFlag.okfail('peer\\ipv6-unicast\\distribute-list')
+TestFlag.okfail('peer\\ipv6-multicast\\distribute-list')
TestFlag.okfail('peer\\ipv4-unicast\\filter-list')
TestFlag.okfail('peer\\ipv4-multicast\\filter-list')
TestFlag.okfail('peer\\ipv6-unicast\\filter-list')
printf("verify: lib failed\n");
if (ospfd != lib) {
- printf("Mismatch in values at size %u\n"
+ printf("Mismatch in values at size %d\n"
"ospfd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
"isisd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
"lib: 0x%04x\n",
/* create vertices */
for (unsigned int i = 0; i < NUMNODES; i++) {
- snprintf(names[i], sizeof(names[i]), "%d", i);
+ snprintf(names[i], sizeof(names[i]), "%u", i);
gn[i] = graph_new_node(g, names[i], NULL);
}
static int log_cmp(const void *a, const void *b)
{
- if (a == NULL && b != NULL)
- return 0;
- if (b == NULL && a != NULL)
+ if (a == NULL || b == NULL)
return 0;
return !memcmp(a, b, 2 * sizeof(struct prefix));
t_remove = 1000 * (tv_stop.tv_sec - tv_lap.tv_sec);
t_remove += (tv_stop.tv_usec - tv_lap.tv_usec) / 1000;
- printf("Scheduling %d random timers took %ld.%03ld seconds.\n",
+ printf("Scheduling %d random timers took %lu.%03lu seconds.\n",
SCHEDULE_TIMERS, t_schedule / 1000, t_schedule % 1000);
- printf("Removing %d random timers took %ld.%03ld seconds.\n",
+ printf("Removing %d random timers took %lu.%03lu seconds.\n",
REMOVE_TIMERS, t_remove / 1000, t_remove % 1000);
fflush(stdout);
close(i);
/* change tty */
fd = open("/dev/tty", O_RDWR);
- ioctl(fd, TIOCNOTTY, 0);
- close(fd);
+ if (fd >= 0) {
+ ioctl(fd, TIOCNOTTY, 0);
+ close(fd);
+ }
chdir("/");
umask(022); /* set a default for dumb programs */
setpgid(0, 0); /* set the process group */
vty_out(vty, "%s", vty->buf);
break;
case CMD_SUCCESS_DAEMON: {
- int cmd_stat = CMD_SUCCESS;
+ int cmd_stat;
vty_out(vty, "%s", vty->buf);
cmd_stat = vtysh_client_execute(&vtysh_client[0],
return vtysh_exit_interface(self, vty, argc, argv);
}
+DEFUN (vtysh_show_poll,
+ vtysh_show_poll_cmd,
+ "show thread poll",
+ SHOW_STR
+ "Thread information\n"
+ "Thread Poll Information\n")
+{
+ unsigned int i;
+ int ret = CMD_SUCCESS;
+ char line[100];
+
+ snprintf(line, sizeof(line), "do show thread poll\n");
+ for (i = 0; i < array_size(vtysh_client); i++)
+ if (vtysh_client[i].fd >= 0) {
+ vty_out(vty, "Thread statistics for %s:\n",
+ vtysh_client[i].name);
+ ret = vtysh_client_execute(&vtysh_client[i], line);
+ vty_out(vty, "\n");
+ }
+ return ret;
+}
+
DEFUN (vtysh_show_thread,
vtysh_show_thread_cmd,
"show thread cpu [FILTER]",
}
DEFUNSH(VTYSH_ALL, no_vtysh_log_syslog, no_vtysh_log_syslog_cmd,
- "no log syslog [LEVEL]", NO_STR
+ "no log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
+ NO_STR
"Logging control\n"
"Cancel logging to syslog\n"
- "Logging level\n")
+ LOG_LEVEL_DESC)
{
return CMD_SUCCESS;
}
return CMD_SUCCESS;
}
-DEFUNSH_DEPRECATED(
- VTYSH_ALL, vtysh_log_trap, vtysh_log_trap_cmd,
- "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
- "Logging control\n"
- "(Deprecated) Set logging level and default for all destinations\n" LOG_LEVEL_DESC)
-{
- return CMD_SUCCESS;
-}
-
-DEFUNSH_DEPRECATED(VTYSH_ALL, no_vtysh_log_trap, no_vtysh_log_trap_cmd,
- "no log trap [LEVEL]", NO_STR
- "Logging control\n"
- "Permit all logging information\n"
- "Logging level\n")
-{
- return CMD_SUCCESS;
-}
-
DEFUNSH(VTYSH_ALL, vtysh_log_record_priority, vtysh_log_record_priority_cmd,
"log record-priority",
"Logging control\n"
strcat(integrate_sav, CONF_BACKUP_EXT);
/* Move current configuration file to backup config file. */
- unlink(integrate_sav);
- rename(fbackup, integrate_sav);
+ if (unlink(integrate_sav) != 0) {
+ vty_out(vty, "Warning: %s unlink failed\n", integrate_sav);
+ }
+ if (rename(fbackup, integrate_sav) != 0) {
+ vty_out(vty, "Error renaming %s to %s\n", fbackup,
+ integrate_sav);
+ }
free(integrate_sav);
}
char line[] = "do write terminal\n";
FILE *fp;
int fd;
+#ifdef FRR_USER
struct passwd *pwentry;
+#endif
+#ifdef FRR_GROUP
struct group *grentry;
+#endif
uid_t uid = -1;
gid_t gid = -1;
struct stat st;
snprintf(accmd, sizeof(accmd), "autocomplete %d %s %s", token->type,
token->text, token->varname ? token->varname : "-");
+ vty->of_saved = vty->of;
+ vty->of = NULL;
for (i = 0; i < array_size(vtysh_client); i++)
vtysh_client_run_all(&vtysh_client[i], accmd, 1, vtysh_ac_line,
comps);
+ vty->of = vty->of_saved;
}
static const struct cmd_variable_handler vtysh_var_handler[] = {
install_element(VIEW_NODE, &vtysh_show_work_queues_cmd);
install_element(VIEW_NODE, &vtysh_show_work_queues_daemon_cmd);
install_element(VIEW_NODE, &vtysh_show_thread_cmd);
+ install_element(VIEW_NODE, &vtysh_show_poll_cmd);
/* Logging */
install_element(VIEW_NODE, &vtysh_show_logging_cmd);
install_element(CONFIG_NODE, &no_vtysh_log_monitor_cmd);
install_element(CONFIG_NODE, &vtysh_log_syslog_cmd);
install_element(CONFIG_NODE, &no_vtysh_log_syslog_cmd);
- install_element(CONFIG_NODE, &vtysh_log_trap_cmd);
- install_element(CONFIG_NODE, &no_vtysh_log_trap_cmd);
install_element(CONFIG_NODE, &vtysh_log_facility_cmd);
install_element(CONFIG_NODE, &no_vtysh_log_facility_cmd);
install_element(CONFIG_NODE, &vtysh_log_record_priority_cmd);
return 0;
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
- if (len < 0)
+ if (len < 0) {
+ zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
+ __PRETTY_FUNCTION__,
+ h->nlmsg_len,
+ (size_t)NLMSG_LENGTH(sizeof(struct ifinfomsg)));
return -1;
+ }
/* We are interested in some AF_BRIDGE notifications. */
if (ifi->ifi_family == AF_BRIDGE)
return 0;
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
- if (len < 0)
+ if (len < 0) {
+ zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
+ __PRETTY_FUNCTION__,
+ h->nlmsg_len,
+ (size_t)NLMSG_LENGTH(sizeof(struct ifaddrmsg)));
return -1;
+ }
memset(tb, 0, sizeof tb);
netlink_parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len);
}
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
- if (len < 0)
+ if (len < 0) {
+ zlog_err("%s: Message received from netlink is of a broken size %d %zu",
+ __PRETTY_FUNCTION__, h->nlmsg_len,
+ (size_t)NLMSG_LENGTH(sizeof(struct ifinfomsg)));
return -1;
+ }
/* We are interested in some AF_BRIDGE notifications. */
if (ifi->ifi_family == AF_BRIDGE)
/* Install connected routes to the kernel. */
if_install_connected(ifp);
+ /* Install any static routes using this vrf interface */
+ if (IS_ZEBRA_IF_VRF(ifp)) {
+ static_fixup_vrf_ids(zvrf);
+ static_config_install_delayed_routes(zvrf);
+ }
+
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug("%u: IF %s up, scheduling RIB processing",
ifp->vrf_id, ifp->name);
return lookup_msg(rttype_str, rttype, "");
}
+#define NL_OK(nla, len) \
+ ((len) >= (int)sizeof(struct nlattr) \
+ && (nla)->nla_len >= sizeof(struct nlattr) \
+ && (nla)->nla_len <= (len))
+#define NL_NEXT(nla, attrlen) \
+ ((attrlen) -= RTA_ALIGN((nla)->nla_len), \
+ (struct nlattr *)(((char *)(nla)) + RTA_ALIGN((nla)->nla_len)))
+#define NL_RTA(r) \
+ ((struct nlattr *)(((char *)(r)) \
+ + NLMSG_ALIGN(sizeof(struct nlmsgerr))))
+
+static void netlink_parse_nlattr(struct nlattr **tb, int max,
+ struct nlattr *nla, int len)
+{
+ while (NL_OK(nla, len)) {
+ if (nla->nla_type <= max)
+ tb[nla->nla_type] = nla;
+ nla = NL_NEXT(nla, len);
+ }
+}
+
+static void netlink_parse_extended_ack(struct nlmsghdr *h)
+{
+ struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
+ const struct nlmsgerr *err =
+ (const struct nlmsgerr *)((uint8_t *)h
+ + NLMSG_ALIGN(
+ sizeof(struct nlmsghdr)));
+ const struct nlmsghdr *err_nlh = NULL;
+ uint32_t hlen = sizeof(*err);
+ const char *msg = NULL;
+ uint32_t off = 0;
+
+ if (!(h->nlmsg_flags & NLM_F_CAPPED))
+ hlen += h->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
+
+ memset(tb, 0, sizeof(tb));
+ netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, NL_RTA(h), hlen);
+
+ if (tb[NLMSGERR_ATTR_MSG])
+ msg = (const char *)RTA_DATA(tb[NLMSGERR_ATTR_MSG]);
+
+ if (tb[NLMSGERR_ATTR_OFFS]) {
+ off = *(uint32_t *)RTA_DATA(tb[NLMSGERR_ATTR_OFFS]);
+
+ if (off > h->nlmsg_len) {
+ zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS\n");
+ } else if (!(h->nlmsg_flags & NLM_F_CAPPED)) {
+ /*
+ * Header of failed message
+ * we are not doing anything currently with it
+ * but noticing it for later.
+ */
+ err_nlh = &err->msg;
+ zlog_warn("%s: Received %d extended Ack",
+ __PRETTY_FUNCTION__, err_nlh->nlmsg_type);
+ }
+ }
+
+ if (msg && *msg != '\0') {
+ bool is_err = !!err->error;
+
+ if (is_err)
+ zlog_err("Extended Error: %s", msg);
+ else
+ zlog_warn("Extended Warning: %s", msg);
+ }
+}
+
/*
* netlink_parse_info
*
int errnum = err->error;
int msg_type = err->msg.nlmsg_type;
+ if (h->nlmsg_len
+ < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+ zlog_err("%s error: message truncated",
+ nl->name);
+ return -1;
+ }
+
+ /*
+ * Parse the extended information before
+ * we actually handle it.
+ * At this point in time we do not
+ * do anything other than report the
+ * issue.
+ */
+ if (h->nlmsg_flags & NLM_F_ACK_TLVS)
+ netlink_parse_extended_ack(h);
+
/* If the error field is zero, then this is an
* ACK */
if (err->error == 0) {
continue;
}
- if (h->nlmsg_len
- < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
- zlog_err("%s error: message truncated",
- nl->name);
- return -1;
- }
-
/* Deal with errors that occur because of races
* in link handling */
if (nl == &zns->netlink_cmd
error = (*filter)(h, zns->ns_id, startup);
if (error < 0) {
zlog_err("%s filter function error", nl->name);
+ zlog_backtrace(LOG_ERR);
ret = error;
}
}
void kernel_init(struct zebra_ns *zns)
{
unsigned long groups;
+#if defined SOL_NETLINK
+ int one, ret;
+#endif
/*
* Initialize netlink sockets
zns->netlink_cmd.sock = -1;
netlink_socket(&zns->netlink_cmd, 0, zns->ns_id);
+ /*
+ * SOL_NETLINK is not available on all platforms yet
+ * apparently. It's in bits/socket.h which I am not
+ * sure that we want to pull into our build system.
+ */
+#if defined SOL_NETLINK
+ /*
+ * Let's tell the kernel that we want to receive extended
+ * ACKS over our command socket
+ */
+ one = 1;
+ ret = setsockopt(zns->netlink_cmd.sock, SOL_NETLINK, NETLINK_EXT_ACK,
+ &one, sizeof(one));
+
+ if (ret < 0)
+ zlog_notice("Registration for extended ACK failed : %d %s",
+ errno, safe_strerror(errno));
+#endif
+
/* Register kernel socket. */
if (zns->netlink.sock > 0) {
/* Only want non-blocking on the netlink event socket */
netlink_install_filter(zns->netlink.sock,
zns->netlink_cmd.snl.nl_pid);
zns->t_netlink = NULL;
+
thread_add_read(zebrad.master, kernel_read, zns,
zns->netlink.sock, &zns->t_netlink);
}
}
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
- if (len < 0)
+ if (len < 0) {
+ zlog_err("%s: Message received from netlink is of a broken size %d %zu",
+ __PRETTY_FUNCTION__, h->nlmsg_len,
+ (size_t)NLMSG_LENGTH(sizeof(struct rtmsg)));
return -1;
+ }
memset(tb, 0, sizeof tb);
netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len);
return 0;
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
- if (len < 0)
+ if (len < 0) {
+ zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
+ __PRETTY_FUNCTION__,
+ h->nlmsg_len,
+ (size_t)NLMSG_LENGTH(sizeof(struct rtmsg)));
return -1;
+ }
if (rtm->rtm_type == RTN_MULTICAST)
netlink_route_change_read_multicast(h, ns_id, startup);
/* Length validity. */
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ndmsg));
- if (len < 0)
+ if (len < 0) {
+ zlog_err("%s: Message received from netlink is of a broken size %d %zu",
+ __PRETTY_FUNCTION__, h->nlmsg_len,
+ (size_t)NLMSG_LENGTH(sizeof(struct ndmsg)));
return -1;
+ }
/* Is this a notification for the MAC FDB or IP neighbor table? */
ndm = NLMSG_DATA(h);
return 0;
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct fib_rule_hdr));
- if (len < 0)
+ if (len < 0) {
+ zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
+ __PRETTY_FUNCTION__, h->nlmsg_len,
+ (size_t)NLMSG_LENGTH(sizeof(struct fib_rule_hdr)));
return -1;
+ }
frh = NLMSG_DATA(h);
if (frh->family != AF_INET && frh->family != AF_INET6)
struct zapi_nexthop *api_nh;
struct nexthop *nexthop;
int count = 0;
+ afi_t afi;
memset(&api, 0, sizeof(api));
api.vrf_id = re->vrf_id;
api.instance = re->instance;
api.flags = re->flags;
+ afi = family2afi(p->family);
+ switch (afi) {
+ case AFI_IP:
+ if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
+ client->redist_v4_add_cnt++;
+ else
+ client->redist_v4_del_cnt++;
+ break;
+ case AFI_IP6:
+ if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
+ client->redist_v6_add_cnt++;
+ else
+ client->redist_v6_del_cnt++;
+ break;
+ default:
+ break;
+ }
+
/* Prefix. */
api.prefix = *p;
if (src_p) {
if (!is_default_prefix(&zpi.dst))
zpi.filter_bm |= PBR_FILTER_DST_IP;
- if (zpi.dst_port_min != 0)
+ if (zpi.dst_port_min != 0 || zpi.proto == IPPROTO_ICMP)
zpi.filter_bm |= PBR_FILTER_DST_PORT;
- if (zpi.src_port_min != 0)
+ if (zpi.src_port_min != 0 || zpi.proto == IPPROTO_ICMP)
zpi.filter_bm |= PBR_FILTER_SRC_PORT;
if (zpi.dst_port_max != 0)
zpi.filter_bm |= PBR_FILTER_DST_PORT_RANGE;
STREAM_GETL(s, zpi.action);
STREAM_GETL(s, zpi.fwmark);
STREAM_GET(&zpi.ipset_name, s, ZEBRA_IPSET_NAME_SIZE);
+ STREAM_GETW(s, zpi.pkt_len_min);
+ STREAM_GETW(s, zpi.pkt_len_max);
+ STREAM_GETW(s, zpi.tcp_flags);
+ STREAM_GETW(s, zpi.tcp_mask_flags);
+ STREAM_GETC(s, zpi.dscp_value);
+ STREAM_GETC(s, zpi.fragment);
STREAM_GETL(s, zpi.nb_interface);
zebra_pbr_iptable_update_interfacelist(s, &zpi);
nlh = (struct nlmsghdr *)((char *)nlh
+ NETLINK_ALIGN(
nlh->nlmsg_len));
- } while (len != 0 && return_nsid != NS_UNKNOWN && ret == 0);
+ } while (len != 0 && ret == 0);
}
close(fd);
continue;
if (event->mask & IN_DELETE)
return zebra_ns_delete(event->name);
+
+ if (offsetof(struct inotify_event, name) + event->len
+ >= sizeof(buf)) {
+ zlog_err("NS notify read: buffer underflow");
+ break;
+ }
+
+ if (strnlen(event->name, event->len) == event->len) {
+ zlog_err("NS notify error: bad event name");
+ break;
+ }
+
netnspath = ns_netns_pathname(NULL, event->name);
if (!netnspath)
continue;
{0}
};
+const struct message icmp_typecode_str[] = {
+ { 0 << 8, "echo-reply"},
+ { 0 << 8, "pong"},
+ { 3 << 8, "network-unreachable"},
+ { (3 << 8) + 1, "host-unreachable"},
+ { (3 << 8) + 2, "protocol-unreachable"},
+ { (3 << 8) + 3, "port-unreachable"},
+ { (3 << 8) + 4, "fragmentation-needed"},
+ { (3 << 8) + 5, "source-route-failed"},
+ { (3 << 8) + 6, "network-unknown"},
+ { (3 << 8) + 7, "host-unknown"},
+ { (3 << 8) + 9, "network-prohibited"},
+ { (3 << 8) + 10, "host-prohibited"},
+ { (3 << 8) + 11, "TOS-network-unreachable"},
+ { (3 << 8) + 12, "TOS-host-unreachable"},
+ { (3 << 8) + 13, "communication-prohibited"},
+ { (3 << 8) + 14, "host-precedence-violation"},
+ { (3 << 8) + 15, "precedence-cutoff"},
+ { 4 << 8, "source-quench"},
+ { 5 << 8, "network-redirect"},
+ { (5 << 8) + 1, "host-redirect"},
+ { (5 << 8) + 2, "TOS-network-redirect"},
+ { (5 << 8) + 3, "TOS-host-redirect"},
+ { 8 << 8, "echo-request"},
+ { 8 << 8, "ping"},
+ { 9 << 8, "router-advertisement"},
+ { 10 << 8, "router-solicitation"},
+ { 11 << 8, "ttl-zero-during-transit"},
+ { (11 << 8) + 1, "ttl-zero-during-reassembly"},
+ { 12 << 8, "ip-header-bad"},
+ { (12 << 8) + 1, "required-option-missing"},
+ { 13 << 8, "timestamp-request"},
+ { 14 << 8, "timestamp-reply"},
+ { 17 << 8, "address-mask-request"},
+ { 18 << 8, "address-mask-reply"},
+ {0}
+};
+
+/* definitions */
+static const struct message tcp_value_str[] = {
+ {TCP_HEADER_FIN, "FIN"},
+ {TCP_HEADER_SYN, "SYN"},
+ {TCP_HEADER_RST, "RST"},
+ {TCP_HEADER_PSH, "PSH"},
+ {TCP_HEADER_ACK, "ACK"},
+ {TCP_HEADER_URG, "URG"},
+ {0}
+};
+
+static const struct message fragment_value_str[] = {
+ {1, "dont-fragment"},
+ {2, "is-fragment"},
+ {4, "first-fragment"},
+ {8, "last-fragment"},
+ {0}
+};
+
/* static function declarations */
DEFINE_HOOK(zebra_pbr_ipset_entry_wrap_script_get_stat, (struct zebra_ns *zns,
struct zebra_pbr_ipset_entry *ipset,
key = jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE,
0x63ab42de);
key = jhash_1word(iptable->fwmark, key);
+ key = jhash_1word(iptable->pkt_len_min, key);
+ key = jhash_1word(iptable->pkt_len_max, key);
+ key = jhash_1word(iptable->tcp_flags, key);
+ key = jhash_1word(iptable->tcp_mask_flags, key);
+ key = jhash_1word(iptable->dscp_value, key);
+ key = jhash_1word(iptable->fragment, key);
return jhash_3words(iptable->filter_bm, iptable->type,
iptable->unique, key);
}
if (strncmp(r1->ipset_name, r2->ipset_name,
ZEBRA_IPSET_NAME_SIZE))
return 0;
+ if (r1->pkt_len_min != r2->pkt_len_min)
+ return 0;
+ if (r1->pkt_len_max != r2->pkt_len_max)
+ return 0;
+ if (r1->tcp_flags != r2->tcp_flags)
+ return 0;
+ if (r1->tcp_mask_flags != r2->tcp_mask_flags)
+ return 0;
+ if (r1->dscp_value != r2->dscp_value)
+ return 0;
+ if (r1->fragment != r2->fragment)
+ return 0;
return 1;
}
char ipset_name[ZEBRA_IPSET_NAME_SIZE];
};
-static const char *zebra_pbr_ipset_type2str(uint32_t type)
+const char *zebra_pbr_ipset_type2str(uint32_t type)
{
return lookup_msg(ipset_type_msg, type,
"Unrecognized IPset Type");
return prefix2str(pu, str, size);
}
+static void zebra_pbr_display_icmp(struct vty *vty,
+ struct zebra_pbr_ipset_entry *zpie)
+{
+ char decoded_str[20];
+ uint16_t port;
+
+ /* range icmp type */
+ if (zpie->src_port_max || zpie->dst_port_max) {
+ vty_out(vty, ":icmp:[type <%d:%d>;code <%d:%d>",
+ zpie->src_port_min, zpie->src_port_max,
+ zpie->dst_port_min, zpie->dst_port_max);
+ } else {
+ port = ((zpie->src_port_min << 8) & 0xff00) +
+ (zpie->dst_port_min & 0xff);
+ memset(decoded_str, 0, sizeof(decoded_str));
+ sprintf(decoded_str, "%d/%d",
+ zpie->src_port_min,
+ zpie->dst_port_min);
+ vty_out(vty, ":icmp:%s",
+ lookup_msg(icmp_typecode_str,
+ port, decoded_str));
+ }
+}
+
static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm,
uint16_t port_min, uint16_t port_max,
uint8_t proto)
zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
vty_out(vty, "\tfrom %s", buf);
- if (zpie->filter_bm & PBR_FILTER_SRC_PORT)
+ if (zpie->filter_bm & PBR_FILTER_SRC_PORT &&
+ zpie->proto != IPPROTO_ICMP)
zebra_pbr_display_port(vty, zpie->filter_bm,
zpie->src_port_min,
zpie->src_port_max,
vty_out(vty, " to ");
zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
vty_out(vty, "%s", buf);
- if (zpie->filter_bm & PBR_FILTER_DST_PORT)
+ if (zpie->filter_bm & PBR_FILTER_DST_PORT &&
+ zpie->proto != IPPROTO_ICMP)
zebra_pbr_display_port(vty, zpie->filter_bm,
zpie->dst_port_min,
zpie->dst_port_max,
zpie->proto);
+ if (zpie->proto == IPPROTO_ICMP)
+ zebra_pbr_display_icmp(vty, zpie);
} else if ((zpi->type == IPSET_NET) ||
(zpi->type == IPSET_NET_PORT)) {
char buf[PREFIX_STRLEN];
zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
vty_out(vty, "\tfrom %s", buf);
}
- if (zpie->filter_bm & PBR_FILTER_SRC_PORT)
+ if (zpie->filter_bm & PBR_FILTER_SRC_PORT &&
+ zpie->proto != IPPROTO_ICMP)
zebra_pbr_display_port(vty, zpie->filter_bm,
zpie->src_port_min,
zpie->src_port_max,
zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
vty_out(vty, "\tto %s", buf);
}
- if (zpie->filter_bm & PBR_FILTER_DST_PORT)
+ if (zpie->filter_bm & PBR_FILTER_DST_PORT &&
+ zpie->proto != IPPROTO_ICMP)
zebra_pbr_display_port(vty, zpie->filter_bm,
zpie->dst_port_min,
zpie->dst_port_max,
zpie->proto);
+ if (zpie->proto == IPPROTO_ICMP)
+ zebra_pbr_display_icmp(vty, zpie);
}
vty_out(vty, " (%u)\n", zpie->unique);
return HASHWALK_CONTINUE;
}
+size_t zebra_pbr_tcpflags_snprintf(char *buffer, size_t len,
+ uint16_t tcp_val)
+{
+ size_t len_written = 0;
+ static struct message nt = {0};
+ const struct message *pnt;
+ int incr = 0;
+
+ for (pnt = tcp_value_str;
+ memcmp(pnt, &nt, sizeof(struct message)); pnt++)
+ if (pnt->key & tcp_val) {
+ len_written += snprintf(buffer + len_written,
+ len - len_written,
+ "%s%s", incr ?
+ ",":"", pnt->str);
+ incr++;
+ }
+ return len_written;
+}
+
/*
*/
void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname)
vty_out(vty, "IPtable %s action %s (%u)\n", iptable->ipset_name,
iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect",
iptable->unique);
-
+ if (iptable->pkt_len_min || iptable->pkt_len_max) {
+ if (!iptable->pkt_len_max)
+ vty_out(vty, "\t pkt len %u\n",
+ iptable->pkt_len_min);
+ else
+ vty_out(vty, "\t pkt len [%u;%u]\n",
+ iptable->pkt_len_min,
+ iptable->pkt_len_max);
+ }
+ if (iptable->tcp_flags || iptable->tcp_mask_flags) {
+ char tcp_flag_str[64];
+ char tcp_flag_mask_str[64];
+
+ zebra_pbr_tcpflags_snprintf(tcp_flag_str,
+ sizeof(tcp_flag_str),
+ iptable->tcp_flags);
+ zebra_pbr_tcpflags_snprintf(tcp_flag_mask_str,
+ sizeof(tcp_flag_mask_str),
+ iptable->tcp_mask_flags);
+ vty_out(vty, "\t tcpflags [%s/%s]\n",
+ tcp_flag_str, tcp_flag_mask_str);
+ }
+ if (iptable->filter_bm & (MATCH_DSCP_SET | MATCH_DSCP_INVERSE_SET)) {
+ vty_out(vty, "\t dscp %s %d\n",
+ iptable->filter_bm & MATCH_DSCP_INVERSE_SET ?
+ "not" : "", iptable->dscp_value);
+ }
+ if (iptable->fragment) {
+ char val_str[10];
+
+ sprintf(val_str, "%d", iptable->fragment);
+ vty_out(vty, "\t fragment%s %s\n",
+ iptable->filter_bm & MATCH_FRAGMENT_INVERSE_SET ?
+ " not" : "", lookup_msg(fragment_value_str,
+ iptable->fragment, val_str));
+ }
ret = hook_call(zebra_pbr_iptable_wrap_script_get_stat,
zns, iptable, &pkts, &bytes);
if (ret && pkts > 0)
struct prefix src;
struct prefix dst;
+ /* udp/tcp src port or icmp type */
uint16_t src_port_min;
uint16_t src_port_max;
+ /* udp/tcp dst port or icmp code */
uint16_t dst_port_min;
uint16_t dst_port_max;
uint32_t action;
+ uint16_t pkt_len_min;
+ uint16_t pkt_len_max;
+ uint16_t tcp_flags;
+ uint16_t tcp_mask_flags;
+ uint8_t dscp_value;
+ uint8_t fragment;
+
uint32_t nb_interface;
struct list *interface_name_list;
char ipset_name[ZEBRA_IPSET_NAME_SIZE];
};
+extern const struct message icmp_typecode_str[];
+
+const char *zebra_pbr_ipset_type2str(uint32_t type);
+
void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule);
void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule);
void zebra_pbr_create_ipset(struct zebra_ns *zns,
extern void zebra_pbr_show_iptable(struct vty *vty);
extern void zebra_pbr_iptable_update_interfacelist(struct stream *s,
struct zebra_pbr_iptable *zpi);
+size_t zebra_pbr_tcpflags_snprintf(char *buffer, size_t len,
+ uint16_t tcp_val);
DECLARE_HOOK(zebra_pbr_ipset_entry_wrap_script_get_stat, (struct zebra_ns *zns,
struct zebra_pbr_ipset_entry *ipset,
if (new != old)
zlog_debug(
"%u:%s: Deleting route rn %p, re %p (type %d) "
- "old %p (type %d) - %s",
+ "old %p (type %d) - nexthop inactive",
zvrf_id(zvrf), buf, rn, new,
- new->type, old, old->type,
- nh_active ? "install failed"
- : "nexthop inactive");
+ new->type, old, old->type);
else
zlog_debug(
- "%u:%s: Deleting route rn %p, re %p (type %d) - %s",
+ "%u:%s: Deleting route rn %p, re %p (type %d) - nexthop inactive",
zvrf_id(zvrf), buf, rn, new,
- new->type,
- nh_active ? "install failed"
- : "nexthop inactive");
+ new->type);
}
/* If labeled-unicast route, uninstall transit LSP. */
rn, vrf_id,
"via %s ifindex %d type %d "
"doesn't exist in rib",
- inet_ntop(
- family2afi(afi),
- &nh->gate, buf2,
- INET_ADDRSTRLEN), /* FIXME
- */
- nh->ifindex, type);
+ inet_ntop(afi2family(afi),
+ &nh->gate, buf2,
+ sizeof(buf2)),
+ nh->ifindex, type);
else
rnode_debug(
rn, vrf_id,
#include "plist.h"
#include "nexthop.h"
#include "vrf.h"
+#include "frrstr.h"
#include "zebra/zserv.h"
#include "zebra/redistribute.h"
"src", route_set_src, route_set_src_compile, route_set_src_free,
};
+static void zebra_route_map_process_update_cb(char *rmap_name)
+{
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("Event handler for route-map: %s",
+ rmap_name);
+}
+
static int zebra_route_map_update_timer(struct thread *thread)
{
zebra_t_rmap_update = NULL;
"%u: Routemap update-timer fired, scheduling RIB processing",
VRF_DEFAULT);
+ route_map_walk_update_list(zebra_route_map_process_update_cb);
+
+ /*
+ * This code needs to be updated to be:
+ * 1) VRF Aware <sigh>
+ * 2) Route-map aware
+ */
zebra_import_table_rm_update();
rib_update(VRF_DEFAULT, RIB_UPDATE_RMAP_CHANGE);
zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
static void zebra_route_map_add(const char *rmap_name)
{
- zebra_route_map_mark_update(rmap_name);
+ if (route_map_mark_updated(rmap_name) == 0)
+ zebra_route_map_mark_update(rmap_name);
+
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
}
static void zebra_route_map_delete(const char *rmap_name)
{
- zebra_route_map_mark_update(rmap_name);
+ if (route_map_mark_updated(rmap_name) == 0)
+ zebra_route_map_mark_update(rmap_name);
+
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
}
static void zebra_route_map_event(route_map_event_t event,
const char *rmap_name)
{
- zebra_route_map_mark_update(rmap_name);
+ if (route_map_mark_updated(rmap_name) == 0)
+ zebra_route_map_mark_update(rmap_name);
+
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
}
return CMD_SUCCESS;
}
-DEFUN (default_vrf_vni_mapping,
+DEFUN_HIDDEN (default_vrf_vni_mapping,
default_vrf_vni_mapping_cmd,
"vni " CMD_VNI_RANGE "[prefix-routes-only]",
"VNI corresponding to the DEFAULT VRF\n"
return CMD_SUCCESS;
}
-DEFUN (no_default_vrf_vni_mapping,
+DEFUN_HIDDEN (no_default_vrf_vni_mapping,
no_default_vrf_vni_mapping_cmd,
"no vni " CMD_VNI_RANGE,
NO_STR
{
struct zserv *client = THREAD_ARG(thread);
struct stream *msg;
- uint32_t wcmd;
+ uint32_t wcmd = 0;
struct stream_fifo *cache;
/* If we have any data pending, try to flush it first */
vty_out(vty, "MAC-IP add notifications: %d\n", client->macipadd_cnt);
vty_out(vty, "MAC-IP delete notifications: %d\n", client->macipdel_cnt);
+#if defined DEV_BUILD
+ vty_out(vty, "Input Fifo: %zu:%zu Output Fifo: %zu:%zu\n",
+ client->ibuf_fifo->count, client->ibuf_fifo->max_count,
+ client->obuf_fifo->count, client->obuf_fifo->max_count);
+#endif
vty_out(vty, "\n");
return;
}