summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_aspath.c2
-rw-r--r--bgpd/bgp_attr.c3
-rw-r--r--bgpd/bgp_clist.c5
-rw-r--r--bgpd/bgp_evpn.c3
-rw-r--r--bgpd/bgp_evpn_vty.c21
-rw-r--r--bgpd/bgp_flowspec.c9
-rw-r--r--bgpd/bgp_flowspec_util.c133
-rw-r--r--bgpd/bgp_flowspec_util.h6
-rw-r--r--bgpd/bgp_flowspec_vty.c14
-rw-r--r--bgpd/bgp_io.c7
-rw-r--r--bgpd/bgp_mplsvpn.c25
-rw-r--r--bgpd/bgp_network.c2
-rw-r--r--bgpd/bgp_nexthop.c4
-rw-r--r--bgpd/bgp_open.c5
-rw-r--r--bgpd/bgp_pbr.c1007
-rw-r--r--bgpd/bgp_pbr.h19
-rw-r--r--bgpd/bgp_route.c52
-rw-r--r--bgpd/bgp_rpki.c43
-rw-r--r--bgpd/bgp_updgrp_packet.c2
-rw-r--r--bgpd/bgp_vpn.c34
-rw-r--r--bgpd/bgp_vty.c42
-rw-r--r--bgpd/bgp_zebra.c6
-rw-r--r--bgpd/bgpd.c7
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.c5
-rw-r--r--bgpd/rfapi/rfapi_vty.c18
-rw-r--r--doc/user/basic.rst12
-rw-r--r--doc/user/bgp.rst48
-rw-r--r--doc/user/conf.py3
-rw-r--r--doc/user/flowspec.rst348
-rw-r--r--doc/user/installation.rst85
-rw-r--r--doc/user/pbr.rst27
-rw-r--r--doc/user/zebra.rst4
-rw-r--r--eigrpd/eigrp_fsm.c8
-rw-r--r--eigrpd/eigrp_hello.c3
-rw-r--r--eigrpd/eigrp_interface.c3
-rw-r--r--eigrpd/eigrp_packet.c6
-rw-r--r--eigrpd/eigrp_topology.c16
-rw-r--r--include/linux/netlink.h247
-rw-r--r--include/subdir.am1
-rw-r--r--isisd/isis_lsp.c3
-rw-r--r--isisd/isis_pfpacket.c6
-rw-r--r--isisd/isis_spf.c43
-rw-r--r--isisd/isis_te.c2
-rw-r--r--isisd/isisd.c2
-rw-r--r--ldpd/ldp_debug.c3
-rw-r--r--ldpd/ldp_vty_conf.c54
-rw-r--r--ldpd/ldpd.c19
-rw-r--r--lib/clippy.c6
-rw-r--r--lib/command.c82
-rw-r--r--lib/command.h4
-rw-r--r--lib/command_match.c5
-rw-r--r--lib/imsg.c5
-rw-r--r--lib/libfrr.c51
-rw-r--r--lib/libfrr.h5
-rw-r--r--lib/linklist.c22
-rw-r--r--lib/linklist.h2
-rw-r--r--lib/pbr.h35
-rw-r--r--lib/plist.c5
-rw-r--r--lib/privs.c13
-rw-r--r--lib/sbuf.c5
-rw-r--r--lib/sockopt.c9
-rw-r--r--lib/sockunion.c3
-rw-r--r--lib/stream.c13
-rw-r--r--lib/stream.h3
-rw-r--r--lib/vrf.c39
-rw-r--r--lib/vty.c10
-rw-r--r--lib/vty.h2
-rw-r--r--nhrpd/nhrp_event.c2
-rw-r--r--nhrpd/nhrp_packet.c2
-rw-r--r--nhrpd/vici.c3
-rw-r--r--ospf6d/ospf6_abr.c28
-rw-r--r--ospf6d/ospf6_asbr.c10
-rw-r--r--ospf6d/ospf6_flood.c1
-rw-r--r--ospf6d/ospf6_intra.c7
-rw-r--r--ospf6d/ospf6_proto.c10
-rw-r--r--ospf6d/ospf6_proto.h9
-rw-r--r--ospf6d/ospf6_spf.c8
-rw-r--r--ospfd/ospf_api.c21
-rw-r--r--ospfd/ospf_apiserver.c3
-rw-r--r--ospfd/ospf_ase.c2
-rw-r--r--ospfd/ospf_ri.c8
-rw-r--r--ospfd/ospf_route.c4
-rw-r--r--ospfd/ospf_te.c5
-rw-r--r--ospfd/ospf_vty.c13
-rw-r--r--ospfd/ospf_zebra.c10
-rw-r--r--ospfd/ospfd.c7
-rw-r--r--pbrd/pbr_nht.c38
-rw-r--r--pbrd/pbr_nht.h8
-rw-r--r--pbrd/pbr_vty.c58
-rw-r--r--pimd/mtracebis.c21
-rw-r--r--pimd/pim_cmd.c4
-rw-r--r--pimd/pim_igmp_mtrace.c2
-rw-r--r--pimd/pim_pim.c2
-rw-r--r--pimd/pim_zebra.c30
-rw-r--r--ripd/ripd.c4
-rw-r--r--ripngd/ripng_interface.c10
-rw-r--r--sharpd/sharp_main.c1
-rw-r--r--tests/Makefile.am5
-rw-r--r--tools/start-stop-daemon.c6
-rw-r--r--vtysh/vtysh.c37
-rw-r--r--zebra/if_netlink.c20
-rw-r--r--zebra/kernel_netlink.c117
-rw-r--r--zebra/rt_netlink.c19
-rw-r--r--zebra/rule_netlink.c6
-rw-r--r--zebra/zapi_msg.c29
-rw-r--r--zebra/zebra_netns_id.c2
-rw-r--r--zebra/zebra_netns_notify.c12
-rw-r--r--zebra/zebra_pbr.c174
-rw-r--r--zebra/zebra_pbr.h15
-rw-r--r--zebra/zebra_rib.c12
-rw-r--r--zebra/zserv.c7
111 files changed, 2826 insertions, 702 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index e02617691f..05e67baa8a 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -1632,7 +1632,7 @@ struct aspath *aspath_reconcile_as4(struct aspath *aspath,
struct aspath *newpath = NULL, *mergedpath;
int hops, cpasns = 0;
- if (!aspath)
+ if (!aspath || !as4path)
return NULL;
seg = aspath->segments;
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 2c52b57b36..6596e7cfa2 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -1513,6 +1513,9 @@ bgp_attr_munge_as4_attrs(struct peer *const peer, struct attr *const attr,
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);
}
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index 7cf1477549..0ffbe174ed 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -1054,6 +1054,9 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
struct ecommunity *ecom = NULL;
regex_t *regex = NULL;
+ if (str == NULL)
+ return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+
entry = NULL;
/* Get community list. */
@@ -1089,7 +1092,7 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
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);
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 0557bbcce9..959418658c 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -4242,8 +4242,9 @@ void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
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);
}
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index cb71e06149..5a4ebc9b17 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -52,7 +52,6 @@ struct vni_walk_ctx {
json_object *json;
};
-#if defined(HAVE_CUMULUS)
static void display_vrf_import_rt(struct vty *vty, struct vrf_irt_node *irt,
json_object *json)
{
@@ -245,7 +244,7 @@ static void display_import_rt(struct vty *vty, struct irt_node *irt,
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);
}
@@ -980,7 +979,6 @@ static void show_vni_entry(struct hash_backet *backet, void *args[])
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,
@@ -1636,8 +1634,6 @@ DEFUN(no_evpnrt5_network,
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);
@@ -1721,6 +1717,7 @@ static void evpn_unconfigure_import_rt(struct bgp *bgp, struct bgpevpn *vpn,
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);
@@ -1788,6 +1785,7 @@ static void evpn_unconfigure_export_rt(struct bgp *bgp, struct bgpevpn *vpn,
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);
@@ -2752,7 +2750,6 @@ static void evpn_unset_advertise_autort_rfc8365(struct bgp *bgp)
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)
{
@@ -2799,7 +2796,6 @@ 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",
@@ -3262,10 +3258,11 @@ DEFUN(show_bgp_l2vpn_evpn_es,
{
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();
@@ -3547,10 +3544,11 @@ DEFUN(show_bgp_l2vpn_evpn_route_esi,
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;
@@ -3904,7 +3902,6 @@ DEFUN(show_bgp_l2vpn_evpn_import_rt,
return CMD_SUCCESS;
}
-#if defined(HAVE_CUMULUS)
DEFUN(test_adv_evpn_type4_route,
test_adv_evpn_type4_route_cmd,
"advertise es ESI",
@@ -4064,7 +4061,6 @@ ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_all, show_bgp_evpn_route_vni_all_cmd,
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,
@@ -4841,7 +4837,6 @@ DEFUN (no_bgp_evpn_vni_rt_without_val,
evpn_unconfigure_export_rt(bgp, vpn, NULL);
return CMD_SUCCESS;
}
-#endif
static int vni_cmp(const void **a, const void **b)
{
@@ -4961,7 +4956,6 @@ void bgp_ethernetvpn_init(void)
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);
@@ -5027,5 +5021,4 @@ void bgp_ethernetvpn_init(void)
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
}
diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c
index 884c5aa51a..9b998d4497 100644
--- a/bgpd/bgp_flowspec.c
+++ b/bgpd/bgp_flowspec.c
@@ -59,7 +59,8 @@ static int bgp_fs_nlri_validate(uint8_t *nlri_content, uint32_t len)
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);
@@ -71,12 +72,6 @@ static int bgp_fs_nlri_validate(uint8_t *nlri_content, uint32_t len)
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;
diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c
index 956cf28c21..1b87427661 100644
--- a/bgpd/bgp_flowspec_util.c
+++ b/bgpd/bgp_flowspec_util.c
@@ -124,8 +124,9 @@ static bool bgp_flowspec_contains_prefix(struct prefix *pfs,
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,
@@ -139,13 +140,6 @@ static bool bgp_flowspec_contains_prefix(struct prefix *pfs,
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;
@@ -312,14 +306,14 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
/*
- * 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)
@@ -348,32 +342,33 @@ int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
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;
@@ -419,92 +414,6 @@ int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
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)
{
@@ -623,7 +532,7 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
&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,
@@ -637,7 +546,7 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
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,
@@ -646,7 +555,7 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
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:
diff --git a/bgpd/bgp_flowspec_util.h b/bgpd/bgp_flowspec_util.h
index e4454ab4db..2d16e57a36 100644
--- a/bgpd/bgp_flowspec_util.h
+++ b/bgpd/bgp_flowspec_util.h
@@ -41,15 +41,11 @@ extern int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
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);
diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c
index b21e5ae0dc..90acd8fcb1 100644
--- a/bgpd/bgp_flowspec_vty.c
+++ b/bgpd/bgp_flowspec_vty.c
@@ -62,7 +62,7 @@ static const struct message bgp_flowspec_display_min[] = {
{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"},
@@ -173,7 +173,7 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
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,
@@ -221,11 +221,11 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
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) {
diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c
index 69c92e829c..c8d5b1daa1 100644
--- a/bgpd/bgp_io.c
+++ b/bgpd/bgp_io.c
@@ -174,7 +174,6 @@ static int bgp_process_reads(struct thread *thread)
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);
@@ -214,10 +213,8 @@ static int bgp_process_reads(struct thread *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;
}
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 28e8ceb15d..3a854be534 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -466,6 +466,7 @@ leak_update(
{
struct prefix *p = &bn->p;
struct bgp_info *bi;
+ struct bgp_info *bi_ultimate;
struct bgp_info *new;
char buf_prefix[PREFIX_STRLEN];
@@ -477,6 +478,26 @@ leak_update(
}
/*
+ * 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
*/
for (bi = bn->info; bi; bi = bi->next) {
@@ -528,7 +549,7 @@ leak_update(
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
/*
@@ -591,7 +612,7 @@ leak_update(
* 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
/*
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 84a959d0e8..476b64e75a 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -745,7 +745,7 @@ int bgp_socket(struct bgp *bgp, unsigned short port, const char *address)
close(sock);
}
freeaddrinfo(ainfo_save);
- if (count == 0) {
+ if (count == 0 && bgp->inst_type != BGP_INSTANCE_TYPE_VRF) {
zlog_err(
"%s: no usable addresses please check other programs usage of specified port %d",
__func__, port);
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index fd8d894878..32011d210b 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -438,7 +438,7 @@ int bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
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;
@@ -447,7 +447,7 @@ int bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
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);
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index aa98f8a557..da90bbd67d 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -80,8 +80,9 @@ void bgp_capability_vty_out(struct vty *vty, struct peer *peer,
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:
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index 5e36f91750..45ec21631c 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -21,6 +21,7 @@
#include "prefix.h"
#include "zclient.h"
#include "jhash.h"
+#include "pbr.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_pbr.h"
@@ -31,11 +32,13 @@
#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);
@@ -175,11 +178,220 @@ static int sprintf_bgp_pbr_match_val(char *str, struct bgp_pbr_match_val *mval,
_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[],
@@ -231,6 +443,8 @@ 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.
@@ -240,16 +454,6 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
* - 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:"
@@ -259,6 +463,7 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
}
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:"
@@ -278,12 +483,114 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
"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
*/
@@ -294,6 +601,14 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
" 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)) {
@@ -518,6 +833,12 @@ uint32_t bgp_pbr_match_hash_key(void *arg)
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);
}
@@ -540,6 +861,23 @@ int bgp_pbr_match_hash_equal(const void *arg1, const void *arg2)
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;
}
@@ -807,10 +1145,11 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
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
@@ -953,20 +1292,24 @@ static int bgp_pbr_get_remaining_entry(struct hash_backet *backet, void *arg)
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
@@ -974,17 +1317,19 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
*/
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) {
@@ -992,7 +1337,9 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
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) {
@@ -1000,9 +1347,35 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
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
@@ -1013,10 +1386,10 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
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;
@@ -1037,16 +1410,182 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
}
}
-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;
@@ -1055,14 +1594,104 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
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);
@@ -1084,33 +1713,63 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
/* 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);
@@ -1134,19 +1793,19 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
}
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);
@@ -1171,7 +1830,7 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
* 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);
@@ -1207,6 +1866,107 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
}
+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,
@@ -1219,9 +1979,16 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
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)
@@ -1251,10 +2018,97 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
dstp = &range;
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 = &range;
+ 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) {
@@ -1264,9 +2118,8 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
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;
@@ -1307,10 +2160,8 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
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
*/
@@ -1320,10 +2171,8 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
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:
diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h
index 20edaf30b8..307a34e34f 100644
--- a/bgpd/bgp_pbr.h
+++ b/bgpd/bgp_pbr.h
@@ -107,7 +107,6 @@ struct bgp_pbr_entry_main {
#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;
@@ -119,12 +118,14 @@ struct bgp_pbr_entry_main {
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];
@@ -133,8 +134,9 @@ struct bgp_pbr_entry_main {
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];
@@ -176,14 +178,15 @@ struct bgp_pbr_match {
*/
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
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 95e7def8fb..7057b62f2b 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1318,6 +1318,8 @@ void bgp_attr_add_gshut_community(struct attr *attr)
old = attr->community;
gshut = community_str2com("graceful-shutdown");
+ assert(gshut);
+
if (old) {
merge = community_merge(community_dup(old), gshut);
@@ -6280,7 +6282,6 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty,
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",
@@ -6288,10 +6289,6 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty,
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 ?
@@ -6564,14 +6561,8 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
} 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);
}
}
@@ -7305,9 +7296,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
{
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;
@@ -7340,7 +7329,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
json_nexthop_global = json_object_new_object();
}
-#if defined(HAVE_CUMULUS)
if (!json_paths && safi == SAFI_EVPN) {
char tag_buf[30];
@@ -7370,7 +7358,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
}
}
}
-#endif
attr = binfo->attr;
@@ -8023,14 +8010,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
if (binfo->extra && binfo->extra->damp_info)
bgp_damp_info_vty(vty, binfo, json_path);
-/* 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)
@@ -8601,9 +8583,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
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;
@@ -8630,7 +8610,6 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
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))
@@ -8648,29 +8627,10 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
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");
}
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index ac4dabc164..82e857dbf4 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -158,6 +158,30 @@ static void free_wrapper(void *ptr)
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);
@@ -253,14 +277,7 @@ static struct rtr_mgr_group *get_groups(void)
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++;
}
@@ -517,9 +534,13 @@ static int add_cache(struct cache *cache)
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;
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index cabd5b5cbd..34ddbfcd14 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -397,7 +397,7 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
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))
diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c
index 351f91dd1a..a771eedf0f 100644
--- a/bgpd/bgp_vpn.c
+++ b/bgpd/bgp_vpn.c
@@ -125,7 +125,7 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
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 = {
@@ -223,21 +223,27 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
}
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 && rm) {
- 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);
- }
}
}
if (use_json) {
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 4e0f7155ba..86f3f97c49 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -2009,27 +2009,19 @@ DEFUN (no_bgp_fast_external_failover,
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;
}
@@ -6745,6 +6737,11 @@ DEFPY (bgp_imexport_vrf,
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;
@@ -7075,7 +7072,7 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name,
!= 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);
}
@@ -7938,6 +7935,11 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int 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",
@@ -11409,7 +11411,6 @@ DEFUN (show_ip_bgp_peer_groups,
"Peer group name\n")
{
char *vrf, *pg;
- vrf = pg = NULL;
int idx = 0;
vrf = argv_find(argv, argc, "VIEWVRFNAME", &idx) ? argv[idx]->arg
@@ -12440,7 +12441,6 @@ void bgp_vty_init(void)
/* "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);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 2d808a6ffb..df3f9ddd6f 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -2219,6 +2219,12 @@ static void bgp_encode_pbr_iptable_match(struct stream *s,
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. */
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 64f36ec6e3..283949ab2a 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1032,6 +1032,8 @@ static inline bgp_peer_sort_t peer_calc_sort(struct peer *peer)
else {
struct peer *peer1;
+
+ assert(peer->group);
peer1 = listnode_head(peer->group->peer);
if (peer1)
@@ -2733,9 +2735,8 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
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);
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c
index 72255e54fb..8553846c90 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.c
+++ b/bgpd/rfapi/bgp_rfapi_cfg.c
@@ -1426,7 +1426,8 @@ DEFUN (vnc_export_nvegroup,
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) {
@@ -4518,7 +4519,7 @@ void bgp_rfapi_show_summary(struct bgp *bgp, struct vty *vty)
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;
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 18a979e531..cd12edbccb 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -388,15 +388,11 @@ int rfapiStream2Vty(void *stream, /* input */
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() */
@@ -3021,9 +3017,9 @@ static int rfapiDeleteLocalPrefixesByRFD(struct rfapi_local_reg_delete_arg *cda,
* 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__);
diff --git a/doc/user/basic.rst b/doc/user/basic.rst
index a75017c442..cb46080055 100644
--- a/doc/user/basic.rst
+++ b/doc/user/basic.rst
@@ -405,6 +405,18 @@ These options apply to all |PACKAGE_NAME| daemons.
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
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 13e0252210..725c55b15b 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -60,11 +60,11 @@ Address Families
----------------
Multiprotocol BGP enables BGP to carry routing information for multiple Network
-Layer protocols. BGP supports multiple Address Family Identifier (AFI), namely
-IPv4 and IPv6. Support is also provided for multiple sets of per-AFI
-information via Subsequent Address Family Identifiers (SAFI). In addition to
-unicast information, VPN information :rfc:`4364` and :rfc:`4659`, and
-Encapsulation attribute :rfc:`5512` is supported.
+Layer protocols. BGP supports an Address Family Identifier (AFI) for IPv4 and
+IPv6. Support is also provided for multiple sets of per-AFI information via the
+BGP Subsequent Address Family Identifier (SAFI). FRR supports SAFIs for unicast
+information, labeled information :rfc:`3107` and :rfc:`8277`, and Layer 3 VPN
+information :rfc:`4364` and :rfc:`4659`.
.. _bgp-route-selection:
@@ -174,6 +174,19 @@ will establish the connection with unicast only capability. When there are no
common capabilities, FRR sends Unsupported Capability error and then resets the
connection.
+.. _bgp-concepts-vrfs:
+
+VRFs: Virtual Routing and Forwarding
+------------------------------------
+
+*bgpd* supports :abbr:`L3VPN (Layer 3 Virtual Private Networks)` :abbr:`VRFs
+(Virtual Routing and Forwarding tables)` for IPv4 :rfc:`4364` and IPv6
+:rfc:`4659`. L3VPN routes, and their associated VRF MPLS labels, can be
+distributed to VPN SAFI neighbors in the *default*, i.e., non VRF, BGP
+instance. VRF MPLS labels are reached using *core* MPLS labels which are
+distributed using LDP or BGP labeled unicast. *bgpd* also supports inter-VRF
+route leaking. General information on FRR's VRF support can be found in
+:ref:`zebra-vrf`.
.. _bgp-router-configuration:
@@ -1550,10 +1563,11 @@ VRF Route Leaking
^^^^^^^^^^^^^^^^^
BGP routes may be leaked (i.e. copied) between a unicast VRF RIB and the VPN
-SAFI RIB of the default VRF (leaking is also permitted between the unicast RIB
-of the default VRF and VPN). A shortcut syntax is also available for specifying
-leaking from one vrf to another vrf using the VPN RIB as the intemediary. A
-common application of the VPN-VRF feature is to connect a customer's private
+SAFI RIB of the default VRF for use in MPLS-based L3VPNs. Unicast routes may
+also be leaked between any VRFs (including the unicast RIB of the default BGP
+instanced). A shortcut syntax is also available for specifying leaking from one
+VRF to another VRF using the default instance's VPN RIB as the intemediary. A
+common application of the VRF-VRF feature is to connect a customer's private
routing domain to a provider's VPN service. Leaking is configured from the
point of view of an individual VRF: ``import`` refers to routes leaked from VPN
to a unicast VRF, whereas ``export`` refers to routes leaked from a unicast VRF
@@ -1596,7 +1610,7 @@ auto-derived.
General configuration
"""""""""""""""""""""
-Configuration of route leaking between a unicast VRF RIB and the VPN safi RIB
+Configuration of route leaking between a unicast VRF RIB and the VPN SAFI RIB
of the default VRF is accomplished via commands in the context of a VRF
address-family:
@@ -1850,22 +1864,22 @@ Debugging
Show all enabled debugs.
-.. index:: [no] debug neighbor-events
-.. clicmd:: [no] debug neighbor-events
+.. index:: [no] debug bgp neighbor-events
+.. clicmd:: [no] debug bgp neighbor-events
Enable or disable debugging for neighbor events. This provides general
information on BGP events such as peer connection / disconnection, session
establishment / teardown, and capability negotiation.
-.. index:: [no] debug updates
-.. clicmd:: [no] debug updates
+.. index:: [no] debug bgp updates
+.. clicmd:: [no] debug bgp updates
Enable or disable debugging for BGP updates. This provides information on
BGP UPDATE messages transmitted and received between local and remote
instances.
-.. index:: [no] debug keepalives
-.. clicmd:: [no] debug keepalives
+.. index:: [no] debug bgp keepalives
+.. clicmd:: [no] debug bgp keepalives
Enable or disable debugging for BGP keepalives. This provides information on
BGP KEEPALIVE messages transmitted and received between local and remote
@@ -2434,6 +2448,8 @@ Example of how to set up a 6-Bone connection.
.. include:: rpki.rst
+.. include:: flowspec.rst
+
.. [#med-transitivity-rant] For some set of objects to have an order, there *must* be some binary ordering relation that is defined for *every* combination of those objects, and that relation *must* be transitive. I.e.:, if the relation operator is <, and if a < b and b < c then that relation must carry over and it *must* be that a < c for the objects to have an order. The ordering relation may allow for equality, i.e. a < b and b < a may both be true and imply that a and b are equal in the order and not distinguished by it, in which case the set has a partial order. Otherwise, if there is an order, all the objects have a distinct place in the order and the set has a total order)
.. [bgp-route-osci-cond] McPherson, D. and Gill, V. and Walton, D., "Border Gateway Protocol (BGP) Persistent Route Oscillation Condition", IETF RFC3345
.. [stable-flexible-ibgp] Flavel, A. and M. Roughan, "Stable and flexible iBGP", ACM SIGCOMM 2009
diff --git a/doc/user/conf.py b/doc/user/conf.py
index 3fced11024..28081bca7d 100644
--- a/doc/user/conf.py
+++ b/doc/user/conf.py
@@ -131,7 +131,8 @@ language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
-exclude_patterns = ['_build', 'rpki.rst', 'routeserver.rst', 'ospf_fundamentals.rst']
+exclude_patterns = ['_build', 'rpki.rst', 'routeserver.rst',
+ 'ospf_fundamentals.rst', 'flowspec.rst']
# The reST default role (used for this markup: `text`) to use for all
# documents.
diff --git a/doc/user/flowspec.rst b/doc/user/flowspec.rst
new file mode 100644
index 0000000000..4672b143ec
--- /dev/null
+++ b/doc/user/flowspec.rst
@@ -0,0 +1,348 @@
+.. _flowspec:
+
+Flowspec
+========
+
+.. _features-of-the-current-implementation-flowspec:
+
+Overview
+---------
+
+Flowspec introduces a new :abbr:`NLRI (Network Layer Reachability Information)`
+encoding format that is used to distribute traffic rule flow specifications.
+Basically, instead of simply relying on destination IP address for IP prefixes,
+the IP prefix is replaced by a n-tuple consisting of a rule. That rule can be a
+more or less complex combination of the following:
+
+
+- Network source/destination (can be one or the other, or both).
+- Layer 4 information for UDP/TCP : source port, destination port, or any port.
+- Layer 4 information for ICMP type and ICMP code.
+- Layer 4 information for TCP Flags.
+- Layer 3 information : DSCP value, Protocol type, packet length, fragmentation.
+- Misc layer 4 TCP flags.
+
+A combination of the above rules is applied for traffic filtering. This is
+encoded as part of specific BGP extended communities and the action can range
+from the obvious rerouting (to nexthop or to separate VRF) to shaping, or
+discard.
+
+The following IETF drafts and RFCs have been used to implement FRR Flowspec:
+
+- :rfc:`5575`
+- [Draft IETF IDR Flowspec redirect IP]_
+
+.. _design-principles-flowspec:
+
+Design Principles
+-----------------
+
+FRR implements the Flowspec client side, that is to say that BGP is able to
+receive Flowspec entries, but is not able to act as manager and send Flowspec
+entries.
+
+Linux provides the following mechanisms to implement policy based routing:
+
+- Filtering the traffic with ``Netfilter``.
+ ``Netfilter`` provides a set of tools like ``ipset`` and ``iptables`` that are
+ powerful enough to be able to filter such Flowspec filter rule.
+
+- using non standard routing tables via ``iproute2`` (via the ``ip rule``
+ command provided by ``iproute2``).
+ ``iproute2`` is already used by FRR's :ref:`pbr` daemon which provides basic
+ policy based routing based on IP source and destination criterion.
+
+Below example is an illustration of what Flowspec will inject in the underlying
+system:
+
+.. code-block:: shell
+
+ # linux shell
+ ipset create match0x102 hash:net,net counters
+ ipset add match0x102 32.0.0.0/16,40.0.0.0/16
+ iptables -N match0x102 -t mangle
+ iptables -A match0x102 -t mangle -j MARK --set-mark 102
+ iptables -A match0x102 -t mangle -j ACCEPT
+ iptables -i ntfp3 -t mangle -I PREROUTING -m set --match-set match0x102
+ src,dst -g match0x102
+ ip rule add fwmark 102 lookup 102
+ ip route add 40.0.0.0/16 via 44.0.0.2 table 102
+
+For handling an incoming Flowspec entry, the following workflow is applied:
+
+- incoming Flowspec entries are handled by *bgpd*, stored in the BGP RIB.
+- Flowspec entry is installed according to its complexity.
+
+It will be installed if one of the following filtering action is seen on the BGP
+extended community: either redirect IP, or redirect VRF, in conjunction with
+rate option, for redirecting traffic. Or rate option set to 0, for discarding
+traffic.
+
+According to the degree of complexity of the Flowspec entry, it will be
+installed in *zebra* RIB. For more information about what is supported in the
+FRR implementation as rule, see :ref:`flowspec-known-issues` chapter. Flowspec
+entry is split in several parts before being sent to *zebra*.
+
+- *zebra* daemon receives the policy routing configuration
+
+Policy Based Routing entities necessary to policy route the traffic in the
+underlying system, are received by *zebra*. Two filtering contexts will be
+created or appended in ``Netfilter``: ``ipset`` and ``iptable`` context. The
+former is used to define an IP filter based on multiple criterium. For instance,
+an ipset ``net:net`` is based on two ip addresses, while ``net,port,net`` is
+based on two ip addresses and one port ( for ICMP, UDP, or TCP). The way the
+filtering is used ( for example, is src port or dst port used ?) is defined by
+the latter filtering context. ``iptable`` command will reference the ``ipset``
+context and will tell how to filter and what to do. In our case, a marker will
+be set to indicate ``iproute2`` where to forward the traffic to. Sometimes, for
+dropping action, there is no need to add a marker; the ``iptable`` will tell to
+drop all packets matching the ``ipset`` entry.
+
+Configuration guide
+-------------------
+
+In order to configure an IPv4 Flowspec engine, use the following configuration.
+As of today, it is only possible to configure Flowspec on the default VRF.
+
+.. code-block:: frr
+
+ router bgp <AS>
+ neighbor <A.B.C.D> remote-as <remoteAS>
+ address-family ipv4 flowspec
+ neighbor <A.B.C.D> activate
+ exit
+ exit
+
+You can see Flowspec entries, by using one of the following show commands:
+
+.. index:: show bgp ipv4 flowspec [detail | A.B.C.D]
+.. clicmd:: show bgp ipv4 flowspec [detail | A.B.C.D]
+
+
+Per-Interface Configuration
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+One nice feature to use is the ability to apply Flowspec to a specific
+interface, instead of applying it to the whole machine. Despite the following
+IETF draft [Draft IETF IDR Flowspec Interface Set]_ is not implemented, it is
+possible to manually limit Flowspec application to some incoming interfaces.
+Actually, not using it can result to some unexpected behaviour like accounting
+twice the traffic, or slow down the traffic (filtering costs). To limit Flowspec
+to one specific interface, use the following command, under
+`flowspec address-family` node.
+
+.. index:: [no] local-install <IFNAME | any>
+.. clicmd:: [no] local-install <IFNAME | any>
+
+By default, Flowspec is activated on all interfaces. Installing it to a named
+interface will result in allowing only this interface. Conversely, enabling any
+interface will flush all previously configured interfaces.
+
+VRF redirection
+^^^^^^^^^^^^^^^
+
+Another nice feature to configure is the ability to redirect traffic to a
+separate VRF. This feature does not go against the ability to configure Flowspec
+only on default VRF. Actually, when you receive incoming BGP flowspec entries on
+that default VRF, you can redirect traffic to an other VRF.
+
+As a reminder, BGP flowspec entries have a BGP extended community that contains
+a Route Target. Finding out a local VRF based on Route Target consists in the
+following:
+
+- A configuration of each VRF must be done, with its Route Target set
+ Each VRF is being configured within a BGP VRF instance with its own Route
+ Target list. Route Target accepted format matches the following:
+ ``A.B.C.D:U16``, or ``U16:U32``, ``U32:U16``.
+
+- The first VRF with the matching Route Target will be selected to route traffic
+ to. Use the following command under ipv4 unicast address-family node
+
+.. index:: [no] rt redirect import RTLIST...
+.. clicmd:: [no] rt redirect import RTLIST...
+
+In order to illustrate, if the Route Target configured in the Flowspec entry is
+E.F.G.H:II, then a BGP VRF instance with the same Route Target will be set set.
+That VRF will then be selected. The below full configuration example depicts how
+Route Targets are configured and how VRFs and cross VRF configuration is done.
+Note that the VRF are mapped on Linux Network Namespaces. For data traffic to
+cross VRF boundaries, virtual ethernet interfaces are created with private IP
+adressing scheme.
+
+.. code-block:: frr
+
+ router bgp <ASx>
+ neighbor <A.B.C.D> remote-as <ASz>
+ address-family ipv4 flowspec
+ neighbor A.B.C.D activate
+ exit
+ exit
+ router bgp <ASy> vrf vrf2
+ address-family ipv4 unicast
+ rt redirect import <E.F.G.H:II>
+ exit
+ exit
+
+Flowspec Monitor and troubleshooting
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You can monitor policy-routing objects by using one of the following commands.
+Those command rely on the filtering contexts configured from BGP, and get the
+statistics information retrieved from the underlying system. In other words,
+those statistics are retrieved from ``Netfilter``.
+
+.. index:: show pbr ipset IPSETNAME | iptable
+.. clicmd:: show pbr ipset IPSETNAME | iptable
+
+``IPSETNAME`` is the policy routing object name created by ``ipset``.
+About rule contexts, it is possible to know which rule has been configured to
+policy-route some specific traffic. The :clicmd:`show pbr iptable` command
+displays for forwarded traffic, which table is used. Then it is easy to use that
+table identifier to dump the routing table that the forwarded traffic will
+match.
+
+.. code-block:: frr
+
+ show ip route table TABLEID
+
+``TABLEID`` is the table number identifier referencing the non standard routing
+table used in this example.
+You can troubleshoot Flowspec, or BGP policy based routing. For instance, if you
+encounter some issues when decoding a Flowspec entry, you should enable
+:clicmd:`debug bgp flowspec`.
+
+.. index:: [no] debug bgp flowspec
+.. clicmd:: [no] debug bgp flowspec
+
+If you fail to apply the flowspec entry into *zebra*, there should be some
+relationship with policy routing mechanism. Here, :clicmd:`debug bgp pbr error`
+could help.
+
+.. index:: [no] debug bgp pbr [error]
+.. clicmd:: [no] debug bgp pbr [error]
+
+To get information about policy routing contexts created/removed, only use
+:clicmd:`debug bgp pbr` command.
+
+Ensuring that a Flowspec entry has been correctly installed and that incoming
+traffic is policy-routed correctly can be checked like illustrated below. First
+of all, you must check whether the Flowspec entry has been installed or not.
+
+.. code-block:: frr
+
+ CLI# show bgp ipv4 flowspec 5.5.5.2/32
+ BGP flowspec entry: (flags 0x418)
+ Destination Address 5.5.5.2/32
+ IP Protocol = 17
+ Destination Port >= 50 , <= 90
+ FS:redirect VRF RT:255.255.255.255:255
+ received for 18:41:37
+ installed in PBR (match0x271ce00)
+
+This means that the Flowspec entry has been installed in a `iptable`
+named `match0x271ce00`. Once you have confirmation it is installed, you can
+check whether you find the associate entry by executing following command. You
+can also check whether incoming traffic has been matched by looking at counter
+line.
+
+.. code-block:: frr
+
+ CLI# show pbr ipset match0x271ce00
+ IPset match0x271ce00 type net,port
+ to 5.5.5.0/24:proto 6:80-120 (8)
+ pkts 1000, bytes 1000000
+ to 5.5.5.2:proto 17:50-90 (5)
+ pkts 1692918, bytes 157441374
+
+As you can see, the entry is present. note that an `iptable` entry can be used
+to host several Flowspec entries. In order to know where the matching traffic is
+redirected to, you have to look at the policy routing rules. The policy-routing
+is done by forwarding traffic to a routing table number. That routing table
+number is reached by using a `iptable`. The relationship between the routing
+table number and the incoming traffic is a MARKER that is set by the IPtable
+referencing the IPSet. In Flowspec case, `iptable` referencing the `ipset`
+context have the same name. So it is easy to know which routing table is used by
+issuing following command:
+
+.. code-block:: frr
+
+ CLI# show pbr iptable
+ IPtable match0x271ce00 action redirect (5)
+ pkts 1700000, bytes 158000000
+ table 257, fwmark 257
+ ...
+
+As you can see, by using following Linux commands, the MARKER `0x101` is present
+in both ``iptable`` and ``ip rule`` contexts.
+
+.. code-block:: shell
+
+ # iptables -t mangle --list match0x271ce00 -v
+ Chain match0x271ce00 (1 references)
+ pkts bytes target prot opt in out source destination
+ 1700K 158M MARK all -- any any anywhere anywhere
+ MARK set 0x101
+ 1700K 158M ACCEPT all -- any any anywhere anywhere
+
+ # ip rule list
+ 0:from all lookup local
+ 0:from all fwmark 0x101 lookup 257
+ 32766:from all lookup main
+ 32767:from all lookup default
+
+This allows us to see where the traffic is forwarded to.
+
+.. _flowspec-known-issues:
+
+Limitations / Known issues
+--------------------------
+
+As you can see, Flowspec is rich and can be very complex.
+As of today, not all Flowspec rules will be able to be converted into Policy
+Based Routing actions.
+
+- The ``Netfilter`` driver is not integrated into FRR yet. Not having this piece
+ of code prevents from injecting flowspec entries into the underlying system.
+
+- There are some limitations around filtering contexts
+
+ If I take example of UDP ports, or TCP ports in Flowspec, the information
+ can be a range of ports, or a unique value. This case is handled.
+ However, complexity can be increased, if the flow is a combination of a list
+ of range of ports and an enumerate of unique values. Here this case is not
+ handled. Similarly, it is not possible to create a filter for both src port
+ and dst port. For instance, filter on src port from [1-1000] and dst port =
+ 80. The same kind of complexity is not possible for packet length, ICMP type,
+ ICMP code.
+
+There are some other known issues:
+
+- The validation procedure depicted in :rfc:`5575` is not available.
+
+ This validation procedure has not been implemented, as this feature was not
+ used in the existing setups you shared wih us.
+
+- The filtering action shaper value, if positive, is not used to apply shaping.
+
+ If value is positive, the traffic is redirected to the wished destination,
+ without any other action configured by Flowspec.
+ It is recommended to configure Quality of Service if needed, more globally on
+ a per interface basis.
+
+- upon crash or unknown event, *zebra* may not have time to flush pbr contexts.
+
+ That is to say ``ipset``, ``iptable`` and ``ip rule`` contexts. This is also a
+ consequence due to the fact that ip rule / ipset / iptables are not discovered
+ at startup (not able to read appropriate contexts coming from Flowspec).
+
+Appendix
+--------
+
+More information with a public presentation that explains the design of Flowspec
+inside FRRouting.
+
+[Presentation]_
+
+.. [Draft IETF IDR Flowspec redirect IP] <https://tools.ietf.org/id/draft-ietf-idr-flowspec-redirect-ip-02.txt>
+.. [Draft IETF IDR Flowspec Interface Set] <https://tools.ietf.org/id/draft-ietf-idr-flowspec-interfaceset-03.txt>
+.. [Presentation] <https://docs.google.com/presentation/d/1ekQygUAG5yvQ3wWUyrw4Wcag0LgmbW1kV02IWcU4iUg/edit#slide=id.g378f0e1b5e_1_44>
diff --git a/doc/user/installation.rst b/doc/user/installation.rst
index 7a430fdf98..26d30f1e10 100644
--- a/doc/user/installation.rst
+++ b/doc/user/installation.rst
@@ -289,6 +289,91 @@ FRR will run with any kernel configuration but some recommendations do exist.
(:ref:`rip`) or *ospfd* (:ref:`ospfv2`) because these protocols use
multicast.
+Linux sysctl settings and kernel modules
+````````````````````````````````````````
+
+There are several kernel parameters that impact overall operation of FRR when
+using Linux as a router. Generally these parameters should be set in a
+sysctl related configuration file, e.g., :file:`/etc/sysctl.conf` on
+Ubuntu based systems and a new file
+:file:`/etc/sysctl.d/90-routing-sysctl.conf` on Centos based systems.
+Additional kernel modules are also needed to support MPLS forwarding.
+
+:makevar:`IPv4 and IPv6 forwarding`
+ The following are set to enable IP forwarding in the kernel:
+
+ .. code-block:: shell
+
+ net.ipv4.conf.all.forwarding=1
+ net.ipv6.conf.all.forwarding=1
+
+:makevar:`MPLS forwarding`
+ Basic MPLS kernel support was introduced 4.1, additional capability
+ was introduced in 4.3 and 4.5. For some general information on Linux
+ MPLS support see
+ https://www.netdevconf.org/1.1/proceedings/slides/prabhu-mpls-tutorial.pdf.
+ The following modules should be loaded to support MPLS forwarding,
+ and are generally added to a configuration file such as
+ :file:`/etc/modules-load.d/modules.conf`:
+
+ .. code-block:: shell
+
+ # Load MPLS Kernel Modules
+ mpls_router
+ mpls_iptunnel
+
+ The following is an example to enable MPLS forwarding in the kernel:
+
+ .. code-block:: shell
+
+ # Enable MPLS Label processing on all interfaces
+ net.mpls.conf.eth0.input=1
+ net.mpls.conf.eth1.input=1
+ net.mpls.conf.eth2.input=1
+ net.mpls.platform_labels=100000
+
+ Make sure to add a line equal to :file:`net.mpls.conf.<if>.input` for
+ each interface *'<if>'* used with MPLS and to set labels to an
+ appropriate value.
+
+:makevar:`VRF forwarding`
+ General information on Linux VRF support can be found in
+ https://www.kernel.org/doc/Documentation/networking/vrf.txt. Kernel
+ support for VRFs was introduced in 4.3 and improved upon through
+ 4.13, which is the version most used in FRR testing (as of June
+ 2018). Additional background on using Linux VRFs and kernel specific
+ features can be found in
+ http://schd.ws/hosted_files/ossna2017/fe/vrf-tutorial-oss.pdf.
+
+ The following impacts how BGP TCP sockets are managed across VRFs:
+
+ .. code-block:: shell
+
+ net.ipv4.tcp_l3mdev_accept=0
+
+ With this setting a BGP TCP socket is opened per VRF. This setting
+ ensures that other TCP services, such as SSH, provided for non-VRF
+ purposes are blocked from VRF associated Linux interfaces.
+
+ .. code-block:: shell
+
+ net.ipv4.tcp_l3mdev_accept=1
+
+ With this setting a single BGP TCP socket is shared across the
+ system. This setting exposes any TCP service running on the system,
+ e.g., SSH, to all VRFs. Generally this setting is not used in
+ environments where VRFs are used to support multiple administrative
+ groups.
+
+ **Important note** as of June 2018, Kernel versions 4.14-4.18 have a
+ known bug where VRF-specific TCP sockets are not properly handled. When
+ running these kernel versions, if unable to establish any VRF BGP
+ adjacencies, either downgrade to 4.13 or set
+ 'net.ipv4.tcp_l3mdev_accept=1'. The fix for this issue is planned to be
+ included in future kernel versions so upgrading your kernel may also
+ address this issue.
+
+
Building
^^^^^^^^
diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst
index aa48a3cd4f..638767c557 100644
--- a/doc/user/pbr.rst
+++ b/doc/user/pbr.rst
@@ -33,7 +33,6 @@ Nexthop Groups
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
@@ -46,24 +45,38 @@ listing of ECMP nexthops used to forward packets for when a pbr-map is matched.
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
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index b6060f0737..180d2d7efd 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -46,7 +46,7 @@ Besides the common invocation options (:ref:`common-invocation-options`), the
ZEBRA will create an associated VRF. The other daemons will operate on the VRF
VRF defined by *Zebra*, as usual.
- .. seealso:: :ref:`vrf`
+ .. seealso:: :ref:`zebra-vrf`
.. option:: --v6-rr-semantics
@@ -396,7 +396,7 @@ default) should the specified gateways not be reachable. E.g.:
After setting TABLENO with this command, static routes defined after this
are added to the specified table.
-.. _vrf:
+.. _zebra-vrf:
Virtual Routing and Forwarding
==============================
diff --git a/eigrpd/eigrp_fsm.c b/eigrpd/eigrp_fsm.c
index 4107d44090..eeefc51968 100644
--- a/eigrpd/eigrp_fsm.c
+++ b/eigrpd/eigrp_fsm.c
@@ -486,6 +486,7 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
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);
@@ -498,9 +499,10 @@ int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
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);
diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c
index d9e89357ca..2e55d57c31 100644
--- a/eigrpd/eigrp_hello.c
+++ b/eigrpd/eigrp_hello.c
@@ -417,7 +417,8 @@ void eigrp_sw_version_initialize(void)
if (dash)
dash[0] = '\0';
- ret = sscanf(ver_string, "%d.%d", &FRR_MAJOR, &FRR_MINOR);
+ ret = sscanf(ver_string, "%" SCNu32 ".%" SCNu32, &FRR_MAJOR,
+ &FRR_MINOR);
if (ret != 2)
zlog_err("Did not Properly parse %s, please fix VERSION string",
VERSION);
diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c
index cd459fdc42..cd62811fdf 100644
--- a/eigrpd/eigrp_interface.c
+++ b/eigrpd/eigrp_interface.c
@@ -336,6 +336,9 @@ void eigrp_if_free(struct eigrp_interface *ei, int source)
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);
diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c
index fab21e5201..027f30563f 100644
--- a/eigrpd/eigrp_packet.c
+++ b/eigrpd/eigrp_packet.c
@@ -566,7 +566,7 @@ int eigrp_read(struct thread *thread)
// return -1;
/* If incoming interface is passive one, ignore it. */
- if (ei && eigrp_if_is_passive(ei)) {
+ if (eigrp_if_is_passive(ei)) {
char buf[3][INET_ADDRSTRLEN];
if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
@@ -725,12 +725,12 @@ static struct stream *eigrp_recv_packet(int fd, struct interface **ifp,
zlog_warn("stream_recvmsg failed: %s", safe_strerror(errno));
return NULL;
}
- if ((unsigned int)ret < sizeof(iph)) /* ret must be > 0 now */
+ if ((unsigned int)ret < sizeof(*iph)) /* ret must be > 0 now */
{
zlog_warn(
"eigrp_recv_packet: discarding runt packet of length %d "
"(ip header size is %u)",
- ret, (unsigned int)sizeof(iph));
+ ret, (unsigned int)sizeof(*iph));
return NULL;
}
diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c
index becb29a95f..8ca0e282a8 100644
--- a/eigrpd/eigrp_topology.c
+++ b/eigrpd/eigrp_topology.c
@@ -182,6 +182,9 @@ void eigrp_prefix_entry_delete(struct route_table *table,
struct eigrp *eigrp = eigrp_lookup();
struct route_node *rn;
+ if (!eigrp)
+ return;
+
rn = route_node_lookup(table, pe->destination);
if (!rn)
return;
@@ -426,6 +429,9 @@ void eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
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;
@@ -442,6 +448,8 @@ void eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest)
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
@@ -471,11 +479,15 @@ void eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest)
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))
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
new file mode 100644
index 0000000000..0b2c29bd08
--- /dev/null
+++ b/include/linux/netlink.h
@@ -0,0 +1,247 @@
+/* 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 */
diff --git a/include/subdir.am b/include/subdir.am
index db5ed06c61..731785d4b4 100644
--- a/include/subdir.am
+++ b/include/subdir.am
@@ -4,6 +4,7 @@ noinst_HEADERS += \
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 \
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index bba86d4c1f..c8ef829064 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -622,7 +622,7 @@ static const char *lsp_bits2string(uint8_t lsp_bits, char *buf, size_t buf_size)
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);
+ sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0);
return buf;
}
@@ -1052,6 +1052,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
uint8_t subtlv_len;
if (IS_MPLS_TE(isisMplsTE)
+ && circuit->interface != NULL
&& HAS_LINK_PARAMS(
circuit->interface))
/* Update Local and Remote IP
diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c
index 6e56870ebd..fd82b85f51 100644
--- a/isisd/isis_pfpacket.c
+++ b/isisd/isis_pfpacket.c
@@ -309,9 +309,9 @@ int isis_recv_pdu_p2p(struct isis_circuit *circuit, uint8_t *ssnpa)
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 */
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index a55a0e1902..556f2890cf 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -77,14 +77,13 @@ enum vertextype {
/*
* 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 */
@@ -407,28 +406,28 @@ static const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
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();
@@ -598,17 +597,17 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree,
#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);
@@ -625,11 +624,12 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree,
}
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);
}
@@ -1212,7 +1212,7 @@ static void add_to_paths(struct isis_spftree *spftree,
{
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);
@@ -1473,8 +1473,9 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
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);
diff --git a/isisd/isis_te.c b/isisd/isis_te.c
index 6834f52a82..8e53df3b61 100644
--- a/isisd/isis_te.c
+++ b/isisd/isis_te.c
@@ -884,7 +884,7 @@ static uint8_t print_subtlv_use_bw(struct sbuf *buf, int indent,
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) {
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 6f04d72082..cecaa0693d 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -1373,7 +1373,7 @@ static int show_isis_database(struct vty *vty, const char *argv, int ui_level)
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];
diff --git a/ldpd/ldp_debug.c b/ldpd/ldp_debug.c
index 39e20ef7c8..ec70ef510a 100644
--- a/ldpd/ldp_debug.c
+++ b/ldpd/ldp_debug.c
@@ -41,6 +41,9 @@ int
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);
diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c
index 382b006884..4ef57f574a 100644
--- a/ldpd/ldp_vty_conf.c
+++ b/ldpd/ldp_vty_conf.c
@@ -89,6 +89,9 @@ struct cmd_node ldp_pseudowire_node =
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) {
@@ -428,6 +431,9 @@ ldp_vty_address_family(struct vty *vty, const char *negate, const char *af_str)
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;
@@ -709,6 +715,11 @@ ldp_vty_interface(struct vty *vty, const char *negate, const char *ifname)
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);
@@ -776,8 +787,9 @@ ldp_vty_trans_addr(struct vty *vty, const char *negate, const char *addr_str)
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);
}
@@ -797,7 +809,7 @@ ldp_vty_neighbor_targeted(struct vty *vty, const char *negate, const char *addr_
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);
@@ -1018,6 +1030,11 @@ ldp_vty_neighbor_password(struct vty *vty, const char *negate, struct in_addr ls
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);
@@ -1113,6 +1130,11 @@ ldp_vty_l2vpn(struct vty *vty, const char *negate, const char *name_str)
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) {
@@ -1158,8 +1180,13 @@ ldp_vty_l2vpn_bridge(struct vty *vty, const char *negate, const char *ifname)
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);
@@ -1187,6 +1214,11 @@ ldp_vty_l2vpn_pwtype(struct vty *vty, const char *negate, const char *type_str)
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
@@ -1208,6 +1240,11 @@ ldp_vty_l2vpn_interface(struct vty *vty, const char *negate, const char *ifname)
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) {
@@ -1246,6 +1283,11 @@ ldp_vty_l2vpn_pseudowire(struct vty *vty, const char *negate, const char *ifname
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) {
@@ -1294,6 +1336,10 @@ ldp_vty_l2vpn_pw_cword(struct vty *vty, const char *negate, const char *preferen
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
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index b265c98dae..b51ff82cea 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -187,6 +187,22 @@ FRR_DAEMON_INFO(ldpd, LDP,
.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[])
{
@@ -195,6 +211,7 @@ 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];
@@ -331,7 +348,7 @@ main(int argc, char *argv[])
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 ||
diff --git a/lib/clippy.c b/lib/clippy.c
index bcec6c2cca..44dcc02eb8 100644
--- a/lib/clippy.c
+++ b/lib/clippy.c
@@ -31,9 +31,11 @@
#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;
}
diff --git a/lib/command.c b/lib/command.c
index a8e61c6bb4..0bf856f248 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -261,8 +261,11 @@ void print_version(const char *progname)
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;
@@ -515,13 +518,6 @@ static int config_write_host(struct vty *vty)
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)) {
@@ -2429,7 +2425,8 @@ static int set_log_file(struct vty *vty, const char *fname, int loglevel)
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;
}
@@ -2445,6 +2442,39 @@ static int set_log_file(struct vty *vty, const char *fname, int loglevel)
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>]",
@@ -2552,36 +2582,6 @@ DEFUN (no_config_log_facility,
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",
@@ -2871,8 +2871,6 @@ void cmd_init(int terminal)
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);
diff --git a/lib/command.h b/lib/command.h
index 9bf482f41b..2d333b098a 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -240,9 +240,6 @@ struct cmd_node {
#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)
@@ -479,4 +476,5 @@ extern void
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 */
diff --git a/lib/command_match.c b/lib/command_match.c
index 99ec03e0c2..c165305d78 100644
--- a/lib/command_match.c
+++ b/lib/command_match.c
@@ -608,11 +608,14 @@ static struct cmd_token *disambiguate_tokens(struct cmd_token *first,
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;
diff --git a/lib/imsg.c b/lib/imsg.c
index 6419f805ab..5424140720 100644
--- a/lib/imsg.c
+++ b/lib/imsg.c
@@ -77,7 +77,7 @@ ssize_t imsg_read(struct imsgbuf *ibuf)
char buf[CMSG_SPACE(sizeof(int) * 1)];
} cmsgbuf;
struct iovec iov;
- ssize_t n = -1;
+ ssize_t n;
int fd;
struct imsg_fd *ifd;
@@ -110,7 +110,8 @@ again:
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;
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 88203fbeb6..9ea5e985cd 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -78,6 +78,8 @@ static void opt_extend(const struct optspec *os)
#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'},
@@ -86,6 +88,8 @@ static const struct option lo_always[] = {
{"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:",
@@ -94,7 +98,9 @@ static const struct optspec os_always = {
" -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};
@@ -444,6 +450,12 @@ static int frr_opt(int opt)
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;
}
@@ -543,9 +555,8 @@ struct thread_master *frr_init(void)
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)) {
@@ -721,15 +732,37 @@ static void frr_daemonize(void)
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();
@@ -813,7 +846,9 @@ static int frr_daemon_ctl(struct thread *t)
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();
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 7ffa780bfb..d255279906 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -50,11 +50,16 @@ struct frr_daemon_info {
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);
diff --git a/lib/linklist.c b/lib/linklist.c
index 2cfa3e7482..86649dd495 100644
--- a/lib/linklist.c
+++ b/lib/linklist.c
@@ -186,26 +186,10 @@ void listnode_move_to_tail(struct list *l, struct listnode *n)
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)
diff --git a/lib/linklist.h b/lib/linklist.h
index 39e70293d2..1e2631ea46 100644
--- a/lib/linklist.h
+++ b/lib/linklist.h
@@ -52,7 +52,9 @@ struct 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)
diff --git a/lib/pbr.h b/lib/pbr.h
index 401cfb0813..90997348cf 100644
--- a/lib/pbr.h
+++ b/lib/pbr.h
@@ -20,6 +20,12 @@
#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
*
@@ -83,6 +89,35 @@ struct pbr_rule {
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);
diff --git a/lib/plist.c b/lib/plist.c
index 5ed1589f45..056b737f54 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -850,6 +850,11 @@ static int vty_prefix_list_install(struct vty *vty, afi_t afi, const char *name,
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);
diff --git a/lib/privs.c b/lib/privs.c
index cfe7d6d6f8..7c99742d34 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -824,6 +824,19 @@ void zprivs_init(struct zebra_privs_t *zprivs)
#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
diff --git a/lib/sbuf.c b/lib/sbuf.c
index 37c1e5283d..03a2be3e09 100644
--- a/lib/sbuf.c
+++ b/lib/sbuf.c
@@ -63,13 +63,12 @@ void sbuf_push(struct sbuf *buf, int indent, const char *format, ...)
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;
diff --git a/lib/sockopt.c b/lib/sockopt.c
index 1d8d9990df..815be86c2e 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -457,8 +457,7 @@ int setsockopt_ifindex(int af, int sock, ifindex_t val)
*/
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 */
@@ -466,7 +465,11 @@ static ifindex_t getsockopt_ipv4_ifindex(struct msghdr *msgh)
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)
diff --git a/lib/sockunion.c b/lib/sockunion.c
index 28a7f647cb..44378b5363 100644
--- a/lib/sockunion.c
+++ b/lib/sockunion.c
@@ -46,6 +46,9 @@ int str2sockunion(const char *str, union sockunion *su)
{
int ret;
+ if (str == NULL)
+ return -1;
+
memset(su, 0, sizeof(union sockunion));
ret = inet_pton(AF_INET, str, &su->sin.sin_addr);
diff --git a/lib/stream.c b/lib/stream.c
index aba4c20166..a172eedc99 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -1109,6 +1109,10 @@ struct stream_fifo *stream_fifo_new(void)
/* 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
@@ -1116,8 +1120,15 @@ void stream_fifo_push(struct stream_fifo *fifo, struct stream *s)
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)
diff --git a/lib/stream.h b/lib/stream.h
index e5d325e43e..11af85c663 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -115,6 +115,9 @@ struct stream_fifo {
/* 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;
diff --git a/lib/vrf.c b/lib/vrf.c
index 797b25d01d..643ad29cf8 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -121,10 +121,10 @@ int vrf_switch_to_netns(vrf_id_t vrf_id)
/* VRF is default VRF. silently ignore */
if (!vrf || vrf->vrf_id == VRF_DEFAULT)
- return 0;
+ return 1; /* 1 = default */
/* VRF has no NETNS backend. silently ignore */
if (vrf->data.l.netns_name[0] == '\0')
- return 0;
+ return 2; /* 2 = no netns */
name = ns_netns_pathname(NULL, vrf->data.l.netns_name);
if (debug_vrf)
zlog_debug("VRF_SWITCH: %s(%u)", name, vrf->vrf_id);
@@ -505,6 +505,35 @@ void vrf_terminate(void)
}
}
+static int vrf_default_accepts_vrf(int type)
+{
+ const char *fname = NULL;
+ char buf[32] = {0x0};
+ int ret = 0;
+ FILE *fd = NULL;
+
+ /*
+ * TCP & UDP services running in the default VRF context (ie., not bound
+ * to any VRF device) can work across all VRF domains by enabling the
+ * tcp_l3mdev_accept and udp_l3mdev_accept sysctl options:
+ * sysctl -w net.ipv4.tcp_l3mdev_accept=1
+ * sysctl -w net.ipv4.udp_l3mdev_accept=1
+ */
+ if (type == SOCK_STREAM)
+ fname = "/proc/sys/net/ipv4/tcp_l3mdev_accept";
+ else if (type == SOCK_DGRAM)
+ fname = "/proc/sys/net/ipv4/udp_l3mdev_accept";
+ else
+ return ret;
+ fd = fopen(fname, "r");
+ if (fd == NULL)
+ return ret;
+ fgets(buf, 32, fd);
+ ret = atoi(buf);
+ fclose(fd);
+ return ret;
+}
+
/* Create a socket for the VRF. */
int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id,
char *interfacename)
@@ -515,6 +544,12 @@ int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id,
if (ret < 0)
zlog_err("%s: Can't switch to VRF %u (%s)", __func__, vrf_id,
safe_strerror(errno));
+ if (ret > 0 && interfacename && vrf_default_accepts_vrf(type)) {
+ zlog_err("VRF socket not used since net.ipv4.%s_l3mdev_accept != 0",
+ (type == SOCK_STREAM ? "tcp" : "udp"));
+ errno = EEXIST; /* not sure if this is the best error... */
+ return -2;
+ }
ret = socket(domain, type, protocol);
save_errno = errno;
ret2 = vrf_switchback_to_initial();
diff --git a/lib/vty.c b/lib/vty.c
index 280b2ace51..e9d1f2e323 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -2462,12 +2462,13 @@ static FILE *vty_use_backup_config(const char *fullpath)
}
/* 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) {
@@ -2525,8 +2526,10 @@ void vty_read_config(const char *config_file, char *config_default_dir)
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");
@@ -2550,6 +2553,7 @@ void vty_read_config(const char *config_file, char *config_default_dir)
}
vty_read_file(confp);
+ read_success = true;
fclose(confp);
@@ -2558,6 +2562,8 @@ void vty_read_config(const char *config_file, char *config_default_dir)
tmp_free_and_out:
if (tmp)
XFREE(MTYPE_TMP, tmp);
+
+ return read_success;
}
/* Small utility function which output log to the VTY. */
diff --git a/lib/vty.h b/lib/vty.h
index d14ddf5908..b55abf2204 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -242,7 +242,7 @@ extern void vty_frame(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
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 *);
diff --git a/nhrpd/nhrp_event.c b/nhrpd/nhrp_event.c
index e7adc971e5..7ca9731765 100644
--- a/nhrpd/nhrp_event.c
+++ b/nhrpd/nhrp_event.c
@@ -59,7 +59,7 @@ static void evmgr_recv_message(struct event_manager *evmgr, struct zbuf *zb)
buf[len] = 0;
debugf(NHRP_DEBUG_EVENT, "evmgr: msg: %s", buf);
- if (sscanf(buf, "eventid=%d", &eventid) != 1)
+ if (sscanf(buf, "eventid=%" SCNu32, &eventid) != 1)
continue;
if (sscanf(buf, "result=%63s", result) != 1)
continue;
diff --git a/nhrpd/nhrp_packet.c b/nhrpd/nhrp_packet.c
index c27ebe1d90..e62ee1ef72 100644
--- a/nhrpd/nhrp_packet.c
+++ b/nhrpd/nhrp_packet.c
@@ -164,7 +164,7 @@ struct nhrp_cie_header *nhrp_cie_pull(struct zbuf *zb,
if (!cie)
return NULL;
- if (cie->nbma_address_len + cie->nbma_subaddress_len) {
+ if (cie->nbma_address_len + cie->nbma_subaddress_len > 0) {
sockunion_set(nbma, afi2family(htons(hdr->afnum)),
zbuf_pulln(zb,
cie->nbma_address_len
diff --git a/nhrpd/vici.c b/nhrpd/vici.c
index e6111f9d71..eb3827a12f 100644
--- a/nhrpd/vici.c
+++ b/nhrpd/vici.c
@@ -287,6 +287,7 @@ static void vici_recv_sa(struct vici_conn *vici, struct zbuf *msg, int event)
char buf[32];
struct handle_sa_ctx ctx = {
.event = event,
+ .msgctx.nsections = 0
};
vici_parse_message(vici, msg, parse_sa_message, &ctx.msgctx);
@@ -305,7 +306,7 @@ static void vici_recv_message(struct vici_conn *vici, struct zbuf *msg)
uint32_t msglen;
uint8_t msgtype;
struct blob name;
- struct vici_message_ctx ctx;
+ struct vici_message_ctx ctx = { .nsections = 0 };
msglen = zbuf_get_be32(msg);
msgtype = zbuf_get8(msg);
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index b3aa3b21d2..7bccc78e00 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -161,9 +161,10 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
&& 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;
}
@@ -177,16 +178,17 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
/* 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;
}
@@ -641,6 +643,11 @@ void ospf6_abr_originate_summary(struct ospf6_route *route)
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) {
@@ -864,7 +871,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
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;
@@ -1284,7 +1292,7 @@ static char *ospf6_inter_area_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa,
(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",
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 7f575ee506..a723396507 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -497,7 +497,8 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
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;
@@ -576,7 +577,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
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;
@@ -603,7 +604,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
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) {
@@ -1705,7 +1706,8 @@ static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa,
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
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index 2059d84868..ae26668c8a 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -347,6 +347,7 @@ void ospf6_flood_interface(struct ospf6_neighbor *from, struct ospf6_lsa *lsa,
"Received is newer, remove requesting");
if (req == on->last_ls_req) {
ospf6_lsa_unlock(req);
+ req = NULL;
on->last_ls_req = NULL;
}
if (req)
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index d99541ebad..0ce08a61e2 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -1323,6 +1323,8 @@ static void ospf6_intra_prefix_update_route_origin(struct ospf6_route *oa_route)
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) {
@@ -1698,7 +1700,8 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
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;
@@ -1880,7 +1883,7 @@ void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa)
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)
diff --git a/ospf6d/ospf6_proto.c b/ospf6d/ospf6_proto.c
index 4b56a64b7f..864974c9a4 100644
--- a/ospf6d/ospf6_proto.c
+++ b/ospf6d/ospf6_proto.c
@@ -24,6 +24,16 @@
#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;
diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h
index ca2804c476..c9e7b549db 100644
--- a/ospf6d/ospf6_proto.h
+++ b/ospf6d/ospf6_proto.h
@@ -84,13 +84,8 @@ struct ospf6_prefix {
#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);
diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c
index 28c3459825..5b6691e6bf 100644
--- a/ospf6d/ospf6_spf.c
+++ b/ospf6d/ospf6_spf.c
@@ -677,6 +677,10 @@ void ospf6_spf_schedule(struct ospf6 *ospf6, unsigned int reason)
{
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)) {
@@ -686,10 +690,6 @@ void ospf6_spf_schedule(struct ospf6 *ospf6, unsigned int reason)
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))
diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c
index 8369dde822..b1175a2f68 100644
--- a/ospfd/ospf_api.c
+++ b/ospfd/ospf_api.c
@@ -510,17 +510,18 @@ struct msg *new_msg_originate_request(uint32_t seqnum, struct in_addr ifaddr,
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);
@@ -630,6 +631,9 @@ struct msg *new_msg_lsa_change_notify(uint8_t msgtype, uint32_t seqnum,
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);
@@ -640,10 +644,9 @@ struct msg *new_msg_lsa_change_notify(uint8_t msgtype, uint32_t seqnum,
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);
diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c
index 37735e3611..8f8900e147 100644
--- a/ospfd/ospf_apiserver.c
+++ b/ospfd/ospf_apiserver.c
@@ -1741,6 +1741,8 @@ struct ospf_lsa *ospf_apiserver_lsa_refresher(struct ospf_lsa *lsa)
struct ospf_lsa *new = NULL;
struct ospf *ospf;
+ assert(lsa);
+
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
assert(ospf);
@@ -1751,6 +1753,7 @@ struct ospf_lsa *ospf_apiserver_lsa_refresher(struct ospf_lsa *lsa)
dump_lsa_key(lsa));
lsa->data->ls_age =
htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */
+ goto out;
}
if (IS_LSA_MAXAGE(lsa)) {
diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c
index d425624862..c799a4b30f 100644
--- a/ospfd/ospf_ase.c
+++ b/ospfd/ospf_ase.c
@@ -582,7 +582,7 @@ static int ospf_ase_route_match_same(struct route_table *rt,
/* 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);
diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c
index 93267156f2..fa7dd04d19 100644
--- a/ospfd/ospf_ri.c
+++ b/ospfd/ospf_ri.c
@@ -1649,7 +1649,7 @@ DEFUN (pce_domain,
if (!ospf_ri_enabled(vty))
return CMD_WARNING_CONFIG_FAILED;
- if (sscanf(argv[idx_number]->arg, "%d", &as) != 1) {
+ if (sscanf(argv[idx_number]->arg, "%" SCNu32, &as) != 1) {
vty_out(vty, "pce_domain: fscanf: %s\n", safe_strerror(errno));
return CMD_WARNING_CONFIG_FAILED;
}
@@ -1684,7 +1684,7 @@ DEFUN (no_pce_domain,
uint32_t as;
struct ospf_pce_info *pce = &OspfRI.pce_info;
- if (sscanf(argv[idx_number]->arg, "%d", &as) != 1) {
+ if (sscanf(argv[idx_number]->arg, "%" SCNu32, &as) != 1) {
vty_out(vty, "no_pce_domain: fscanf: %s\n",
safe_strerror(errno));
return CMD_WARNING_CONFIG_FAILED;
@@ -1718,7 +1718,7 @@ DEFUN (pce_neigbhor,
if (!ospf_ri_enabled(vty))
return CMD_WARNING_CONFIG_FAILED;
- if (sscanf(argv[idx_number]->arg, "%d", &as) != 1) {
+ if (sscanf(argv[idx_number]->arg, "%" SCNu32, &as) != 1) {
vty_out(vty, "pce_neighbor: fscanf: %s\n",
safe_strerror(errno));
return CMD_WARNING_CONFIG_FAILED;
@@ -1754,7 +1754,7 @@ DEFUN (no_pce_neighbor,
uint32_t as;
struct ospf_pce_info *pce = &OspfRI.pce_info;
- if (sscanf(argv[idx_number]->arg, "%d", &as) != 1) {
+ if (sscanf(argv[idx_number]->arg, "%" SCNu32, &as) != 1) {
vty_out(vty, "no_pce_neighbor: fscanf: %s\n",
safe_strerror(errno));
return CMD_WARNING_CONFIG_FAILED;
diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c
index b964bbab74..b36f2f4652 100644
--- a/ospfd/ospf_route.c
+++ b/ospfd/ospf_route.c
@@ -170,8 +170,8 @@ int ospf_route_match_same(struct route_table *rt, struct prefix_ipv4 *prefix,
/* 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);
diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c
index 2b1b328617..86125d0c76 100644
--- a/ospfd/ospf_te.c
+++ b/ospfd/ospf_te.c
@@ -2051,12 +2051,11 @@ static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty,
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);
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 31cffea7f2..ddf9133ed9 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -2412,8 +2412,8 @@ DEFUN (ospf_neighbor_poll_interval,
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");
@@ -2422,8 +2422,8 @@ DEFUN (ospf_neighbor_poll_interval,
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);
@@ -8166,6 +8166,11 @@ DEFUN (ospf_redistribute_instance_source,
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) {
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 141ece9c7a..0a7776cced 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -670,6 +670,16 @@ int ospf_redistribute_set(struct ospf *ospf, int type, unsigned short 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;
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index 4cf38439c6..f315421843 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -243,13 +243,14 @@ static struct ospf *ospf_new(unsigned short instance, const char *name)
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;
diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c
index a4a9233f72..a8cefce84f 100644
--- a/pbrd/pbr_nht.c
+++ b/pbrd/pbr_nht.c
@@ -192,7 +192,7 @@ static void *pbr_nhgc_alloc(void *p)
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);
@@ -218,6 +218,9 @@ void pbr_nhgroup_add_cb(const char *name)
pnhgc = pbr_nht_add_group(name);
+ if (!pnhgc)
+ return;
+
DEBUGD(&pbr_dbg_nht, "%s: Added nexthop-group %s", __PRETTY_FUNCTION__,
name);
@@ -234,6 +237,13 @@ void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
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);
@@ -268,7 +278,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
/* 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;
@@ -487,6 +497,14 @@ void pbr_nht_add_individual_nexthop(struct pbr_map_sequence *pbrms)
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);
@@ -547,11 +565,18 @@ struct pbr_nexthop_group_cache *pbr_nht_add_group(const char *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;
}
@@ -709,8 +734,7 @@ static int pbr_nhg_hash_equal(const void *arg1, const void *arg2)
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;
@@ -723,7 +747,7 @@ uint32_t pbr_nht_get_next_tableid(void)
}
if (found) {
- nhg_tableid[i] = true;
+ nhg_tableid[i] = !peek;
return i;
} else
return 0;
diff --git a/pbrd/pbr_nht.h b/pbrd/pbr_nht.h
index e6fdbfd04c..d37803fbe3 100644
--- a/pbrd/pbr_nht.h
+++ b/pbrd/pbr_nht.h
@@ -56,9 +56,13 @@ extern void pbr_nht_write_table_range(struct vty *vty);
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
*/
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index 7e0e8d632b..44e14c5477 100644
--- a/pbrd/pbr_vty.c
+++ b/pbrd/pbr_vty.c
@@ -26,8 +26,8 @@
#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"
@@ -85,6 +85,34 @@ DEFUN_NOSH(no_pbr_map, no_pbr_map_cmd, "no pbr-map WORD [seq (1-700)]",
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
@@ -355,10 +383,9 @@ DEFPY (pbr_policy,
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);
@@ -368,13 +395,12 @@ DEFPY (show_pbr,
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;
@@ -439,7 +465,7 @@ DEFPY(show_pbr_nexthop_group,
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")
{
@@ -450,12 +476,11 @@ DEFPY(show_pbr_nexthop_group,
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;
@@ -489,7 +514,6 @@ DEFPY (show_pbr_interface,
}
/* PBR debugging CLI ------------------------------------------------------- */
-/* clang-format off */
static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
@@ -498,7 +522,7 @@ DEFPY(debug_pbr,
"[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"
@@ -527,7 +551,7 @@ DEFUN_NOSH(show_debugging_pbr,
"show debugging [pbr]",
SHOW_STR
DEBUG_STR
- "Policy Based Routing\n")
+ PBR_STR)
{
vty_out(vty, "PBR debugging status:\n");
@@ -536,7 +560,6 @@ DEFUN_NOSH(show_debugging_pbr,
return CMD_SUCCESS;
}
-/* clang-format on */
/* ------------------------------------------------------------------------- */
@@ -634,6 +657,7 @@ void pbr_vty_init(void)
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);
diff --git a/pimd/mtracebis.c b/pimd/mtracebis.c
index 731fdb1beb..c0d95aeed9 100644
--- a/pimd/mtracebis.c
+++ b/pimd/mtracebis.c
@@ -266,6 +266,8 @@ static int recv_response(int fd, int *hops, struct igmp_mtrace *mtracer)
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);
@@ -292,17 +294,20 @@ static int recv_response(int fd, int *hops, struct igmp_mtrace *mtracer)
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;
-
- if ((char *)mtrace + mtrace_len
- > (char *)mtrace_buf + IP_AND_MTRACE_BUF_LEN)
+ /* 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)) {
@@ -336,7 +341,7 @@ static int wait_for_response(int fd, int *hops, struct igmp_mtrace *mtrace,
{
fd_set readfds;
struct timeval timeout;
- int ret = -1;
+ int ret;
long msec, rmsec, tmsec;
FD_ZERO(&readfds);
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 55222ecddb..123c47568c 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -4504,8 +4504,8 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill,
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];
diff --git a/pimd/pim_igmp_mtrace.c b/pimd/pim_igmp_mtrace.c
index 673e2ca5b8..95d0278a34 100644
--- a/pimd/pim_igmp_mtrace.c
+++ b/pimd/pim_igmp_mtrace.c
@@ -817,7 +817,7 @@ int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr,
* 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 */
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c
index de09b070f4..f506875282 100644
--- a/pimd/pim_pim.c
+++ b/pimd/pim_pim.c
@@ -521,7 +521,7 @@ int pim_msg_send(int fd, struct in_addr src, struct in_addr dst,
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;
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index ae7f61c8eb..a58dfcdd5f 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -202,7 +202,7 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient,
* If we have a pimreg device callback and it's for a specific
* table set the master appropriately
*/
- if (sscanf(ifp->name, "pimreg%d", &table_id) == 1) {
+ if (sscanf(ifp->name, "pimreg%" SCNu32, &table_id) == 1) {
struct vrf *vrf;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
if ((table_id == vrf->data.l.table_id)
@@ -737,8 +737,6 @@ static void pim_zebra_connected(struct zclient *zclient)
void pim_zebra_init(void)
{
- int i;
-
/* Socket for receiving updates from Zebra daemon */
zclient = zclient_new_notify(master, &zclient_options_default);
@@ -754,31 +752,7 @@ void pim_zebra_init(void)
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__);
}
diff --git a/ripd/ripd.c b/ripd/ripd.c
index 92c27106d5..90dc7808eb 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -799,11 +799,11 @@ static int rip_auth_simple_password(struct rte *rte, struct sockaddr_in *from,
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;
}
diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c
index d1057bf53e..c463630b12 100644
--- a/ripngd/ripng_interface.c
+++ b/ripngd/ripng_interface.c
@@ -492,7 +492,7 @@ static int ripng_enable_network_lookup_if(struct interface *ifp)
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) {
struct prefix *p;
- struct route_node *node;
+ struct route_node *n;
p = connected->address;
@@ -501,10 +501,10 @@ static int ripng_enable_network_lookup_if(struct interface *ifp)
address.prefix = p->u.prefix6;
address.prefixlen = IPV6_MAX_BITLEN;
- node = route_node_match(ripng_enable_network,
- (struct prefix *)&address);
- if (node) {
- route_unlock_node(node);
+ n = route_node_match(ripng_enable_network,
+ (struct prefix *)&address);
+ if (n) {
+ route_unlock_node(n);
return 1;
}
}
diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c
index a478b416bf..22a19da0b3 100644
--- a/sharpd/sharp_main.c
+++ b/sharpd/sharp_main.c
@@ -51,7 +51,6 @@ uint32_t installed_routes = 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 = {
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9b60312cef..32d2db768a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -102,8 +102,6 @@ lib/cli/test_commands_defun.c: ../vtysh/vtysh_cmd.c
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 \
@@ -146,6 +144,9 @@ bgpd_test_ecommunity_SOURCES = bgpd/test_ecommunity.c
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
diff --git a/tools/start-stop-daemon.c b/tools/start-stop-daemon.c
index 8c3fe0c3c5..de58e0a20e 100644
--- a/tools/start-stop-daemon.c
+++ b/tools/start-stop-daemon.c
@@ -1024,8 +1024,10 @@ int main(int argc, char **argv)
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 */
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 309493b13e..b56eaa899f 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -2415,10 +2415,11 @@ DEFUNSH(VTYSH_ALL, vtysh_log_syslog, vtysh_log_syslog_cmd,
}
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;
}
@@ -2440,24 +2441,6 @@ DEFUNSH(VTYSH_ALL, no_vtysh_log_facility, no_vtysh_log_facility_cmd,
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"
@@ -2634,8 +2617,13 @@ static void backup_config_file(const char *fbackup)
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);
}
@@ -3369,9 +3357,12 @@ static void vtysh_autocomplete(vector comps, struct cmd_token *token)
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[] = {
@@ -3760,8 +3751,6 @@ void vtysh_init_vty(void)
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);
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index e6d324ab6a..5c84219418 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -586,8 +586,13 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
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)
@@ -893,8 +898,13 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
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);
@@ -1105,8 +1115,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
}
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)
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 0e79b82533..d9c6631845 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -498,6 +498,75 @@ const char *nl_rttype_to_str(uint8_t rttype)
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
*
@@ -582,6 +651,23 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
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) {
@@ -603,13 +689,6 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
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
@@ -692,6 +771,7 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
error = (*filter)(h, zns->ns_id, startup);
if (error < 0) {
zlog_err("%s filter function error", nl->name);
+ zlog_backtrace(LOG_ERR);
ret = error;
}
}
@@ -836,6 +916,9 @@ int netlink_request(struct nlsock *nl, struct nlmsghdr *n)
void kernel_init(struct zebra_ns *zns)
{
unsigned long groups;
+#if defined SOL_NETLINK
+ int one, ret;
+#endif
/*
* Initialize netlink sockets
@@ -866,6 +949,25 @@ void kernel_init(struct zebra_ns *zns)
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 */
@@ -880,6 +982,7 @@ void kernel_init(struct zebra_ns *zns)
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);
}
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index a5f288f541..9033491549 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -295,8 +295,12 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
}
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);
@@ -747,8 +751,13 @@ int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
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);
@@ -2356,8 +2365,12 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id)
/* 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);
diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c
index bcffdf4722..c7a8517e17 100644
--- a/zebra/rule_netlink.c
+++ b/zebra/rule_netlink.c
@@ -196,8 +196,12 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
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)
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 853a83373d..6e0d86d668 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -521,6 +521,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p,
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;
@@ -528,6 +529,24 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p,
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) {
@@ -2896,9 +2915,9 @@ static inline void zread_ipset_entry(ZAPI_HANDLER_ARGS)
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;
@@ -2938,6 +2957,12 @@ static inline void zread_iptable(ZAPI_HANDLER_ARGS)
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);
diff --git a/zebra/zebra_netns_id.c b/zebra/zebra_netns_id.c
index 317b02f601..96e6df34da 100644
--- a/zebra/zebra_netns_id.c
+++ b/zebra/zebra_netns_id.c
@@ -307,7 +307,7 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
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);
diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c
index 30f850597c..d0ea661403 100644
--- a/zebra/zebra_netns_notify.c
+++ b/zebra/zebra_netns_notify.c
@@ -212,6 +212,18 @@ static int zebra_ns_notify_read(struct thread *t)
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;
diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c
index d511c8c6ec..74ef25b031 100644
--- a/zebra/zebra_pbr.c
+++ b/zebra/zebra_pbr.c
@@ -44,6 +44,63 @@ static const struct message ipset_type_msg[] = {
{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,
@@ -322,6 +379,12 @@ uint32_t zebra_pbr_iptable_hash_key(void *arg)
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);
}
@@ -346,6 +409,18 @@ int zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2)
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;
}
@@ -515,7 +590,7 @@ struct pbr_ipset_name_lookup {
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");
@@ -773,6 +848,30 @@ static const char *zebra_pbr_prefix2str(union prefixconstptr pu,
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)
@@ -816,7 +915,8 @@ static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet,
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,
@@ -824,11 +924,14 @@ static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet,
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];
@@ -837,7 +940,8 @@ static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet,
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,
@@ -846,11 +950,14 @@ static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet,
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);
@@ -882,6 +989,26 @@ static int zebra_pbr_show_ipset_walkcb(struct hash_backet *backet, void *arg)
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)
@@ -946,7 +1073,42 @@ static int zebra_pbr_show_iptable_walkcb(struct hash_backet *backet, void *arg)
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)
diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h
index 6cbafd6daa..fd83502ae1 100644
--- a/zebra/zebra_pbr.h
+++ b/zebra/zebra_pbr.h
@@ -91,8 +91,10 @@ struct zebra_pbr_ipset_entry {
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;
@@ -131,6 +133,13 @@ struct zebra_pbr_iptable {
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;
@@ -138,6 +147,10 @@ struct zebra_pbr_iptable {
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,
@@ -225,6 +238,8 @@ extern void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname);
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,
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index bd00823ed8..8935956b25 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1428,18 +1428,14 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
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. */
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 14e0db40bf..b297f75ed9 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -198,7 +198,7 @@ static int zserv_write(struct thread *thread)
{
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 */
@@ -939,6 +939,11 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
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;
}