From e8ea359a1775c8a2030ed16f819cabcbd4be154c Mon Sep 17 00:00:00 2001
From: Volodymyr Huti <volodymyr.huti@gmail.com>
Date: Thu, 14 Jul 2022 16:55:55 +0300
Subject: [PATCH] QPPB DEMO (FRR)

---
 bgpd/bgp_attr.c           |   1 +
 bgpd/bgp_attr.h           |   2 +
 bgpd/bgp_routemap.c       |  29 +++++++
 bgpd/bgp_zebra.c          |   7 ++
 include/linux/rtnetlink.h |   2 +
 lib/routemap.c            | 175 ++++++++++++++++++++++++++++++++++++++
 lib/routemap.h            |  28 ++++++
 lib/routemap_cli.c        |  39 +++++++++
 lib/routemap_northbound.c |  53 ++++++++++++
 lib/zclient.c             |   4 +
 lib/zclient.h             |   3 +
 yang/frr-route-map.yang   |  15 ++++
 zebra/rib.h               |   3 +
 zebra/rt_netlink.c        |  10 +++
 zebra/zapi_msg.c          |   5 ++
 zebra/zebra_dplane.c      |  21 +++++
 zebra/zebra_dplane.h      |   2 +
 zebra/zebra_rib.c         |   2 +
 zebra/zebra_vty.c         |  18 ++++
 19 files changed, 419 insertions(+)

diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index d57281a70..3b610d65e 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -961,6 +961,7 @@ struct attr *bgp_attr_default_set(struct attr *attr, uint8_t origin)
 	attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
 	attr->weight = BGP_ATTR_DEFAULT_WEIGHT;
 	attr->tag = 0;
+	attr->dscp = 0;
 	attr->label_index = BGP_INVALID_LABEL_INDEX;
 	attr->label = MPLS_INVALID_LABEL;
 	attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 01d993dab..913ba6d41 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -325,6 +325,8 @@ struct attr {
 	/* SR-TE Color */
 	uint32_t srte_color;
 
+	uint8_t dscp;
+
 	/* EVPN DF preference and algorithm for DF election on local ESs */
 	uint16_t df_pref;
 	uint8_t df_alg;
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index c7f5e0433..739aed17a 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -119,6 +119,7 @@ o Cisco route-map
       metric-type       :  Not yet
       origin            :  Done
       tag               :  Done
+      dscp              :  Done
       weight            :  Done
       table             :  Done
 
@@ -3053,6 +3054,30 @@ static const struct route_map_rule_cmd route_set_tag_cmd = {
 	route_map_rule_tag_free,
 };
 
+/* Set dscp to object. object must be pointer to struct bgp_path_info */
+static enum route_map_cmd_result_t
+route_set_dscp(void *rule, const struct prefix *prefix, void *object)
+{
+	struct bgp_path_info *path;
+	uint8_t *rawDscp;
+
+	rawDscp = rule;
+	path = object;
+
+	/* Set dscp value */
+	path->attr->dscp = *rawDscp;
+
+	return RMAP_OKAY;
+}
+
+/* Route map commands for dscp set. */
+static const struct route_map_rule_cmd route_set_dscp_cmd = {
+	"dscp",
+	route_set_dscp,
+	route_map_rule_dscp_compile,
+	route_map_rule_dscp_free,
+};
+
 /* Set label-index to object. object must be pointer to struct bgp_path_info */
 static enum route_map_cmd_result_t
 route_set_label_index(void *rule, const struct prefix *prefix, void *object)
@@ -6777,6 +6802,9 @@ void bgp_route_map_init(void)
 	route_map_set_tag_hook(generic_set_add);
 	route_map_no_set_tag_hook(generic_set_delete);
 
+	route_map_set_dscp_hook(generic_set_add);
+	route_map_no_set_dscp_hook(generic_set_delete);
+
 	route_map_install_match(&route_match_peer_cmd);
 	route_map_install_match(&route_match_alias_cmd);
 	route_map_install_match(&route_match_local_pref_cmd);
@@ -6835,6 +6863,7 @@ void bgp_route_map_init(void)
 	route_map_install_set(&route_set_ecommunity_lb_cmd);
 	route_map_install_set(&route_set_ecommunity_none_cmd);
 	route_map_install_set(&route_set_tag_cmd);
+	route_map_install_set(&route_set_dscp_cmd);
 	route_map_install_set(&route_set_label_index_cmd);
 
 	install_element(RMAP_NODE, &match_peer_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 2c1d56172..1a9770ab2 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1274,6 +1274,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
 	uint64_t cum_bw = 0;
 	uint32_t nhg_id = 0;
 	bool is_add;
+        uint8_t dscp;
 
 	/* Don't try to install if we're not connected to Zebra or Zebra doesn't
 	 * know of this instance.
@@ -1315,6 +1316,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
 	}
 
 	tag = info->attr->tag;
+	dscp = info->attr->dscp;
 
 	/* If the route's source is EVPN, flag as such. */
 	is_evpn = is_route_parent_evpn(info);
@@ -1421,6 +1423,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
 			if (mpinfo == info) {
 				metric = mpinfo_cp->attr->med;
 				tag = mpinfo_cp->attr->tag;
+				dscp = mpinfo_cp->attr->dscp;
 			}
 		}
 
@@ -1550,6 +1553,10 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
 
 	SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
 	api.metric = metric;
+        if (dscp) {
+            SET_FLAG(api.message, ZAPI_MESSAGE_DSCP);
+            api.dscp = dscp;
+        }
 
 	if (tag) {
 		SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index b15b72a26..5450e95e1 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -241,6 +241,7 @@ struct rtattr {
  ****/
 
 struct rtmsg {
+	/* unsigned char		rtm_dscp; */
 	unsigned char		rtm_family;
 	unsigned char		rtm_dst_len;
 	unsigned char		rtm_src_len;
@@ -342,6 +343,7 @@ enum rt_scope_t {
 #define RTM_F_FIB_MATCH	        0x2000	/* return full fib lookup match */
 #define RTM_F_OFFLOAD		0x4000	/* route is offloaded */
 #define RTM_F_TRAP		0x8000	/* route is trapping packets */
+#define RTM_F_DSCP		0x10000	/* route modifies the dscp mark */
 #define RTM_F_OFFLOAD_FAILED	0x20000000 /* route offload failed, this value
 					    * is chosen to avoid conflicts with
 					    * other flags defined in
diff --git a/lib/routemap.c b/lib/routemap.c
index 722693ea2..387c91bf0 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -425,6 +425,24 @@ void route_map_no_set_tag_hook(int (*func)(struct route_map_index *index,
 	rmap_match_set_hook.no_set_tag = func;
 }
 
+/* set dscp */
+void route_map_set_dscp_hook(int (*func)(struct route_map_index *index,
+					 const char *command, const char *arg,
+					 char *errmsg, size_t errmsg_len))
+{
+
+	rmap_match_set_hook.set_dscp = func;
+}
+
+/* no set dscp */
+void route_map_no_set_dscp_hook(int (*func)(struct route_map_index *index,
+					    const char *command,
+					    const char *arg,
+					    char *errmsg, size_t errmsg_len))
+{
+	rmap_match_set_hook.no_set_dscp = func;
+}
+
 int generic_match_add(struct route_map_index *index,
 		      const char *command, const char *arg,
 		      route_map_event_t type,
@@ -3203,6 +3221,163 @@ void *route_map_rule_tag_compile(const char *arg)
 	return tag;
 }
 
+/* Decodes a standardized DSCP into its representative value */
+uint8_t route_map_decode_dscp_enum(const char *name)
+{
+	/* Standard Differentiated Services Field Codepoints */
+	if (!strcmp(name, "cs0"))
+		return 0;
+	if (!strcmp(name, "cs1"))
+		return 8;
+	if (!strcmp(name, "cs2"))
+		return 16;
+	if (!strcmp(name, "cs3"))
+		return 24;
+	if (!strcmp(name, "cs4"))
+		return 32;
+	if (!strcmp(name, "cs5"))
+		return 40;
+	if (!strcmp(name, "cs6"))
+		return 48;
+	if (!strcmp(name, "cs7"))
+		return 56;
+	if (!strcmp(name, "af11"))
+		return 10;
+	if (!strcmp(name, "af12"))
+		return 12;
+	if (!strcmp(name, "af13"))
+		return 14;
+	if (!strcmp(name, "af21"))
+		return 18;
+	if (!strcmp(name, "af22"))
+		return 20;
+	if (!strcmp(name, "af23"))
+		return 22;
+	if (!strcmp(name, "af31"))
+		return 26;
+	if (!strcmp(name, "af32"))
+		return 28;
+	if (!strcmp(name, "af33"))
+		return 30;
+	if (!strcmp(name, "af41"))
+		return 34;
+	if (!strcmp(name, "af42"))
+		return 36;
+	if (!strcmp(name, "af43"))
+		return 38;
+	if (!strcmp(name, "ef"))
+		return 46;
+	if (!strcmp(name, "voice-admit"))
+		return 44;
+
+	/* No match? Error out */
+	return -1;
+}
+
+const char *route_map_dscp_enum_str(int dscp)
+{
+	/* Standard Differentiated Services Field Codepoints */
+	switch (dscp) {
+	case 0:
+		return "cs0";
+	case 8:
+		return "cs1";
+	case 16:
+		return "cs2";
+	case 24:
+		return "cs3";
+	case 32:
+		return "cs4";
+	case 40:
+		return "cs5";
+	case 48:
+		return "cs6";
+	case 56:
+		return "cs7";
+	case 10:
+		return "af11";
+	case 12:
+		return "af12";
+	case 14:
+		return "af13";
+	case 18:
+		return "af21";
+	case 20:
+		return "af22";
+	case 22:
+		return "af23";
+	case 26:
+		return "af31";
+	case 28:
+		return "af32";
+	case 30:
+		return "af33";
+	case 34:
+		return "af41";
+	case 36:
+		return "af42";
+	case 38:
+		return "af43";
+	case 46:
+		return "ef";
+	case 44:
+		return "voice-admit";
+	default:
+		return NULL;
+        }
+}
+
+#define PBR_DSFIELD_DSCP (0xfc) /* Upper 6 bits of DS field: DSCP */
+/* Discriminate dscp enums (cs0, cs1 etc.) and numbers */
+void *route_map_rule_dscp_compile(const char *dscp)
+{
+	char dscpname[100];
+	bool isANumber = true;
+	uint8_t *rawDscp, tmpDscp;
+
+	for (int i = 0; i < (int)strlen(dscp); i++) {
+		/* Letters are not numbers */
+		if (!isdigit(dscp[i]))
+			isANumber = false;
+
+		/* Lowercase the dscp enum (if needed) */
+		if (isupper(dscp[i]))
+			dscpname[i] = tolower(dscp[i]);
+		else
+			dscpname[i] = dscp[i];
+	}
+	dscpname[strlen(dscp)] = '\0';
+
+	if (isANumber) {
+		/* dscp passed is a regular number */
+		long dscpAsNum = strtol(dscp, NULL, 0);
+		if (dscpAsNum > PBR_DSFIELD_DSCP >> 2) {
+			zlog_debug("dscp (%s) must be less than 64\n", dscp);
+                        return NULL;
+                }
+
+                rawDscp = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*rawDscp));
+		*rawDscp = dscpAsNum;
+	} else {
+		/* check dscp if it is an enum like cs0 */
+		tmpDscp = route_map_decode_dscp_enum(dscpname);
+		if (tmpDscp > PBR_DSFIELD_DSCP) {
+			zlog_debug("Invalid dscp value: %s\n", dscpname);
+                        return NULL;
+		}
+                rawDscp = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*rawDscp));
+                *rawDscp = tmpDscp;
+	}
+
+        *rawDscp = (*rawDscp << 2);
+        return rawDscp;
+}
+
+void route_map_rule_dscp_free(void *rule)
+{
+	XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
 void route_map_rule_tag_free(void *rule)
 {
 	XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
diff --git a/lib/routemap.h b/lib/routemap.h
index 13dafe684..123fd0d04 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -322,6 +322,7 @@ DECLARE_QOBJ_TYPE(route_map);
 #define IS_SET_METRIC(A)                                                       \
 	(strmatch(A, "frr-route-map:set-metric"))
 #define IS_SET_TAG(A) (strmatch(A, "frr-route-map:set-tag"))
+#define IS_SET_DSCP(A) (strmatch(A, "frr-route-map:set-dscp"))
 #define IS_SET_SR_TE_COLOR(A)                                                  \
 	(strmatch(A, "frr-route-map:set-sr-te-color"))
 /* Zebra route-map set actions */
@@ -703,8 +704,25 @@ extern void route_map_no_set_tag_hook(int (*func)(struct route_map_index *index,
 						  char *errmsg,
 						  size_t errmsg_len));
 
+/* set dscp */
+extern void route_map_set_dscp_hook(int (*func)(struct route_map_index *index,
+					        const char *command,
+					        const char *arg,
+					        char *errmsg,
+					        size_t errmsg_len));
+/* no set dscp */
+extern void route_map_no_set_dscp_hook(int (*func)(struct route_map_index *index,
+						   const char *command,
+						   const char *arg,
+						   char *errmsg,
+						   size_t errmsg_len));
+
 extern void *route_map_rule_tag_compile(const char *arg);
 extern void route_map_rule_tag_free(void *rule);
+extern uint8_t route_map_decode_dscp_enum(const char *name);
+extern const char *route_map_dscp_enum_str(int dscp);
+extern void *route_map_rule_dscp_compile(const char *dscp);
+extern void route_map_rule_dscp_free(void *dscp);
 
 /* Increment the route-map used counter */
 extern void route_map_counter_increment(struct route_map *map);
@@ -936,6 +954,16 @@ struct route_map_match_set_hooks {
 	int (*no_set_tag)(struct route_map_index *index,
 			  const char *command, const char *arg,
 			  char *errmsg, size_t errmsg_len);
+
+	/* set dscp */
+	int (*set_dscp)(struct route_map_index *index,
+		        const char *command, const char *arg,
+		        char *errmsg, size_t errmsg_len);
+
+	/* no set dscp */
+	int (*no_set_dscp)(struct route_map_index *index,
+			   const char *command, const char *arg,
+			   char *errmsg, size_t errmsg_len);
 };
 
 extern struct route_map_match_set_hooks rmap_match_set_hook;
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
index ff98a14c4..9ec415bb5 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -934,6 +934,39 @@ DEFPY_YANG(
 	return nb_cli_apply_changes(vty, NULL);
 }
 
+DEFPY_YANG(
+	set_dscp, set_dscp_cmd,
+	"set dscp DSCP$dscp",
+	SET_STR
+	"DSCP value for routing protocol\n"
+        "DSCP value\n")
+{
+	const char *xpath = "./set-action[action='frr-route-map:set-dscp']";
+	char xpath_value[XPATH_MAXLEN];
+
+	nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+	snprintf(xpath_value, sizeof(xpath_value), "%s/rmap-set-action/dscp",
+		 xpath);
+	nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, dscp);
+
+	return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY_YANG(
+	no_set_dscp, no_set_dscp_cmd,
+	"no set dscp [OPTVAL]",
+	NO_STR
+	SET_STR
+	"DSCP value for routing protocol\n"
+	"DSCP value\n")
+{
+	const char *xpath = "./set-action[action='frr-route-map:set-dscp']";
+
+	nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+	return nb_cli_apply_changes(vty, NULL);
+}
+
 DEFUN_YANG (set_srte_color,
 	    set_srte_color_cmd,
 	    "set sr-te color (1-4294967295)",
@@ -1025,6 +1058,9 @@ void route_map_action_show(struct vty *vty, const struct lyd_node *dnode,
 	} else if (IS_SET_TAG(action)) {
 		vty_out(vty, " set tag %s\n",
 			yang_dnode_get_string(dnode, "./rmap-set-action/tag"));
+	} else if (IS_SET_DSCP(action)) {
+		vty_out(vty, " set dscp %s\n",
+			yang_dnode_get_string(dnode, "./rmap-set-action/dscp"));
 	} else if (IS_SET_SR_TE_COLOR(action)) {
 		vty_out(vty, " set sr-te color %s\n",
 			yang_dnode_get_string(dnode,
@@ -1555,6 +1591,9 @@ void route_map_cli_init(void)
 	install_element(RMAP_NODE, &set_tag_cmd);
 	install_element(RMAP_NODE, &no_set_tag_cmd);
 
+	install_element(RMAP_NODE, &set_dscp_cmd);
+	install_element(RMAP_NODE, &no_set_dscp_cmd);
+
 	install_element(RMAP_NODE, &set_srte_color_cmd);
 	install_element(RMAP_NODE, &no_set_srte_color_cmd);
 }
diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c
index 51b879959..bfbbc8252 100644
--- a/lib/routemap_northbound.c
+++ b/lib/routemap_northbound.c
@@ -1193,6 +1193,52 @@ lib_route_map_entry_set_action_tag_destroy(struct nb_cb_destroy_args *args)
 	return lib_route_map_entry_set_destroy(args);
 }
 
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/dscp
+ */
+static int
+lib_route_map_entry_set_action_dscp_modify(struct nb_cb_modify_args *args)
+{
+	struct routemap_hook_context *rhc;
+	const char *dscp;
+	int rv;
+
+	/*
+	 * NOTE: validate if 'action' is 'dscp', currently it is not
+	 * necessary because this is the only implemented action. Other
+	 * actions might have different validations.
+	 */
+	if (args->event != NB_EV_APPLY)
+		return NB_OK;
+
+	/* Check for hook function. */
+	if (rmap_match_set_hook.set_dscp == NULL)
+		return NB_OK;
+
+	/* Add configuration. */
+	rhc = nb_running_get_entry(args->dnode, NULL, true);
+	dscp = yang_dnode_get_string(args->dnode, NULL);
+
+	/* Set destroy information. */
+	rhc->rhc_shook = rmap_match_set_hook.no_set_dscp;
+	rhc->rhc_rule = "dscp";
+
+	rv = rmap_match_set_hook.set_dscp(rhc->rhc_rmi, "dscp", dscp,
+					 args->errmsg, args->errmsg_len);
+	if (rv != CMD_SUCCESS) {
+		rhc->rhc_shook = NULL;
+		return NB_ERR_INCONSISTENCY;
+	}
+
+	return NB_OK;
+}
+
+static int
+lib_route_map_entry_set_action_dscp_destroy(struct nb_cb_destroy_args *args)
+{
+	return lib_route_map_entry_set_destroy(args);
+}
+
 /*
  * XPath: /frr-route-map:lib/route-map/entry/set-action/policy
  */
@@ -1424,6 +1470,13 @@ const struct frr_yang_module_info frr_route_map_info = {
 				.destroy = lib_route_map_entry_set_action_tag_destroy,
 			}
 		},
+		{
+			.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/dscp",
+			.cbs = {
+				.modify = lib_route_map_entry_set_action_dscp_modify,
+				.destroy = lib_route_map_entry_set_action_dscp_destroy,
+			}
+		},
 		{
 			.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/policy",
 			.cbs = {
diff --git a/lib/zclient.c b/lib/zclient.c
index a933b6bb2..612d35ce8 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1324,6 +1324,8 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
 		stream_putc(s, api->distance);
 	if (CHECK_FLAG(api->message, ZAPI_MESSAGE_METRIC))
 		stream_putl(s, api->metric);
+	if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DSCP))
+		stream_putl(s, api->dscp);
 	if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TAG))
 		stream_putl(s, api->tag);
 	if (CHECK_FLAG(api->message, ZAPI_MESSAGE_MTU))
@@ -1567,6 +1569,8 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
 		STREAM_GETC(s, api->distance);
 	if (CHECK_FLAG(api->message, ZAPI_MESSAGE_METRIC))
 		STREAM_GETL(s, api->metric);
+	if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DSCP))
+		STREAM_GETL(s, api->dscp);
 	if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TAG))
 		STREAM_GETL(s, api->tag);
 	if (CHECK_FLAG(api->message, ZAPI_MESSAGE_MTU))
diff --git a/lib/zclient.h b/lib/zclient.h
index 9756923a6..d785a6518 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -389,6 +389,7 @@ extern int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS);
 #define ZAPI_MESSAGE_TABLEID 0x0100
 #define ZAPI_MESSAGE_SRTE 0x0200
 #define ZAPI_MESSAGE_OPAQUE 0x0400
+#define ZAPI_MESSAGE_DSCP 0x0800
 
 #define ZSERV_VERSION 6
 /* Zserv protocol message header */
@@ -562,6 +563,8 @@ struct zapi_route {
 
 	uint32_t metric;
 
+	uint32_t dscp;
+
 	route_tag_t tag;
 
 	uint32_t mtu;
diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang
index 1e8c04bc6..b0e479dd2 100644
--- a/yang/frr-route-map.yang
+++ b/yang/frr-route-map.yang
@@ -165,6 +165,12 @@ module frr-route-map {
       "Set tag";
   }
 
+  identity set-dscp {
+    base rmap-set-type;
+    description
+      "Set dscp";
+  }
+
   identity set-sr-te-color {
     base rmap-set-type;
     description
@@ -356,6 +362,15 @@ module frr-route-map {
           }
         }
 
+        case set-dscp {
+          when "derived-from-or-self(../action, 'set-dscp')";
+          leaf dscp {
+            type string;
+            description
+              "Dscp value";
+          }
+        }
+
         case set-sr-te-color {
           when "derived-from-or-self(../action, 'set-sr-te-color')";
           leaf policy {
diff --git a/zebra/rib.h b/zebra/rib.h
index 60092c963..278beccef 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -131,6 +131,9 @@ struct route_entry {
 	/* Metric */
 	uint32_t metric;
 
+	/* DSCP */
+	uint32_t dscp;
+
 	/* MTU */
 	uint32_t mtu;
 	uint32_t nexthop_mtu;
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 93b2d9467..7b09349b5 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -694,6 +694,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
 	uint8_t distance = 0;
 	route_tag_t tag = 0;
 	uint32_t nhe_id = 0;
+	uint8_t dscp = 0;
 
 	void *dest = NULL;
 	void *gate = NULL;
@@ -782,6 +783,11 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
 		flags |= ZEBRA_FLAG_OFFLOADED;
 	if (rtm->rtm_flags & RTM_F_OFFLOAD_FAILED)
 		flags |= ZEBRA_FLAG_OFFLOAD_FAILED;
+#if 0
+	if (rtm->rtm_flags & RTM_F_DSCP) {
+                zlog_debug("QQQ DSCP DETECTED %d", dscp);
+        }
+#endif
 
 	/* Route which inserted by Zebra. */
 	if (selfroute) {
@@ -947,6 +953,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
 			re->uptime = monotime(NULL);
 			re->tag = tag;
 			re->nhe_id = nhe_id;
+			re->dscp = 0;
 
 			if (!nhe_id) {
 				uint8_t nhop_num;
@@ -1959,6 +1966,9 @@ ssize_t netlink_route_multipath_msg_encode(int cmd,
 	req->r.rtm_dst_len = p->prefixlen;
 	req->r.rtm_src_len = src_p ? src_p->prefixlen : 0;
 	req->r.rtm_scope = RT_SCOPE_UNIVERSE;
+        req->r.rtm_tos = dplane_ctx_get_dscp(ctx);
+        if (req->r.rtm_tos)
+            req->r.rtm_flags |= RTM_F_DSCP;
 
 	if (cmd == RTM_DELROUTE)
 		req->r.rtm_protocol = zebra2proto(dplane_ctx_get_old_type(ctx));
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 9a30c2b78..9f2bc027b 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -631,6 +631,8 @@ int zsend_redistribute_route(int cmd, struct zserv *client,
 	api.distance = re->distance;
 	SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
 	api.metric = re->metric;
+	SET_FLAG(api.message, ZAPI_MESSAGE_DSCP);
+	api.dscp = re->dscp;
 	if (re->tag) {
 		SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
 		api.tag = re->tag;
@@ -2111,6 +2113,9 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
 		re->tag = api.tag;
 	if (CHECK_FLAG(api.message, ZAPI_MESSAGE_MTU))
 		re->mtu = api.mtu;
+	if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DSCP))
+		re->dscp = api.dscp;
+
 
 	if (CHECK_FLAG(api.message, ZAPI_MESSAGE_OPAQUE)) {
 		re->opaque =
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 0da44e3c4..e645d07be 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -124,6 +124,9 @@ struct dplane_route_info {
 	uint32_t zd_metric;
 	uint32_t zd_old_metric;
 
+	uint32_t zd_dscp;
+	uint32_t zd_old_dscp;
+
 	uint16_t zd_instance;
 	uint16_t zd_old_instance;
 
@@ -1376,6 +1379,21 @@ uint32_t dplane_ctx_get_old_metric(const struct zebra_dplane_ctx *ctx)
 	return ctx->u.rinfo.zd_old_metric;
 }
 
+
+uint32_t dplane_ctx_get_dscp(const struct zebra_dplane_ctx *ctx)
+{
+	DPLANE_CTX_VALID(ctx);
+
+	return ctx->u.rinfo.zd_dscp;
+}
+
+uint32_t dplane_ctx_get_old_dscp(const struct zebra_dplane_ctx *ctx)
+{
+	DPLANE_CTX_VALID(ctx);
+
+	return ctx->u.rinfo.zd_old_dscp;
+}
+
 uint32_t dplane_ctx_get_mtu(const struct zebra_dplane_ctx *ctx)
 {
 	DPLANE_CTX_VALID(ctx);
@@ -2508,6 +2526,8 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
 
 	ctx->u.rinfo.zd_metric = re->metric;
 	ctx->u.rinfo.zd_old_metric = re->metric;
+	ctx->u.rinfo.zd_dscp = re->dscp;
+	ctx->u.rinfo.zd_old_dscp = re->dscp;
 	ctx->zd_vrf_id = re->vrf_id;
 	ctx->u.rinfo.zd_mtu = re->mtu;
 	ctx->u.rinfo.zd_nexthop_mtu = re->nexthop_mtu;
@@ -3243,6 +3263,7 @@ dplane_route_update_internal(struct route_node *rn,
 			ctx->u.rinfo.zd_old_instance = old_re->instance;
 			ctx->u.rinfo.zd_old_distance = old_re->distance;
 			ctx->u.rinfo.zd_old_metric = old_re->metric;
+                        ctx->u.rinfo.zd_old_dscp = old_re->dscp;
 			ctx->u.rinfo.nhe.old_id = old_re->nhe->id;
 
 #ifndef HAVE_NETLINK
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index 334d440a2..705fb615e 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -372,6 +372,8 @@ void dplane_ctx_set_instance(struct zebra_dplane_ctx *ctx, uint16_t instance);
 uint16_t dplane_ctx_get_old_instance(const struct zebra_dplane_ctx *ctx);
 uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx);
 uint32_t dplane_ctx_get_old_metric(const struct zebra_dplane_ctx *ctx);
+uint32_t dplane_ctx_get_dscp(const struct zebra_dplane_ctx *ctx);
+uint32_t dplane_ctx_get_old_dscp(const struct zebra_dplane_ctx *ctx);
 uint32_t dplane_ctx_get_mtu(const struct zebra_dplane_ctx *ctx);
 uint32_t dplane_ctx_get_nh_mtu(const struct zebra_dplane_ctx *ctx);
 uint8_t dplane_ctx_get_distance(const struct zebra_dplane_ctx *ctx);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 680128001..b6faafc1e 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -3820,6 +3820,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
 	struct route_entry *re = NULL;
 	struct nexthop *nexthop = NULL;
 	struct nexthop_group *ng = NULL;
+        int dscp = 0;
 
 	/* Allocate new route_entry structure. */
 	re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
@@ -3834,6 +3835,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
 	re->uptime = monotime(NULL);
 	re->tag = tag;
 	re->nhe_id = nhe_id;
+	re->dscp = dscp;
 
 	/* If the owner of the route supplies a shared nexthop-group id,
 	 * we'll use that. Otherwise, pass the nexthop along directly.
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 3756f8153..4bf724456 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -595,6 +595,16 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
 	}
 }
 
+static char *my_itoa(int num, char *str)
+{
+        if(str == NULL)
+        {
+                return NULL;
+        }
+        sprintf(str, "%d", num);
+        return str;
+}
+
 /*
  * Helper for nexthop output, used in the 'show ip route' path
  */
@@ -708,6 +718,14 @@ static void show_route_nexthop_helper(struct vty *vty,
 	if (nexthop->weight)
 		vty_out(vty, ", weight %u", nexthop->weight);
 
+
+        uint32_t dscp = re->dscp >> 2;
+        const char *dscp_name  = route_map_dscp_enum_str(dscp);
+        if (dscp_name)
+            memcpy(buf, dscp_name, sizeof(buf));
+        else
+            my_itoa(dscp, buf);
+	vty_out(vty, ", dscp %s", buf);
 	if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
 		vty_out(vty, ", backup %d", nexthop->backup_idx[0]);
 
-- 
2.25.1

