diff options
| author | Siger Yang <siger.yang@outlook.com> | 2022-09-11 14:56:12 +0800 | 
|---|---|---|
| committer | Siger Yang <siger.yang@outlook.com> | 2022-11-22 22:35:35 +0800 | 
| commit | 04bc334e7a2e08229000d208f3a5df970172dcd0 (patch) | |
| tree | 0df3fa550aaaaa266be686a26e50924ff6b29864 /sharpd | |
| parent | dfacea4ae7001346ea5e21fce485db5255e809f6 (diff) | |
sharpd: traffic control PoC
This commit adds a command to sharpd to validate the proof of concept for
traffic control on specific interface with specific filters.
Signed-off-by: Siger Yang <siger.yang@outlook.com>
Diffstat (limited to 'sharpd')
| -rw-r--r-- | sharpd/sharp_vty.c | 61 | ||||
| -rw-r--r-- | sharpd/sharp_zebra.c | 122 | ||||
| -rw-r--r-- | sharpd/sharp_zebra.h | 5 | 
3 files changed, 153 insertions, 35 deletions
diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 164a0fd218..0cedd2bafc 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -32,6 +32,7 @@  #include "linklist.h"  #include "link_state.h"  #include "cspf.h" +#include "tc.h"  #include "sharpd/sharp_globals.h"  #include "sharpd/sharp_zebra.h" @@ -1339,6 +1340,64 @@ DEFPY (no_sharp_interface_protodown,  	return CMD_SUCCESS;  } +DEFPY (tc_filter_rate, +       tc_filter_rate_cmd, +       "sharp tc dev IFNAME$ifname \ +        source <A.B.C.D/M|X:X::X:X/M>$src \ +        destination <A.B.C.D/M|X:X::X:X/M>$dst \ +        ip-protocol <tcp|udp>$ip_proto \ +        src-port (1-65535)$src_port \ +        dst-port (1-65535)$dst_port \ +        rate RATE$ratestr", +       SHARP_STR +       "Traffic control\n" +       "TC interface (for qdisc, class, filter)\n" +       "TC interface name\n" +       "TC filter source\n" +       "TC filter source IPv4 prefix\n" +       "TC filter source IPv6 prefix\n" +       "TC filter destination\n" +       "TC filter destination IPv4 prefix\n" +       "TC filter destination IPv6 prefix\n" +       "TC filter IP protocol\n" +       "TC filter IP protocol TCP\n" +       "TC filter IP protocol UDP\n" +       "TC filter source port\n" +       "TC filter source port\n" +       "TC filter destination port\n" +       "TC filter destination port\n" +       "TC rate\n" +       "TC rate number (bits/s) or rate string (suffixed with Bps or bit)\n") +{ +	struct interface *ifp; +	struct protoent *p; +	uint64_t rate; + +	ifp = if_lookup_vrf_all(ifname); + +	if (!ifp) { +		vty_out(vty, "%% Can't find interface %s\n", ifname); +		return CMD_WARNING; +	} + +	p = getprotobyname(ip_proto); +	if (!p) { +		vty_out(vty, "Unable to convert %s to proto id\n", ip_proto); +		return CMD_WARNING; +	} + +	if (tc_getrate(ratestr, &rate) != 0) { +		vty_out(vty, "Unable to convert %s to rate\n", ratestr); +		return CMD_WARNING; +	} + +	if (sharp_zebra_send_tc_filter_rate(ifp, src, dst, p->p_proto, src_port, +					    dst_port, rate) != 0) +		return CMD_WARNING; + +	return CMD_SUCCESS; +} +  void sharp_vty_init(void)  {  	install_element(ENABLE_NODE, &install_routes_data_dump_cmd); @@ -1374,5 +1433,7 @@ void sharp_vty_init(void)  	install_element(ENABLE_NODE, &sharp_interface_protodown_cmd);  	install_element(ENABLE_NODE, &no_sharp_interface_protodown_cmd); +	install_element(ENABLE_NODE, &tc_filter_rate_cmd); +  	return;  } diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 9d343576d6..bf5b98544e 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -31,6 +31,7 @@  #include "nexthop.h"  #include "nexthop_group.h"  #include "link_state.h" +#include "tc.h"  #include "sharp_globals.h"  #include "sharp_nht.h" @@ -302,8 +303,8 @@ static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance,  		memcpy(api.opaque.data, opaque, api.opaque.length);  	} -	if (zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api) -	    == ZCLIENT_SEND_BUFFERED) +	if (zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api) == +	    ZCLIENT_SEND_BUFFERED)  		return true;  	else  		return false; @@ -326,8 +327,8 @@ static bool route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance)  	api.instance = instance;  	memcpy(&api.prefix, p, sizeof(*p)); -	if (zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api) -	    == ZCLIENT_SEND_BUFFERED) +	if (zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api) == +	    ZCLIENT_SEND_BUFFERED)  		return true;  	else  		return false; @@ -360,7 +361,7 @@ static void sharp_install_routes_restart(struct prefix *p, uint32_t count,  		if (buffered) {  			wb.p = *p; -			wb.count = i+1; +			wb.count = i + 1;  			wb.routes = routes;  			wb.vrf_id = vrf_id;  			wb.instance = instance; @@ -447,17 +448,16 @@ static void handle_repeated(bool installed)  	if (installed) {  		sg.r.removed_routes = 0; -		sharp_remove_routes_helper(&p, sg.r.vrf_id, -					   sg.r.inst, sg.r.total_routes); +		sharp_remove_routes_helper(&p, sg.r.vrf_id, sg.r.inst, +					   sg.r.total_routes);  	}  	if (!installed) {  		sg.r.installed_routes = 0; -		sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst, -					    sg.r.nhgid, &sg.r.nhop_group, -					    &sg.r.backup_nhop_group, -					    sg.r.total_routes, sg.r.flags, -					    sg.r.opaque); +		sharp_install_routes_helper( +			&p, sg.r.vrf_id, sg.r.inst, sg.r.nhgid, +			&sg.r.nhop_group, &sg.r.backup_nhop_group, +			sg.r.total_routes, sg.r.flags, sg.r.opaque);  	}  } @@ -467,8 +467,7 @@ static void sharp_zclient_buffer_ready(void)  	case SHARP_INSTALL_ROUTES_RESTART:  		sharp_install_routes_restart(  			&wb.p, wb.count, wb.vrf_id, wb.instance, wb.nhgid, -			wb.nhg, wb.backup_nhg, wb.routes, wb.flags, -			wb.opaque); +			wb.nhg, wb.backup_nhg, wb.routes, wb.flags, wb.opaque);  		return;  	case SHARP_DELETE_ROUTES_RESTART:  		sharp_remove_routes_restart(&wb.p, wb.count, wb.vrf_id, @@ -484,8 +483,8 @@ static int route_notify_owner(ZAPI_CALLBACK_ARGS)  	enum zapi_route_notify_owner note;  	uint32_t table; -	if (!zapi_route_notify_decode(zclient->ibuf, &p, &table, ¬e, -				      NULL, NULL)) +	if (!zapi_route_notify_decode(zclient->ibuf, &p, &table, ¬e, NULL, +				      NULL))  		return -1;  	switch (note) { @@ -574,8 +573,8 @@ void nhg_add(uint32_t id, const struct nexthop_group *nhg,  	}  	if (api_nhg.nexthop_num == 0) { -		zlog_debug("%s: nhg %u not sent: no valid nexthops", -			   __func__, id); +		zlog_debug("%s: nhg %u not sent: no valid nexthops", __func__, +			   id);  		is_valid = false;  		goto done;  	} @@ -635,8 +634,7 @@ void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import,  		command = ZEBRA_NEXTHOP_UNREGISTER;  	if (zclient_send_rnh(zclient, command, p, SAFI_UNICAST, connected, -			     false, vrf_id) -	    == ZCLIENT_SEND_FAILURE) +			     false, vrf_id) == ZCLIENT_SEND_FAILURE)  		zlog_warn("%s: Failure to send nexthop to zebra", __func__);  } @@ -645,8 +643,7 @@ static int sharp_debug_nexthops(struct zapi_route *api)  	int i;  	if (api->nexthop_num == 0) { -		zlog_debug( -			"        Not installed"); +		zlog_debug("        Not installed");  		return 0;  	} @@ -711,8 +708,8 @@ static int sharp_redistribute_route(ZAPI_CALLBACK_ARGS)  		zlog_warn("%s: Decode of redistribute failed: %d", __func__,  			  ZEBRA_REDISTRIBUTE_ROUTE_ADD); -	zlog_debug("%s: %pFX (%s)", zserv_command_string(cmd), -		   &api.prefix, zebra_route_string(api.type)); +	zlog_debug("%s: %pFX (%s)", zserv_command_string(cmd), &api.prefix, +		   zebra_route_string(api.type));  	sharp_debug_nexthops(&api); @@ -784,9 +781,9 @@ int sharp_zclient_delete(uint32_t session_id)  	return 0;  } -static const char *const type2txt[] = { "Generic", "Vertex", "Edge", "Subnet" }; -static const char *const status2txt[] = { "Unknown", "New", "Update", -					  "Delete", "Sync", "Orphan"}; +static const char *const type2txt[] = {"Generic", "Vertex", "Edge", "Subnet"}; +static const char *const status2txt[] = {"Unknown", "New",  "Update", +					 "Delete",  "Sync", "Orphan"};  /* Handler for opaque messages */  static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS)  { @@ -809,8 +806,7 @@ static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS)  				   status2txt[lse->status],  				   type2txt[lse->type]);  			lse->status = SYNC; -		} -		else +		} else  			zlog_debug(  				"%s: Error to convert Stream into Link State",  				__func__); @@ -847,12 +843,11 @@ void sharp_opaque_send(uint32_t type, uint32_t proto, uint32_t instance,  							  instance, session_id,  							  buf, sizeof(buf));  		if (ret == ZCLIENT_SEND_FAILURE) { -			zlog_debug("%s: send_opaque() failed => %d", -				   __func__, ret); +			zlog_debug("%s: send_opaque() failed => %d", __func__, +				   ret);  			break;  		}  	} -  }  /* @@ -883,7 +878,6 @@ void sharp_opaque_reg_send(bool is_reg, uint32_t proto, uint32_t instance,  	stream_putw_at(s, 0, stream_get_endp(s));  	(void)zclient_send_message(zclient); -  }  /* Link State registration */ @@ -985,6 +979,64 @@ int sharp_zebra_send_interface_protodown(struct interface *ifp, bool down)  	return 0;  } +int sharp_zebra_send_tc_filter_rate(struct interface *ifp, +				    const struct prefix *source, +				    const struct prefix *destination, +				    uint8_t ip_proto, uint16_t src_port, +				    uint16_t dst_port, uint64_t rate) +{ +#define SHARPD_TC_HANDLE 0x0001 +	struct stream *s; + +	s = zclient->obuf; + +	struct tc_qdisc q = {.ifindex = ifp->ifindex, .kind = TC_QDISC_HTB}; + +	zapi_tc_qdisc_encode(ZEBRA_TC_QDISC_INSTALL, s, &q); +	if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE) +		return -1; + +	struct tc_class c = {.ifindex = ifp->ifindex, +			     .handle = SHARPD_TC_HANDLE & 0xffff, +			     .kind = TC_QDISC_HTB, +			     .u.htb.ceil = rate, +			     .u.htb.rate = rate}; + +	zapi_tc_class_encode(ZEBRA_TC_CLASS_ADD, s, &c); +	if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE) +		return -1; + +	struct tc_filter f = {.ifindex = ifp->ifindex, +			      .handle = SHARPD_TC_HANDLE, +			      .priority = 0x1, +			      .kind = TC_FILTER_FLOWER, +			      .u.flower.filter_bm = 0}; + +#ifdef ETH_P_IP +	f.protocol = ETH_P_IP; +#else +	f.protocol = 0x0800; +#endif + +	f.u.flower.filter_bm |= TC_FLOWER_IP_PROTOCOL; +	f.u.flower.ip_proto = ip_proto; +	f.u.flower.filter_bm |= TC_FLOWER_SRC_IP; +	prefix_copy(&f.u.flower.src_ip, source); +	f.u.flower.filter_bm |= TC_FLOWER_DST_IP; +	prefix_copy(&f.u.flower.dst_ip, destination); +	f.u.flower.filter_bm |= TC_FLOWER_SRC_PORT; +	f.u.flower.src_port_min = f.u.flower.src_port_max = src_port; +	f.u.flower.filter_bm |= TC_FLOWER_DST_PORT; +	f.u.flower.dst_port_min = f.u.flower.dst_port_max = dst_port; +	f.u.flower.classid = SHARPD_TC_HANDLE & 0xffff; + +	zapi_tc_filter_encode(ZEBRA_TC_FILTER_ADD, s, &f); +	if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE) +		return -1; + +	return 0; +} +  static zclient_handler *const sharp_handlers[] = {  	[ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add,  	[ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete, @@ -1002,8 +1054,8 @@ void sharp_zebra_init(void)  {  	struct zclient_options opt = {.receive_notify = true}; -	if_zapi_callbacks(sharp_ifp_create, sharp_ifp_up, -			  sharp_ifp_down, sharp_ifp_destroy); +	if_zapi_callbacks(sharp_ifp_create, sharp_ifp_up, sharp_ifp_down, +			  sharp_ifp_destroy);  	zclient = zclient_new(master, &opt, sharp_handlers,  			      array_size(sharp_handlers)); diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index d8ea679797..8de14ce5af 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -75,4 +75,9 @@ extern void sharp_install_seg6local_route_helper(struct prefix *p,  extern int sharp_zebra_send_interface_protodown(struct interface *ifp,  						bool down); +extern int sharp_zebra_send_tc_filter_rate(struct interface *ifp, +					   const struct prefix *source, +					   const struct prefix *destination, +					   uint8_t ip_proto, uint16_t src_port, +					   uint16_t dst_port, uint64_t rate);  #endif  | 
