summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_pbr.c66
-rw-r--r--bgpd/bgp_pbr.h3
-rw-r--r--bgpd/bgp_zebra.c2
3 files changed, 54 insertions, 17 deletions
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index 0a54183db7..47f12d23d4 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -255,8 +255,7 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
* - combination src/dst => drop
* - combination srcport + @IP
*/
- if (api->match_packet_length_num
- || api->match_dscp_num || api->match_tcpflags_num) {
+ if (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.");
@@ -326,6 +325,12 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
"too complex. ignoring.");
return 0;
}
+ if (!bgp_pbr_extract(api->packet_length, api->match_packet_length_num, NULL)) {
+ if (BGP_DEBUG(pbr, PBR))
+ zlog_debug("BGP: match packet length operations:"
+ "too complex. ignoring.");
+ return 0;
+ }
/* no combinations with both src_port and dst_port
* or port with src_port and dst_port
*/
@@ -568,6 +573,8 @@ 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);
return jhash_1word(pbm->type, key);
}
@@ -590,6 +597,12 @@ 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;
+
return 1;
}
@@ -1009,6 +1022,7 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
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)
{
@@ -1052,6 +1066,11 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
}
temp2.proto = protocol;
+ if (pkt_len)
+ temp.pkt_len_min = pkt_len->min_port;
+ if (pkt_len && pkt_len->max_port)
+ temp.pkt_len_max = pkt_len->max_port;
+
if (src == NULL || dst == NULL) {
if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
temp.type = IPSET_NET_PORT;
@@ -1095,6 +1114,7 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
struct nexthop *nh,
float *rate,
uint8_t protocol,
+ struct bgp_pbr_range_port *pkt_len,
struct bgp_pbr_range_port *src_port,
struct bgp_pbr_range_port *dst_port)
{
@@ -1161,6 +1181,11 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
temp.flags |= MATCH_PORT_SRC_RANGE_SET;
if (dst_port && dst_port->max_port)
temp.flags |= MATCH_PORT_DST_RANGE_SET;
+ if (pkt_len)
+ temp.pkt_len_min = pkt_len->min_port;
+ if (pkt_len && pkt_len->max_port)
+ temp.pkt_len_max = pkt_len->max_port;
+
temp.action = bpa;
bpm = hash_get(bgp->pbr_match_hash, &temp,
bgp_pbr_match_alloc_intern);
@@ -1298,6 +1323,7 @@ static void bgp_pbr_enumerate_action_src_dst(struct bgp_pbr_match_val src[],
struct prefix *src_address,
struct prefix *dst_address,
uint8_t proto,
+ struct bgp_pbr_range_port *pkt_len,
struct bgp *bgp,
struct bgp_info *binfo,
bool add,
@@ -1321,7 +1347,7 @@ static void bgp_pbr_enumerate_action_src_dst(struct bgp_pbr_match_val src[],
vrf_id, src_address,
dst_address,
nh, rate, proto,
- &srcp, &dstp);
+ pkt_len, &srcp, &dstp);
else
bgp_pbr_policyroute_remove_from_zebra(
bgp,
@@ -1329,7 +1355,7 @@ static void bgp_pbr_enumerate_action_src_dst(struct bgp_pbr_match_val src[],
vrf_id,
src_address,
dst_address,
- proto,
+ proto, pkt_len,
&srcp, &dstp);
return;
}
@@ -1372,7 +1398,7 @@ static void bgp_pbr_enumerate_action_src_dst(struct bgp_pbr_match_val src[],
vrf_id, src_address,
dst_address,
nh, rate, proto,
- &srcp, &dstp);
+ pkt_len, &srcp, &dstp);
else
bgp_pbr_policyroute_remove_from_zebra(
bgp,
@@ -1381,6 +1407,7 @@ static void bgp_pbr_enumerate_action_src_dst(struct bgp_pbr_match_val src[],
src_address,
dst_address,
proto,
+ pkt_len,
&srcp, &dstp);
}
}
@@ -1395,6 +1422,7 @@ static void bgp_pbr_enumerate_action_src_dst(struct bgp_pbr_match_val src[],
vrf_id, src_address,
dst_address,
nh, rate, proto,
+ pkt_len,
&srcp, &dstp);
else
bgp_pbr_policyroute_remove_from_zebra(
@@ -1403,7 +1431,7 @@ static void bgp_pbr_enumerate_action_src_dst(struct bgp_pbr_match_val src[],
vrf_id,
src_address,
dst_address,
- proto,
+ proto, pkt_len,
&srcp, &dstp);
}
@@ -1419,7 +1447,7 @@ static void bgp_pbr_enumerate_action_src_dst(struct bgp_pbr_match_val src[],
vrf_id, src_address,
dst_address,
nh, rate, proto,
- &srcp, &dstp);
+ pkt_len, &srcp, &dstp);
else
bgp_pbr_policyroute_remove_from_zebra(
bgp,
@@ -1427,7 +1455,7 @@ static void bgp_pbr_enumerate_action_src_dst(struct bgp_pbr_match_val src[],
vrf_id,
src_address,
dst_address,
- proto,
+ proto, pkt_len,
&srcp, &dstp);
break;
}
@@ -1447,6 +1475,7 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
uint8_t proto = 0;
struct bgp_pbr_range_port *srcp = NULL, *dstp = NULL;
struct bgp_pbr_range_port range, range_icmp_code;
+ struct bgp_pbr_range_port pkt_len;
bool enum_icmp = false;
memset(&nh, 0, sizeof(struct nexthop));
@@ -1503,14 +1532,17 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
dstp = &range_icmp_code;
}
}
-
+ if (api->match_packet_length_num >= 1)
+ bgp_pbr_extract(api->packet_length,
+ api->match_packet_length_num,
+ &pkt_len);
if (!add) {
if (enum_icmp) {
return bgp_pbr_enumerate_action_src_dst(api->icmp_type,
api->match_icmp_type_num,
api->icmp_code,
api->match_icmp_code_num,
- src, dst, proto,
+ src, dst, proto, &pkt_len,
bgp, binfo, add,
api->vrf_id, NULL, NULL);
}
@@ -1518,7 +1550,7 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
binfo,
api->vrf_id,
src, dst,
- proto,
+ proto, &pkt_len,
srcp, dstp);
}
/* no action for add = true */
@@ -1534,14 +1566,14 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
api->match_icmp_type_num,
api->icmp_code,
api->match_icmp_code_num,
- src, dst, proto,
+ src, dst, proto, &pkt_len,
bgp, binfo, add,
api->vrf_id, &nh, &rate);
else
bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
api->vrf_id, src, dst,
&nh, &rate, proto,
- srcp, dstp);
+ &pkt_len, srcp, dstp);
} else {
/* update rate. can be reentrant */
rate = api->actions[i].u.r.rate;
@@ -1586,7 +1618,7 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
api->match_icmp_type_num,
api->icmp_code,
api->match_icmp_code_num,
- src, dst, proto,
+ src, dst, proto, &pkt_len,
bgp, binfo, add,
api->vrf_id, &nh, &rate);
else
@@ -1594,7 +1626,7 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
api->vrf_id,
src, dst,
&nh, &rate, proto,
- srcp, dstp);
+ &pkt_len, srcp, dstp);
/* XXX combination with REDIRECT_VRF
* + REDIRECT_NH_IP not done
*/
@@ -1608,7 +1640,7 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
api->match_icmp_type_num,
api->icmp_code,
api->match_icmp_code_num,
- src, dst, proto,
+ src, dst, proto, &pkt_len,
bgp, binfo, add,
api->vrf_id, &nh, &rate);
else
@@ -1616,7 +1648,7 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
api->vrf_id,
src, dst,
&nh, &rate, proto,
- srcp, dstp);
+ &pkt_len, srcp, dstp);
continue_loop = 0;
break;
case ACTION_MARKING:
diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h
index e869d0106d..9d578a183b 100644
--- a/bgpd/bgp_pbr.h
+++ b/bgpd/bgp_pbr.h
@@ -185,6 +185,9 @@ struct bgp_pbr_match {
#define MATCH_PORT_DST_RANGE_SET (1 << 5)
uint32_t flags;
+ uint16_t pkt_len_min;
+ uint16_t pkt_len_max;
+
vrf_id_t vrf_id;
/* unique identifier for ipset create transaction
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 2d808a6ffb..8cf7b29396 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -2219,6 +2219,8 @@ 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);
}
/* BGP has established connection with Zebra. */