summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_evpn.c14
-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.c16
-rw-r--r--bgpd/bgp_network.c2
-rw-r--r--bgpd/bgp_pbr.c1007
-rw-r--r--bgpd/bgp_pbr.h19
-rw-r--r--bgpd/bgp_route.c43
-rw-r--r--bgpd/bgp_rpki.c57
-rw-r--r--bgpd/bgp_vty.c7
-rw-r--r--bgpd/bgp_zebra.c6
-rw-r--r--bgpd/bgpd.c11
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.c2
-rw-r--r--bgpd/rfapi/rfapi.c2
-rw-r--r--bgpd/rfapi/rfapi_vty.c4
-rw-r--r--bgpd/rfapi/vnc_import_bgp.c2
-rw-r--r--doc/user/bgp.rst52
-rw-r--r--doc/user/conf.py3
-rw-r--r--doc/user/flowspec.rst351
-rw-r--r--doc/user/installation.rst85
-rw-r--r--doc/user/zebra.rst4
-rw-r--r--eigrpd/eigrp_hello.c3
-rw-r--r--eigrpd/eigrp_packet.c6
-rw-r--r--isisd/isis_lsp.c2
-rw-r--r--isisd/isis_spf.c5
-rw-r--r--lib/linklist.c22
-rw-r--r--lib/pbr.h29
-rw-r--r--lib/stream.c13
-rw-r--r--lib/stream.h3
-rw-r--r--lib/vrf.c39
-rw-r--r--lib/vty.c16
-rw-r--r--lib/workqueue.c3
-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.c5
-rw-r--r--ospf6d/ospf6_asbr.c10
-rw-r--r--ospf6d/ospf6_intra.c5
-rw-r--r--ospf6d/ospf6_proto.c10
-rw-r--r--ospf6d/ospf6_proto.h9
-rw-r--r--ospfd/ospf_flood.c2
-rw-r--r--ospfd/ospf_lsa.c8
-rw-r--r--ospfd/ospf_ri.c8
-rw-r--r--ospfd/ospf_vty.c23
-rw-r--r--pimd/pim_mroute.c4
-rw-r--r--pimd/pim_zebra.c30
-rw-r--r--redhat/frr.spec.in343
-rw-r--r--ripngd/ripng_interface.c10
-rw-r--r--ripngd/ripngd.c5
-rw-r--r--vtysh/vtysh.c3
-rw-r--r--zebra/kernel_netlink.c1
-rw-r--r--zebra/redistribute.c4
-rw-r--r--zebra/zapi_msg.c29
-rw-r--r--zebra/zebra_netns_id.c2
-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/zebra_vrf.c8
-rw-r--r--zebra/zserv.c15
61 files changed, 2097 insertions, 642 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 0557bbcce9..e2cf094cc1 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);
}
@@ -5215,7 +5216,7 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac,
struct bgpevpn *vpn = NULL;
as_t as = 0;
- /* get the default instamce - required to get the AS number for VRF
+ /* get the default instance - required to get the AS number for VRF
* auto-creatio
*/
bgp_def = bgp_get_default();
@@ -5318,11 +5319,12 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id)
return -1;
}
- /* unimport remote routes from VRF, if it is AUTO vrf bgp_delete will
- * take care of uninstalling the routes from zebra
+ /* Remove remote routes from BGT VRF even if BGP_VRF_AUTO is configured,
+ * bgp_delete would not remove/decrement bgp_info of the ip_prefix
+ * routes. This will uninstalling the routes from zebra and decremnt the
+ * bgp info count.
*/
- if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO))
- uninstall_routes_for_vrf(bgp_vrf);
+ uninstall_routes_for_vrf(bgp_vrf);
/* delete/withdraw all type-5 routes */
delete_withdraw_vrf_routes(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..c695e7f125 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) {
@@ -274,7 +274,7 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
else
json_nlri_path = json_paths;
}
- if (display == NLRI_STRING_FORMAT_LARGE)
+ if (display == NLRI_STRING_FORMAT_LARGE && binfo)
vty_out(vty, "BGP flowspec entry: (flags 0x%x)\n",
binfo->flags);
bgp_fs_nlri_get_string((unsigned char *)
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_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 0b1deba517..60d1b5f313 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -2168,7 +2168,6 @@ struct bgp_process_queue {
static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
afi_t afi, safi_t safi)
{
- struct prefix *p = &rn->p;
struct bgp_info *new_select;
struct bgp_info *old_select;
struct bgp_info_pair old_and_new;
@@ -2191,6 +2190,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
return;
}
+ struct prefix *p = &rn->p;
+
debug = bgp_debug_bestpath(&rn->p);
if (debug) {
prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf));
@@ -6282,7 +6283,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",
@@ -6290,10 +6290,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 ?
@@ -7301,9 +7297,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;
@@ -7336,7 +7330,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];
@@ -7366,7 +7359,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
}
}
}
-#endif
attr = binfo->attr;
@@ -8019,14 +8011,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)
@@ -8597,9 +8584,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;
@@ -8626,7 +8611,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))
@@ -8644,29 +8628,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..db182eef98 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -5,8 +5,8 @@
* Berlin
* Copyright (C) 2016-2017 Colin Sames (colin.sames@haw-hamburg.de), for HAW
* Hamburg
- * Copyright (C) 2017 Marcel Röthke (marcel.roethke@haw-hamburg.de), for HAW
- * Hamburg
+ * Copyright (C) 2017-2018 Marcel Röthke (marcel.roethke@haw-hamburg.de),
+ * for HAW Hamburg
*
* This file is part of FRRouting.
*
@@ -158,9 +158,41 @@ 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);
+static void ipv6_addr_to_host_byte_order(const uint32_t *src, uint32_t *dest)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ dest[i] = ntohl(src[i]);
+}
+
static route_map_result_t route_match(void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -253,14 +285,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++;
}
@@ -462,13 +487,11 @@ static int rpki_validate_prefix(struct peer *peer, struct attr *attr,
ip_addr_prefix.u.addr4.addr = ntohl(prefix->u.prefix4.s_addr);
break;
-#ifdef HAVE_IPV6
case AF_INET6:
ip_addr_prefix.ver = LRTR_IPV6;
ipv6_addr_to_host_byte_order(prefix->u.prefix6.s6_addr32,
ip_addr_prefix.u.addr6.addr);
break;
-#endif /* HAVE_IPV6 */
default:
return 0;
@@ -517,9 +540,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_vty.c b/bgpd/bgp_vty.c
index 3d1fdfd38d..86f3f97c49 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -7072,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);
}
@@ -7935,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",
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..d21c074ccc 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1026,12 +1026,16 @@ static inline bgp_peer_sort_t peer_calc_sort(struct peer *peer)
else if (peer->as_type == AS_EXTERNAL)
return BGP_PEER_EBGP;
- else if (peer->as_type == AS_SPECIFIED && peer->as)
+ else if (peer->as_type == AS_SPECIFIED && peer->as) {
+ assert(bgp);
return (bgp->as == peer->as ? BGP_PEER_IBGP
: BGP_PEER_EBGP);
+ }
else {
struct peer *peer1;
+
+ assert(peer->group);
peer1 = listnode_head(peer->group->peer);
if (peer1)
@@ -2733,9 +2737,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 491741a35b..8553846c90 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.c
+++ b/bgpd/rfapi/bgp_rfapi_cfg.c
@@ -4519,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.c b/bgpd/rfapi/rfapi.c
index 177244d277..04531433ac 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -2336,7 +2336,7 @@ int rfapi_reopen(struct rfapi_descriptor *rfd, struct bgp *bgp)
h = bgp->rfapi;
- assert(!CHECK_FLAG(h->flags, RFAPI_INCALLBACK));
+ assert(h != NULL && !CHECK_FLAG(h->flags, RFAPI_INCALLBACK));
if (CHECK_FLAG(rfd->flags,
RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY)
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 2f8f132fcd..cd12edbccb 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -3017,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/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c
index 4bc5535e1b..7182e952b5 100644
--- a/bgpd/rfapi/vnc_import_bgp.c
+++ b/bgpd/rfapi/vnc_import_bgp.c
@@ -2904,6 +2904,8 @@ void vnc_import_bgp_redist_disable(struct bgp *bgp, afi_t afi)
struct rfapi_descriptor *rfd;
vncHDBgpDirect.peer = bi->peer;
+ assert(bi->extra);
+
rfd = bi->extra->vnc.export
.rfapi_handle;
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 13e0252210..0fb27441b2 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
@@ -2062,8 +2076,8 @@ Displaying Routes by AS Path
.. index:: show ip bgp ipv4 vpn
.. clicmd:: show ip bgp ipv4 vpn
-.. index:: show ipv6 bgp ipv6 vpn
-.. clicmd:: show ipv6 bgp ipv6 vpn
+.. index:: show ip bgp ipv6 vpn
+.. clicmd:: show ip bgp ipv6 vpn
Print active IPV4 or IPV6 routes advertised via the VPN SAFI.
@@ -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..f6af88cac8
--- /dev/null
+++ b/doc/user/flowspec.rst
@@ -0,0 +1,351 @@
+.. _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 monitoring & 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
+
+.. index:: show ip route table TABLEID
+.. clicmd:: show ip route table TABLEID
+
+ ``TABLEID`` is the table number identifier referencing the non standard
+ routing table used in this example.
+
+.. index:: [no] debug bgp flowspec
+.. clicmd:: [no] debug bgp flowspec
+
+ 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 pbr [error]
+.. clicmd:: [no] debug bgp pbr [error]
+
+ 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.
+
+ 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 as demonstrated 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 an ``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 an unexpected crash or other 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/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_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_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/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 4dcde0cba6..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;
}
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 2e2933db33..556f2890cf 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -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/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/pbr.h b/lib/pbr.h
index 1704d8d37e..90997348cf 100644
--- a/lib/pbr.h
+++ b/lib/pbr.h
@@ -89,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/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 e9d1f2e323..073092dfb6 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -479,6 +479,8 @@ static int vty_command(struct vty *vty, char *buf)
const char *protocolname;
char *cp = NULL;
+ assert(vty);
+
/*
* Log non empty command lines
*/
@@ -496,13 +498,13 @@ static int vty_command(struct vty *vty, char *buf)
/* format the base vty info */
snprintf(vty_str, sizeof(vty_str), "vty[??]@%s", vty->address);
- if (vty)
- for (i = 0; i < vector_active(vtyvec); i++)
- if (vty == vector_slot(vtyvec, i)) {
- snprintf(vty_str, sizeof(vty_str),
- "vty[%d]@%s", i, vty->address);
- break;
- }
+
+ for (i = 0; i < vector_active(vtyvec); i++)
+ if (vty == vector_slot(vtyvec, i)) {
+ snprintf(vty_str, sizeof(vty_str), "vty[%d]@%s",
+ i, vty->address);
+ break;
+ }
/* format the prompt */
snprintf(prompt_str, sizeof(prompt_str), cmd_prompt(vty->node),
diff --git a/lib/workqueue.c b/lib/workqueue.c
index 1af51c06c1..39dd142afb 100644
--- a/lib/workqueue.c
+++ b/lib/workqueue.c
@@ -245,10 +245,11 @@ int work_queue_run(struct thread *thread)
char yielded = 0;
wq = THREAD_ARG(thread);
- wq->thread = NULL;
assert(wq);
+ wq->thread = NULL;
+
/* calculate cycle granularity:
* list iteration == 1 run
* listnode processing == 1 cycle
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 5efe702457..7bccc78e00 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -871,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;
@@ -1291,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_intra.c b/ospf6d/ospf6_intra.c
index 7898b10905..0ce08a61e2 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -1700,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;
@@ -1882,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/ospfd/ospf_flood.c b/ospfd/ospf_flood.c
index 820b892176..002c6bba8d 100644
--- a/ospfd/ospf_flood.c
+++ b/ospfd/ospf_flood.c
@@ -91,7 +91,7 @@ struct external_info *ospf_external_info_check(struct ospf *ospf,
p.prefix = lsa->data->id;
p.prefixlen = ip_masklen(al->mask);
- for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
+ for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
int redist_on = 0;
redist_on =
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 729e508865..502f233036 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -1889,7 +1889,7 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf,
zlog_debug(
"ospf_translated_nssa_refresh(): no Type-7 found for "
"Type-5 LSA Id %s",
- inet_ntoa(type5->data->id));
+ type5 ? inet_ntoa(type5->data->id) : "(null)");
return NULL;
}
@@ -1899,7 +1899,7 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf,
zlog_debug(
"ospf_translated_nssa_refresh(): No translated Type-5 "
"found for Type-7 with Id %s",
- inet_ntoa(type7->data->id));
+ type7 ? inet_ntoa(type7->data->id) : "(null)");
return NULL;
}
@@ -1912,7 +1912,7 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf,
zlog_debug(
"ospf_translated_nssa_refresh(): Could not translate "
"Type-7 for %s to Type-5",
- inet_ntoa(type7->data->id));
+ type7 ? inet_ntoa(type7->data->id) : "(null)");
return NULL;
}
@@ -1921,7 +1921,7 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf,
zlog_debug(
"ospf_translated_nssa_refresh(): Could not install "
"translated LSA, Id %s",
- inet_ntoa(type7->data->id));
+ type7 ? inet_ntoa(type7->data->id) : "(null)");
return NULL;
}
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_vty.c b/ospfd/ospf_vty.c
index ddf9133ed9..ec654b9e29 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -4809,16 +4809,19 @@ static void show_ip_ospf_nbr_nbma_detail_sub(struct vty *vty,
vty_out(vty, " Poll interval %d\n", nbr_nbma->v_poll);
/* Show poll-interval timer. */
- if (use_json) {
- long time_store;
- time_store = monotime_until(&nbr_nbma->t_poll->u.sands, NULL)
- / 1000LL;
- json_object_int_add(json_sub, "pollIntervalTimerDueMsec",
- time_store);
- } else
- vty_out(vty, " Poll timer due in %s\n",
- ospf_timer_dump(nbr_nbma->t_poll, timebuf,
- sizeof(timebuf)));
+ if (nbr_nbma->t_poll) {
+ if (use_json) {
+ long time_store;
+ time_store = monotime_until(&nbr_nbma->t_poll->u.sands,
+ NULL) / 1000LL;
+ json_object_int_add(json_sub,
+ "pollIntervalTimerDueMsec",
+ time_store);
+ } else
+ vty_out(vty, " Poll timer due in %s\n",
+ ospf_timer_dump(nbr_nbma->t_poll, timebuf,
+ sizeof(timebuf)));
+ }
/* Show poll-interval timer thread. */
if (use_json) {
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index 8462a4fdf8..c7e1a18d28 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -152,7 +152,7 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
struct pim_rpf *rpg;
struct prefix_sg sg;
- rpg = RP(pim_ifp->pim, msg->im_dst);
+ rpg = pim_ifp ? RP(pim_ifp->pim, msg->im_dst) : NULL;
/*
* If the incoming interface is unknown OR
* the Interface type is SSM we don't need to
@@ -278,7 +278,7 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
pim_ifp = up->rpf.source_nexthop.interface->info;
- rpg = RP(pim_ifp->pim, sg.grp);
+ rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
if ((pim_rpf_addr_is_inaddr_none(rpg)) || (!pim_ifp)
|| (!(PIM_I_am_DR(pim_ifp)))) {
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/redhat/frr.spec.in b/redhat/frr.spec.in
index 064b78b260..e2be7050d7 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -10,41 +10,43 @@
#################### FRRouting (FRR) configure options #####################
# with-feature options
-%{!?with_pam: %global with_pam 0 }
-%{!?with_ospfclient: %global with_ospfclient 1 }
-%{!?with_ospfapi: %global with_ospfapi 1 }
-%{!?with_rtadv: %global with_rtadv 1 }
-%{!?with_ldpd: %global with_ldpd 1 }
-%{!?with_nhrpd: %global with_nhrpd 1 }
-%{!?with_eigrpd: %global with_eigrpd 1 }
%{!?with_babeld: %global with_babeld 1 }
-%{!?with_shared: %global with_shared 1 }
-%{!?with_multipath: %global with_multipath 256 }
-%{!?frr_user: %global frr_user frr }
-%{!?vty_group: %global vty_group frrvty }
-%{!?with_fpm: %global with_fpm 1 }
-%{!?with_watchfrr: %global with_watchfrr 1 }
%{!?with_bgp_vnc: %global with_bgp_vnc 0 }
+%{!?with_cumulus: %global with_cumulus 0 }
+%{!?with_eigrpd: %global with_eigrpd 1 }
+%{!?with_fpm: %global with_fpm 1 }
+%{!?with_ldpd: %global with_ldpd 1 }
+%{!?with_multipath: %global with_multipath 256 }
+%{!?with_nhrpd: %global with_nhrpd 1 }
+%{!?with_ospfapi: %global with_ospfapi 1 }
+%{!?with_ospfclient: %global with_ospfclient 1 }
+%{!?with_pam: %global with_pam 0 }
+%{!?with_pbrd: %global with_pbrd 1 }
%{!?with_pimd: %global with_pimd 1 }
%{!?with_rpki: %global with_rpki 0 }
-%{!?with_pbrd: %global with_pbrd 1 }
+%{!?with_rtadv: %global with_rtadv 1 }
+%{!?with_watchfrr: %global with_watchfrr 1 }
+
+# user and group
+%{!?frr_user: %global frr_user frr }
+%{!?vty_group: %global vty_group frrvty }
# path defines
-%define _sysconfdir /etc/frr
-%define _sbindir /usr/lib/frr
-%define zeb_src %{_builddir}/%{name}-%{frrversion}
-%define zeb_rh_src %{zeb_src}/redhat
-%define zeb_docs %{zeb_src}/doc
-%define frr_tools %{zeb_src}/tools
+%define configdir %{_sysconfdir}/%{name}
+%define _sbindir /usr/lib/frr
+%define zeb_src %{_builddir}/%{name}-%{frrversion}
+%define zeb_rh_src %{zeb_src}/redhat
+%define zeb_docs %{zeb_src}/doc
+%define frr_tools %{zeb_src}/tools
# defines for configure
-%define _localstatedir /var/run/frr
+%define rundir %{_localstatedir}/run/%{name}
# define for sphinx-build binary
%if 0%{?rhel} && 0%{?rhel} < 7
-%define sphinx sphinx-build2.7
+ %define sphinx sphinx-build2.7
%else
-%define sphinx sphinx-build
+ %define sphinx sphinx-build
%endif
############################################################################
@@ -83,55 +85,52 @@
%{!?frr_gid: %global frr_gid 92 }
%{!?vty_gid: %global vty_gid 85 }
-%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd
+%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd
%if %{with_ldpd}
-%define daemon_ldpd ldpd
+ %define daemon_ldpd ldpd
%else
-%define daemon_ldpd ""
+ %define daemon_ldpd ""
%endif
%if %{with_pimd}
-%define daemon_pimd pimd
+ %define daemon_pimd pimd
%else
-%define daemon_pimd ""
+ %define daemon_pimd ""
%endif
%if %{with_pbrd}
-%define daemon_pbrd pbrd
+ %define daemon_pbrd pbrd
%else
-%define daemon_pbrd ""
+ %define daemon_pbrd ""
%endif
%if %{with_nhrpd}
-%define daemon_nhrpd nhrpd
+ %define daemon_nhrpd nhrpd
%else
-%define daemon_nhrpd ""
+ %define daemon_nhrpd ""
%endif
%if %{with_eigrpd}
-%define daemon_eigrpd eigrpd
+ %define daemon_eigrpd eigrpd
%else
-%define daemon_eigrpd ""
+ %define daemon_eigrpd ""
%endif
%if %{with_babeld}
-%define daemon_babeld babeld
+ %define daemon_babeld babeld
%else
-%define daemon_babeld ""
+ %define daemon_babeld ""
%endif
%if %{with_watchfrr}
-%define daemon_watchfrr watchfrr
+ %define daemon_watchfrr watchfrr
%else
-%define daemon_watchfrr ""
+ %define daemon_watchfrr ""
%endif
%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd}
-# allow build dir to be kept
-%{!?keep_build: %global keep_build 0 }
-
#release sub-revision (the two digits after the CONFDATE)
%{!?release_rev: %global release_rev 01 }
@@ -143,19 +142,27 @@ License: GPLv2+
Group: System Environment/Daemons
Source0: https://github.com/FRRouting/frr/archive/%{name}-%{frrversion}.tar.gz
URL: https://www.frrouting.org
+Requires(pre): shadow-utils
Requires(preun): info
Requires(post): info
-BuildRequires: gcc patch libcap-devel
-BuildRequires: readline-devel ncurses-devel
-BuildRequires: json-c-devel bison >= 2.7 flex make
-BuildRequires: c-ares-devel texinfo
+BuildRequires: bison >= 2.7
+BuildRequires: c-ares-devel
+BuildRequires: flex
+BuildRequires: gcc
+BuildRequires: json-c-devel
+BuildRequires: libcap-devel
+BuildRequires: make
+BuildRequires: ncurses-devel
+BuildRequires: readline-devel
+BuildRequires: texinfo
%if 0%{?rhel} && 0%{?rhel} < 7
#python27-devel is available from ius community repo for RedHat/CentOS 6
-BuildRequires: python27-devel python27-sphinx
+BuildRequires: python27-devel
+BuildRequires: python27-sphinx
%else
-BuildRequires: python-devel >= 2.7 python-sphinx
+BuildRequires: python-devel >= 2.7
+BuildRequires: python-sphinx
%endif
-Requires: json-c initscripts
%if %{with_pam}
BuildRequires: pam-devel
%endif
@@ -163,7 +170,8 @@ BuildRequires: pam-devel
BuildRequires: librtr-devel >= 0.5
%endif
%if "%{initsystem}" == "systemd"
-BuildRequires: systemd systemd-devel
+BuildRequires: systemd
+BuildRequires: systemd-devel
Requires(post): systemd
Requires(preun): systemd
Requires(postun): systemd
@@ -172,12 +180,13 @@ Requires(post): chkconfig
Requires(preun): chkconfig
# Initscripts > 5.60 is required for IPv6 support
Requires(pre): initscripts >= 5.60
+Requires: initscripts
%endif
Provides: routingdaemon = %{version}-%{release}
-BuildRoot: %{_tmppath}/%{name}-%{version}-root
Obsoletes: gated mrt zebra frr-sysvinit
Conflicts: bird
+
%description
FRRouting is a free software that manages TCP/IP based routing
protocol. It takes multi-server and multi-thread approach to resolve
@@ -188,6 +197,7 @@ NHRP, Babel, PBR and EIGRP.
FRRouting is a fork of Quagga.
+
%package contrib
Summary: contrib tools for frr
Group: System Environment/Daemons
@@ -195,6 +205,7 @@ Group: System Environment/Daemons
%description contrib
Contributed/3rd party tools which may be of use with frr.
+
%package pythontools
Summary: python tools for frr
BuildRequires: python
@@ -204,6 +215,7 @@ Group: System Environment/Daemons
%description pythontools
Contributed python 2.7 tools which may be of use with frr.
+
%package devel
Summary: Header and object files for frr development
Group: System Environment/Daemons
@@ -213,8 +225,10 @@ Requires: %{name} = %{version}-%{release}
The frr-devel package contains the header and object files neccessary for
developing OSPF-API and frr applications.
+
%prep
-%setup -q -n frr-%{frrversion}
+%setup -q -n frr-%{frrversion}
+
%build
@@ -230,15 +244,11 @@ developing OSPF-API and frr applications.
%configure \
--sbindir=%{_sbindir} \
- --sysconfdir=%{_sysconfdir} \
- --libdir=%{_libdir} \
- --libexecdir=%{_libexecdir} \
- --localstatedir=%{_localstatedir} \
+ --sysconfdir=%{configdir} \
+ --localstatedir=%{rundir} \
+ --disable-static \
--disable-werror \
--enable-irdp \
-%if !%{with_shared}
- --disable-shared \
-%endif
%if %{with_multipath}
--enable-multipath=%{with_multipath} \
%endif
@@ -292,11 +302,11 @@ developing OSPF-API and frr applications.
--with-libpam \
%endif
%if 0%{?frr_user:1}
- --enable-user=%frr_user \
- --enable-group=%frr_user \
+ --enable-user=%{frr_user} \
+ --enable-group=%{frr_user} \
%endif
%if 0%{?vty_group:1}
- --enable-vty-group=%vty_group \
+ --enable-vty-group=%{vty_group} \
%endif
%if %{with_fpm}
--enable-fpm \
@@ -308,6 +318,9 @@ developing OSPF-API and frr applications.
%else
--disable-watchfrr \
%endif
+%if %{with_cumulus}
+ --enable-cumulus \
+%endif
%if %{with_bgp_vnc}
--enable-bgp-vnc \
%else
@@ -318,9 +331,10 @@ developing OSPF-API and frr applications.
--enable-systemd \
%endif
%if %{with_rpki}
- --enable-rpki \
+ --enable-rpki
+%else
+ --disable-rpki
%endif
- --enable-poll
make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" SPHINXBUILD=%{sphinx}
@@ -328,9 +342,10 @@ pushd doc
make SPHINXBUILD=%{sphinx} info
popd
+
%install
-mkdir -p %{buildroot}/etc/{frr,sysconfig,logrotate.d,pam.d,default} \
- %{buildroot}/var/log/frr %{buildroot}%{_infodir}
+mkdir -p %{buildroot}%{_sysconfdir}/{frr,sysconfig,logrotate.d,pam.d,default} \
+ %{buildroot}%{_localstatedir}/log/frr %{buildroot}%{_infodir}
make DESTDIR=%{buildroot} INSTALL="install -p" CP="cp -p" SPHINXBUILD=%{sphinx} install
# Remove this file, as it is uninstalled and causes errors when building on RH9
@@ -339,53 +354,47 @@ rm -rf %{buildroot}/usr/share/info/dir
# Remove debian init script if it was installed
rm -f %{buildroot}%{_sbindir}/frr
-# kill bogus libtool files for modules
-rm -f %{buildroot}%{_libdir}/frr/modules/*.la
+# kill bogus libtool files
+rm -vf %{buildroot}%{_libdir}/frr/modules/*.la
+rm -vf %{buildroot}%{_libdir}/*.la
# install /etc sources
%if "%{initsystem}" == "systemd"
mkdir -p %{buildroot}%{_unitdir}
-install -m644 %{zeb_rh_src}/frr.service \
- %{buildroot}%{_unitdir}/frr.service
-install %{zeb_rh_src}/frr.init \
- %{buildroot}%{_sbindir}/frr
+install -m644 %{zeb_rh_src}/frr.service %{buildroot}%{_unitdir}/frr.service
+install %{zeb_rh_src}/frr.init %{buildroot}%{_sbindir}/frr
%else
-mkdir -p %{buildroot}/etc/rc.d/init.d
-install %{zeb_rh_src}/frr.init \
- %{buildroot}%{_sbindir}/frr
-ln -s %{_sbindir}/frr \
- %{buildroot}/etc/rc.d/init.d/frr
+mkdir -p %{buildroot}%{_initddir}
+install %{zeb_rh_src}/frr.init %{buildroot}%{_sbindir}/frr
+ln -s %{_sbindir}/frr %{buildroot}%{_initddir}/frr
%endif
-install %{zeb_rh_src}/daemons %{buildroot}/etc/frr
-install -m644 %{zeb_rh_src}/frr.pam \
- %{buildroot}/etc/pam.d/frr
-install -m644 %{zeb_rh_src}/frr.logrotate \
- %{buildroot}/etc/logrotate.d/frr
-install -d -m750 %{buildroot}/var/run/frr
+install %{zeb_rh_src}/daemons %{buildroot}%{_sysconfdir}/frr
+install -m644 %{zeb_rh_src}/frr.pam %{buildroot}%{_sysconfdir}/pam.d/frr
+install -m644 %{zeb_rh_src}/frr.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/frr
+install -d -m750 %{buildroot}%{rundir}
+
%pre
# add vty_group
%if 0%{?vty_group:1}
-if getent group %vty_group > /dev/null ; then : ; else \
- /usr/sbin/groupadd -r -g %vty_gid %vty_group > /dev/null || : ; fi
+ getent group %{vty_group} >/dev/null || groupadd -r -g %{vty_gid} %{vty_group}
%endif
# add frr user and group
%if 0%{?frr_user:1}
-# Ensure that frr_gid gets correctly allocated
-if getent group %frr_user >/dev/null; then : ; else \
- /usr/sbin/groupadd -g %frr_gid %frr_user > /dev/null || : ; \
-fi
-if getent passwd %frr_user >/dev/null ; then : ; else \
- /usr/sbin/useradd -u %frr_uid -g %frr_gid \
- -M -r -s /sbin/nologin -c "FRRouting suite" \
- -d %_localstatedir %frr_user 2> /dev/null || : ; \
-fi
-%if 0%{?vty_group:1}
-/usr/sbin/usermod -a -G %vty_group %frr_user
-%endif
+ # Ensure that frr_gid gets correctly allocated
+ getent group %{frr_user} >/dev/null || groupadd -g %{frr_gid} %{frr_user}
+ getent passwd %{frr_user} >/dev/null || \
+ useradd -r -u %{frr_uid} -g %{frr_user} \
+ -s /sbin/nologin -c "FRRouting suite" \
+ -d %{rundir} %{frr_user}
+
+ %if 0%{?vty_group:1}
+ usermod -a -G %{vty_group} %{frr_user}
+ %endif
%endif
+exit 0
%post
@@ -395,9 +404,9 @@ fi
zebra_spec_add_service ()
{
# Add port /etc/services entry if it isn't already there
- if [ -f /etc/services ] && \
- ! %__sed -e 's/#.*$//' /etc/services | %__grep -wq $1 ; then
- echo "$1 $2 # $3" >> /etc/services
+ if [ -f %{_sysconfdir}/services ] && \
+ ! %__sed -e 's/#.*$//' %{_sysconfdir}/services | %__grep -wq $1 ; then
+ echo "$1 $2 # $3" >> %{_sysconfdir}/services
fi
}
@@ -408,86 +417,87 @@ zebra_spec_add_service ripngd 2603/tcp "RIPngd vty"
zebra_spec_add_service ospfd 2604/tcp "OSPFd vty"
zebra_spec_add_service bgpd 2605/tcp "BGPd vty"
zebra_spec_add_service ospf6d 2606/tcp "OSPF6d vty"
+zebra_spec_add_service isisd 2608/tcp "ISISd vty"
%if %{with_ospfapi}
-zebra_spec_add_service ospfapi 2607/tcp "OSPF-API"
+ zebra_spec_add_service ospfapi 2607/tcp "OSPF-API"
%endif
-zebra_spec_add_service isisd 2608/tcp "ISISd vty"
%if %{with_babeld}
-zebra_spec_add_service babeld 2609/tcp "BABELd vty"
+ zebra_spec_add_service babeld 2609/tcp "BABELd vty"
%endif
%if %{with_nhrpd}
-zebra_spec_add_service nhrpd 2610/tcp "NHRPd vty"
+ zebra_spec_add_service nhrpd 2610/tcp "NHRPd vty"
%endif
%if %{with_pimd}
-zebra_spec_add_service pimd 2611/tcp "PIMd vty"
+ zebra_spec_add_service pimd 2611/tcp "PIMd vty"
%endif
%if %{with_pbrd}
-zebra_spec_add_service pbrd 2615/tcp "PBRd vty"
+ zebra_spec_add_service pbrd 2615/tcp "PBRd vty"
%endif
%if %{with_ldpd}
-zebra_spec_add_service ldpd 2612/tcp "LDPd vty"
+ zebra_spec_add_service ldpd 2612/tcp "LDPd vty"
%endif
%if %{with_eigrpd}
-zebra_spec_add_service eigrpd 2613/tcp "EIGRPd vty"
+ zebra_spec_add_service eigrpd 2613/tcp "EIGRPd vty"
%endif
%if "%{initsystem}" == "systemd"
-for daemon in %all_daemons ; do
- %systemd_post frr.service
-done
+ for daemon in %all_daemons ; do
+ %systemd_post frr.service
+ done
%else
-/sbin/chkconfig --add frr
+ /sbin/chkconfig --add frr
%endif
# Fix bad path in previous config files
# Config files won't get replaced by default, so we do this ugly hack to fix it
-%__sed -i 's|/etc/init.d/|%{_sbindir}/|g' %{_sysconfdir}/daemons 2> /dev/null || true
+%__sed -i 's|/etc/init.d/|%{_sbindir}/|g' %{configdir}/daemons 2> /dev/null || true
# With systemd, watchfrr is mandatory. Fix config to make sure it's enabled if
# we install or upgrade to a frr built with systemd
%if "%{initsystem}" == "systemd"
- %__sed -i 's|watchfrr_enable=no|watchfrr_enable=yes|g' %{_sysconfdir}/daemons 2> /dev/null || true
+ %__sed -i 's|watchfrr_enable=no|watchfrr_enable=yes|g' %{configdir}/daemons 2> /dev/null || true
%endif
/sbin/install-info %{_infodir}/frr.info.gz %{_infodir}/dir
# Create dummy files if they don't exist so basic functions can be used.
-if [ ! -e %{_sysconfdir}/zebra.conf ]; then
- echo "hostname `hostname`" > %{_sysconfdir}/zebra.conf
+if [ ! -e %{configdir}/zebra.conf ]; then
+ echo "hostname `hostname`" > %{configdir}/zebra.conf
%if 0%{?frr_user:1}
- chown %frr_user:%frr_user %{_sysconfdir}/zebra.conf*
+ chown %{frr_user}:%{frr_user} %{configdir}/zebra.conf*
%endif
- chmod 640 %{_sysconfdir}/zebra.conf*
+ chmod 640 %{configdir}/zebra.conf*
fi
for daemon in %{all_daemons} ; do
if [ x"${daemon}" != x"" ] ; then
- if [ ! -e %{_sysconfdir}/${daemon}.conf ]; then
- touch %{_sysconfdir}/${daemon}.conf
+ if [ ! -e %{configdir}/${daemon}.conf ]; then
+ touch %{configdir}/${daemon}.conf
%if 0%{?frr_user:1}
- chown %frr_user:%frr_user %{_sysconfdir}/${daemon}.conf*
+ chown %{frr_user}:%{frr_user} %{configdir}/${daemon}.conf*
%endif
fi
fi
done
%if 0%{?frr_user:1}
- chown %frr_user:%frr_user %{_sysconfdir}/daemons
+ chown %{frr_user}:%{frr_user} %{configdir}/daemons
%endif
%if %{with_watchfrr}
# No config for watchfrr - this is part of /etc/sysconfig/frr
- rm -f %{_sysconfdir}/watchfrr.*
+ rm -f %{configdir}/watchfrr.*
%endif
-if [ ! -e %{_sysconfdir}/vtysh.conf ]; then
- touch %{_sysconfdir}/vtysh.conf
- chmod 640 %{_sysconfdir}/vtysh.conf
+if [ ! -e %{configdir}/vtysh.conf ]; then
+ touch %{configdir}/vtysh.conf
+ chmod 640 %{configdir}/vtysh.conf
%if 0%{?frr_user:1}
-%if 0%{?vty_group:1}
- chown %{frr_user}:%{vty_group} %{_sysconfdir}/vtysh.conf*
-%endif
+ %if 0%{?vty_group:1}
+ chown %{frr_user}:%{vty_group} %{configdir}/vtysh.conf*
+ %endif
%endif
fi
+
%postun
if [ "$1" -ge 1 ]; then
#
@@ -502,11 +512,12 @@ if [ "$1" -ge 1 ]; then
##
## init.d Version
##
- /etc/rc.d/init.d/frr restart >/dev/null 2>&1
+ service frr restart >/dev/null 2>&1
%endif
:
fi
+
%preun
%if "%{initsystem}" == "systemd"
##
@@ -520,33 +531,28 @@ fi
## init.d Version
##
if [ $1 -eq 0 ] ; then
- /etc/rc.d/init.d/frr stop >/dev/null 2>&1
+ service frr stop >/dev/null 2>&1
/sbin/chkconfig --del frr
fi
%endif
/sbin/install-info --delete %{_infodir}/frr.info.gz %{_infodir}/dir
-%clean
-%if !0%{?keep_build:1}
-rm -rf %{buildroot}
-%endif
%files
-%defattr(-,root,root)
%doc */*.sample* AUTHORS COPYING
%doc doc/mpls
%doc ChangeLog NEWS README
%if 0%{?frr_user:1}
-%dir %attr(751,%frr_user,%frr_user) %{_sysconfdir}
-%dir %attr(750,%frr_user,%frr_user) /var/log/frr
-%dir %attr(751,%frr_user,%frr_user) /var/run/frr
+ %dir %attr(751,%{frr_user},%{frr_user}) %{configdir}
+ %dir %attr(750,%{frr_user},%{frr_user}) %{_localstatedir}/log/frr
+ %dir %attr(751,%{frr_user},%{frr_user}) %{rundir}
%else
-%dir %attr(750,root,root) %{_sysconfdir}
-%dir %attr(750,root,root) /var/log/frr
-%dir %attr(750,root,root) /var/run/frr
+ %dir %attr(750,root,root) %{configdir}
+ %dir %attr(750,root,root) %{_localstatedir}/log/frr
+ %dir %attr(750,root,root) %{rundir}
%endif
%if 0%{?vty_group:1}
-%attr(750,%frr_user,%vty_group) %{_sysconfdir}/vtysh.conf.sample
+ %attr(750,%{frr_user},%{vty_group}) %{configdir}/vtysh.conf.sample
%endif
%{_infodir}/frr.info.gz
%{_mandir}/man*/*
@@ -579,63 +585,60 @@ rm -rf %{buildroot}
%if %{with_babeld}
%{_sbindir}/babeld
%endif
-%if %{with_shared}
-%{_libdir}/lib*.so
%{_libdir}/lib*.so.0
-%attr(755,root,root) %{_libdir}/lib*.so.0.*
-%endif
+%{_libdir}/lib*.so.0.*
%if %{with_fpm}
-%attr(755,root,root) %{_libdir}/frr/modules/zebra_fpm.so
+ %{_libdir}/frr/modules/zebra_fpm.so
%endif
%if %{with_rpki}
-%attr(755,root,root) %{_libdir}/frr/modules/bgpd_rpki.so
+ %{_libdir}/frr/modules/bgpd_rpki.so
%endif
-%attr(755,root,root) %{_libdir}/frr/modules/zebra_irdp.so
+%{_libdir}/frr/modules/zebra_irdp.so
%{_bindir}/*
-%config(noreplace) /etc/frr/[!v]*.conf*
-%config(noreplace) %attr(750,%frr_user,%frr_user) /etc/frr/daemons
+%config(noreplace) %{configdir}/[!v]*.conf*
+%config(noreplace) %attr(750,%{frr_user},%{frr_user}) %{configdir}/daemons
%if "%{initsystem}" == "systemd"
%{_unitdir}/frr.service
%else
- /etc/rc.d/init.d/frr
+ %{_initddir}/frr
%endif
%{_sbindir}/frr
-%config(noreplace) /etc/pam.d/frr
-%config(noreplace) /etc/logrotate.d/frr
+%config(noreplace) %{_sysconfdir}/pam.d/frr
+%config(noreplace) %{_sysconfdir}/logrotate.d/frr
%{_sbindir}/frr-reload
+
%files contrib
-%defattr(-,root,root)
%doc tools
+
%files pythontools
-%defattr(-,root,root)
%{_sbindir}/frr-reload.py
%{_sbindir}/frr-reload.pyc
%{_sbindir}/frr-reload.pyo
+
%files devel
-%defattr(-,root,root)
+%{_libdir}/lib*.so
%if %{with_ospfclient}
-%{_sbindir}/ospfclient
-%endif
-%{_libdir}/*.a
-%{_libdir}/*.la
-%dir %attr(755,root,root) %{_includedir}/%{name}
-%{_includedir}/%name/*.h
-%dir %attr(755,root,root) %{_includedir}/%{name}/ospfd
-%{_includedir}/%name/ospfd/*.h
+ %{_sbindir}/ospfclient
+%endif
+%dir %{_includedir}/%{name}
+%{_includedir}/%{name}/*.h
+%dir %{_includedir}/%{name}/ospfd
+%{_includedir}/%{name}/ospfd/*.h
%if %{with_ospfapi}
-%dir %attr(755,root,root) %{_includedir}/%{name}/ospfapi
-%{_includedir}/%name/ospfapi/*.h
+ %dir %{_includedir}/%{name}/ospfapi
+ %{_includedir}/%{name}/ospfapi/*.h
%endif
%if %{with_eigrpd}
-%dir %attr(755,root,root) %{_includedir}/%{name}/eigrpd
-%{_includedir}/%name/eigrpd/*.h
+ %dir %{_includedir}/%{name}/eigrpd
+ %{_includedir}/%{name}/eigrpd/*.h
%endif
+
%changelog
-* Sun May 20 2018 Martin Winter <mwinter@opensourcerouting.org> - %{version}
+* Sun May 20 2018 Martin Winter <mwinter@opensourcerouting.org>
- Fixed RPKI RPM build
* Sun Mar 4 2018 Martin Winter <mwinter@opensourcerouting.org>
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/ripngd/ripngd.c b/ripngd/ripngd.c
index 840157516f..565e151c53 100644
--- a/ripngd/ripngd.c
+++ b/ripngd/ripngd.c
@@ -1516,9 +1516,10 @@ int ripng_write_rte(int num, struct stream *s, struct prefix_ipv6 *p,
}
/* Write routing table entry. */
- if (!nexthop)
+ if (!nexthop) {
+ assert(p);
stream_write(s, (uint8_t *)&p->prefix, sizeof(struct in6_addr));
- else
+ } else
stream_write(s, (uint8_t *)nexthop, sizeof(struct in6_addr));
stream_putw(s, tag);
if (p)
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 0697cd8b75..b56eaa899f 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -3357,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[] = {
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 7334c8094a..d9c6631845 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -545,7 +545,6 @@ static void netlink_parse_extended_ack(struct nlmsghdr *h)
if (off > h->nlmsg_len) {
zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS\n");
- off = 0;
} else if (!(h->nlmsg_flags & NLM_F_CAPPED)) {
/*
* Header of failed message
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index be53b74b3f..1fee675cbf 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -274,7 +274,7 @@ void zebra_redistribute_add(ZAPI_HANDLER_ARGS)
__func__, zebra_route_string(client->proto), afi,
zebra_route_string(type), zvrf_id(zvrf), instance);
- if (afi == 0 || afi > AFI_MAX) {
+ if (afi == 0 || afi >= AFI_MAX) {
zlog_warn("%s: Specified afi %d does not exist",
__PRETTY_FUNCTION__, afi);
return;
@@ -320,7 +320,7 @@ void zebra_redistribute_delete(ZAPI_HANDLER_ARGS)
STREAM_GETC(msg, type);
STREAM_GETW(msg, instance);
- if (afi == 0 || afi > AFI_MAX) {
+ if (afi == 0 || afi >= AFI_MAX) {
zlog_warn("%s: Specified afi %d does not exist",
__PRETTY_FUNCTION__, afi);
return;
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_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/zebra_vrf.c b/zebra/zebra_vrf.c
index d443f725b0..3c21c3c1e5 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -134,14 +134,6 @@ static int zebra_vrf_enable(struct vrf *vrf)
zvrf->import_check_table[afi] = table;
}
- static_fixup_vrf_ids(zvrf);
-
- /*
- * We may have static routes that are now possible to
- * insert into the appropriate tables
- */
- static_config_install_delayed_routes(zvrf);
-
/* Kick off any VxLAN-EVPN processing. */
zebra_vxlan_vrf_enable(zvrf);
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 14e0db40bf..434a1507ae 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 */
@@ -618,14 +618,6 @@ static int zserv_handle_client_close(struct thread *thread)
{
struct zserv *client = THREAD_ARG(thread);
- /*
- * Ensure these have been nulled. This does not equate to the
- * associated task(s) being scheduled or unscheduled on the client
- * pthread's threadmaster.
- */
- assert(!client->t_read);
- assert(!client->t_write);
-
/* synchronously stop thread */
frr_pthread_stop(client->pthread, NULL);
@@ -939,6 +931,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;
}