[dpdk-dev] ip_pipeline: routing pipeline improvements

Message ID 1462579071-82557-1-git-send-email-jasvinder.singh@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers

Commit Message

Jasvinder Singh May 6, 2016, 11:57 p.m. UTC
  This patch implements the tracking mechanism for the routing pipeline in
order to identify the physical nic port where a specific output port of
the rotuing pipeline is eventually connected. Depending upon the
application, tracking could involve traversing the other intermediate
pipelines.

Typically, tracking is successful through those intermediate pipelines
where each input port is connected to a single out port for example
pass-through (RX, TX and TM), flow-actions etc. In such pipelines, all
the packets from the current port can only go out of the idetified output
port. In contrast, the pipelines such as flow-classification, firewall
don't allow the tracking mechanism due to one to many mapping between input
and output ports.

As a result of tracking mechainsm, routing pipeline uses the real MAC
addresses of the network interfaces instead of hardcoded default value.
Furthermore, it allows adding/removing the implicit routes every time when
the corresponding physical nic port is brought up/down.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/app.h                         | 137 +++++++++++++++++++++
 examples/ip_pipeline/pipeline/pipeline_common_fe.c |  88 +++++++++++++
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |   5 +
 examples/ip_pipeline/pipeline/pipeline_routing.c   |  62 +++++++++-
 examples/ip_pipeline/pipeline/pipeline_routing.h   |   7 ++
 .../ip_pipeline/pipeline/pipeline_routing_be.c     |  37 ++++--
 .../ip_pipeline/pipeline/pipeline_routing_be.h     |  15 +++
 7 files changed, 341 insertions(+), 10 deletions(-)
  

Comments

Jasvinder Singh June 1, 2016, 2 p.m. UTC | #1
This commit adds following features to the routing pipeline;

1. Implements the tracking mechanism for the routing pipeline for identifying
the physical nic port where a specific output ports of the routing pipeline are
eventually connected. Depending upon the application, tracking could involve
traversing the other intermediate pipelines.

The pipelines such as pass-through allows tracking to be performaned through
them becasue of straightforward connections between their input and output
ports, while pipelines like flow-classifications, firewall fails the tracking
because of dependency upon the table rule set. As a result of tracking
mechainsm, routing pipeline uses the real MAC addresses of the network
interfaces instead of hardcoded default value.

2. Adds support for automatic route automatic update when physical NIC ports
change their state (up/down) or configuration. Every time a physical port
goes up/down, a call-back function that the specific pipeline type
(e.g. routing) registered with NIC ports at init time; will simply add/delete
a route associated with that output port.

v2
- rebased on top of "ip_pipeline: add rss support" patch
  http://dpdk.org/dev/patchwork/patch/13110/
- split the single patch into multiple patches of the patchset. 
- add post init function for tracking and linking physical nic with 
  routing pipeline output port
- create default tracking function "app_pipeline_track_default()" in
  pipeline_common_fe.c for all the pipelines except pass-through
- fix port in/out connections in passthrough pipeline tracking function
  and move that function to pipeline/pipeline_passthrough.c
- fix mac address endianess issue in routing pipeline table
- add/remove implicit routes (for host and local network) when corresponding
  link is brought up/down
- update the release notes

Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>

Jasvinder Singh (6):
  ip_pipeline: increase macros values
  ip_pipeline: linking routing pipeline output ports with NIC ports
  ip_pipeline: assign nic ports mac address to the routing pipeline
    outports
  ip_pipeline: automatic routes update with the change in nic ports
    state
  ip_pipeline: sample config file on adding various network layer
    components
  ip_pipeline: update release notes

 doc/guides/rel_notes/release_16_07.rst             |  10 +
 examples/ip_pipeline/app.h                         | 184 ++++++++++++++--
 examples/ip_pipeline/config/network_layers.cfg     | 223 +++++++++++++++++++
 examples/ip_pipeline/config/network_layers.sh      |  79 +++++++
 examples/ip_pipeline/init.c                        |  32 ++-
 examples/ip_pipeline/pipeline.h                    |  11 +-
 examples/ip_pipeline/pipeline/pipeline_common_fe.c | 161 ++++++++++++++
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |  17 ++
 examples/ip_pipeline/pipeline/pipeline_firewall.c  |   2 +
 .../ip_pipeline/pipeline/pipeline_firewall_be.c    |  22 --
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   |   2 +
 .../pipeline/pipeline_flow_actions_be.c            |  22 --
 .../pipeline/pipeline_flow_classification.c        |   2 +
 .../pipeline/pipeline_flow_classification_be.c     |  22 --
 examples/ip_pipeline/pipeline/pipeline_master.c    |   2 +
 examples/ip_pipeline/pipeline/pipeline_master_be.c |  13 +-
 .../ip_pipeline/pipeline/pipeline_passthrough.c    |  27 +++
 .../ip_pipeline/pipeline/pipeline_passthrough_be.c |  39 ++--
 examples/ip_pipeline/pipeline/pipeline_routing.c   | 239 ++++++++++++++++++++-
 examples/ip_pipeline/pipeline/pipeline_routing.h   |   7 +
 .../ip_pipeline/pipeline/pipeline_routing_be.c     | 102 +++++----
 .../ip_pipeline/pipeline/pipeline_routing_be.h     |  16 ++
 examples/ip_pipeline/pipeline_be.h                 |  18 +-
 23 files changed, 1091 insertions(+), 161 deletions(-)
 create mode 100644 examples/ip_pipeline/config/network_layers.cfg
 create mode 100644 examples/ip_pipeline/config/network_layers.sh
  
Thomas Monjalon June 8, 2016, 7:43 p.m. UTC | #2
2016-06-01 15:00, Jasvinder Singh:
> This commit adds following features to the routing pipeline;
> 
> 1. Implements the tracking mechanism for the routing pipeline for identifying
> the physical nic port where a specific output ports of the routing pipeline are
> eventually connected. Depending upon the application, tracking could involve
> traversing the other intermediate pipelines.
> 
> The pipelines such as pass-through allows tracking to be performaned through
> them becasue of straightforward connections between their input and output
> ports, while pipelines like flow-classifications, firewall fails the tracking
> because of dependency upon the table rule set. As a result of tracking
> mechainsm, routing pipeline uses the real MAC addresses of the network
> interfaces instead of hardcoded default value.
> 
> 2. Adds support for automatic route automatic update when physical NIC ports
> change their state (up/down) or configuration. Every time a physical port
> goes up/down, a call-back function that the specific pipeline type
> (e.g. routing) registered with NIC ports at init time; will simply add/delete
> a route associated with that output port.
> 
> Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> 
> Jasvinder Singh (6):
>   ip_pipeline: increase macros values
>   ip_pipeline: linking routing pipeline output ports with NIC ports
>   ip_pipeline: assign nic ports mac address to the routing pipeline
>     outports
>   ip_pipeline: automatic routes update with the change in nic ports
>     state
>   ip_pipeline: sample config file on adding various network layer
>     components
>   ip_pipeline: update release notes

Applied, thanks
  

Patch

diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h
index 55a9841..803e42e 100644
--- a/examples/ip_pipeline/app.h
+++ b/examples/ip_pipeline/app.h
@@ -665,6 +665,40 @@  app_swq_get_readers(struct app_params *app, struct app_pktq_swq_params *swq)
 	return n_readers;
 }
 
+static inline struct app_pipeline_params *
+app_swq_get_reader(struct app_params *app, struct app_pktq_swq_params *swq,
+	uint32_t *pktq_in_id)
+{
+	struct app_pipeline_params *reader;
+	uint32_t pos = swq - app->swq_params;
+	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+		RTE_DIM(app->pipeline_params));
+	uint32_t n_readers = 0, id, i;
+
+	for (i = 0; i < n_pipelines; i++) {
+		struct app_pipeline_params *p = &app->pipeline_params[i];
+		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
+		uint32_t j;
+
+		for (j = 0; j < n_pktq_in; j++) {
+			struct app_pktq_in_params *pktq = &p->pktq_in[j];
+
+			if ((pktq->type == APP_PKTQ_IN_SWQ) &&
+				(pktq->id == pos)) {
+				n_readers++;
+				reader = p;
+				id = j;
+			}
+		}
+	}
+
+	if (n_readers != 1)
+		return NULL;
+
+	*pktq_in_id = id;
+	return reader;
+}
+
 static inline uint32_t
 app_tm_get_readers(struct app_params *app, struct app_pktq_tm_params *tm)
 {
@@ -690,6 +724,40 @@  app_tm_get_readers(struct app_params *app, struct app_pktq_tm_params *tm)
 	return n_readers;
 }
 
+static inline struct app_pipeline_params *
+app_tm_get_reader(struct app_params *app, struct app_pktq_tm_params *tm,
+	uint32_t *pktq_in_id)
+{
+	struct app_pipeline_params *reader;
+	uint32_t pos = tm - app->tm_params;
+	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+		RTE_DIM(app->pipeline_params));
+	uint32_t n_readers = 0, id, i;
+
+	for (i = 0; i < n_pipelines; i++) {
+		struct app_pipeline_params *p = &app->pipeline_params[i];
+		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
+		uint32_t j;
+
+		for (j = 0; j < n_pktq_in; j++) {
+			struct app_pktq_in_params *pktq = &p->pktq_in[j];
+
+			if ((pktq->type == APP_PKTQ_IN_TM) &&
+				(pktq->id == pos)) {
+				n_readers++;
+				reader = p;
+				id = j;
+			}
+		}
+	}
+
+	if (n_readers != 1)
+		return NULL;
+
+	*pktq_in_id = id;
+	return reader;
+}
+
 static inline uint32_t
 app_source_get_readers(struct app_params *app,
 struct app_pktq_source_params *source)
@@ -789,6 +857,41 @@  app_swq_get_writers(struct app_params *app, struct app_pktq_swq_params *swq)
 	return n_writers;
 }
 
+static inline struct app_pipeline_params *
+app_swq_get_writer(struct app_params *app, struct app_pktq_swq_params *swq,
+	uint32_t *pktq_out_id)
+{
+	struct app_pipeline_params *writer;
+	uint32_t pos = swq - app->swq_params;
+	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+		RTE_DIM(app->pipeline_params));
+	uint32_t n_writers = 0, id, i;
+
+	for (i = 0; i < n_pipelines; i++) {
+		struct app_pipeline_params *p = &app->pipeline_params[i];
+		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
+			RTE_DIM(p->pktq_out));
+		uint32_t j;
+
+		for (j = 0; j < n_pktq_out; j++) {
+			struct app_pktq_out_params *pktq = &p->pktq_out[j];
+
+			if ((pktq->type == APP_PKTQ_OUT_SWQ) &&
+				(pktq->id == pos)) {
+				n_writers++;
+				writer = p;
+				id = j;
+			}
+		}
+	}
+
+	if (n_writers != 1)
+		return NULL;
+
+	*pktq_out_id = id;
+	return writer;
+}
+
 static inline uint32_t
 app_tm_get_writers(struct app_params *app, struct app_pktq_tm_params *tm)
 {
@@ -815,6 +918,40 @@  app_tm_get_writers(struct app_params *app, struct app_pktq_tm_params *tm)
 	return n_writers;
 }
 
+static inline struct app_pipeline_params *
+app_tm_get_writer(struct app_params *app, struct app_pktq_tm_params *tm,
+	uint32_t *pktq_out_id)
+{
+	struct app_pipeline_params *writer;
+	uint32_t pos = tm - app->tm_params;
+	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+		RTE_DIM(app->pipeline_params));
+	uint32_t n_writers = 0, id, i;
+
+	for (i = 0; i < n_pipelines; i++) {
+		struct app_pipeline_params *p = &app->pipeline_params[i];
+		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
+			RTE_DIM(p->pktq_out));
+		uint32_t j;
+
+		for (j = 0; j < n_pktq_out; j++) {
+			struct app_pktq_out_params *pktq = &p->pktq_out[j];
+
+			if ((pktq->type == APP_PKTQ_OUT_TM) &&
+				(pktq->id == pos))
+				n_writers++;
+				writer = p;
+				id = j;
+		}
+	}
+
+	if (n_writers != 1)
+		return NULL;
+
+	*pktq_out_id = id;
+	return writer;
+}
+
 static inline uint32_t
 app_sink_get_writers(struct app_params *app, struct app_pktq_sink_params *sink)
 {
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.c b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
index a691d42..e29d9a1 100644
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.c
+++ b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
@@ -49,6 +49,94 @@ 
 
 #include "pipeline_common_fe.h"
 
+struct app_link_params *
+app_pipeline_track_pktq_out_to_link(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t pktq_out_id)
+{
+	struct app_pipeline_params *p;
+
+	/* Check input arguments */
+	if (app == NULL)
+		return NULL;
+
+	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
+	if (p == NULL)
+		return NULL;
+
+	for ( ; ; ) {
+		struct app_pktq_out_params *pktq_out =
+			&p->pktq_out[pktq_out_id];
+
+		switch (pktq_out->type) {
+		case APP_PKTQ_OUT_HWQ:
+		{
+			struct app_pktq_hwq_out_params *hwq_out;
+
+			hwq_out = &app->hwq_out_params[pktq_out->id];
+
+			return app_get_link_for_txq(app, hwq_out);
+		}
+
+		case APP_PKTQ_OUT_SWQ:
+		{
+			struct app_pipeline_data *pdata;
+			struct app_pktq_swq_params *swq;
+			uint32_t pktq_in_id;
+			int status;
+
+			swq = &app->swq_params[pktq_out->id];
+			p = app_swq_get_reader(app, swq, &pktq_in_id);
+			if (p == NULL)
+				return NULL;
+
+			pipeline_id = p - app->pipeline_params;
+			pdata = &app->pipeline_data[pipeline_id];
+			if (pdata->ptype->be_ops->f_track == NULL)
+				return NULL;
+
+			status = pdata->ptype->be_ops->f_track(pdata->be,
+				pktq_in_id,
+				&pktq_out_id);
+			if (status)
+				return NULL;
+
+			break;
+		}
+
+		case APP_PKTQ_OUT_TM:
+		{
+			struct app_pipeline_data *pdata;
+			struct app_pktq_tm_params *tm;
+			uint32_t pktq_in_id;
+			int status;
+
+			tm = &app->tm_params[pktq_out->id];
+			p = app_tm_get_reader(app, tm, &pktq_in_id);
+			if (p == NULL)
+				return NULL;
+
+			pipeline_id = p - app->pipeline_params;
+			pdata = &app->pipeline_data[pipeline_id];
+			if (pdata->ptype->be_ops->f_track == NULL)
+				return NULL;
+
+			status = pdata->ptype->be_ops->f_track(pdata->be,
+				pktq_in_id,
+				&pktq_out_id);
+			if (status)
+				return NULL;
+
+			break;
+		}
+
+		case APP_PKTQ_OUT_SINK:
+		default:
+			return NULL;
+		}
+	}
+}
+
 int
 app_pipeline_ping(struct app_params *app,
 	uint32_t pipeline_id)
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.h b/examples/ip_pipeline/pipeline/pipeline_common_fe.h
index cfad963..7fa6ea9 100644
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.h
+++ b/examples/ip_pipeline/pipeline/pipeline_common_fe.h
@@ -182,6 +182,11 @@  app_msg_send_recv(struct app_params *app,
 	return msg_recv;
 }
 
+struct app_link_params *
+app_pipeline_track_pktq_out_to_link(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t pktq_out_id);
+
 int
 app_pipeline_ping(struct app_params *app,
 	uint32_t pipeline_id);
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing.c b/examples/ip_pipeline/pipeline/pipeline_routing.c
index eab89f2..d890cc8 100644
--- a/examples/ip_pipeline/pipeline/pipeline_routing.c
+++ b/examples/ip_pipeline/pipeline/pipeline_routing.c
@@ -81,10 +81,11 @@  struct pipeline_routing {
 
 static void *
 pipeline_routing_init(struct pipeline_params *params,
-	__rte_unused void *arg)
+	void *arg)
 {
+	struct app_params *app = (struct app_params *) arg;
 	struct pipeline_routing *p;
-	uint32_t size;
+	uint32_t pipeline_id, size;
 
 	/* Check input arguments */
 	if ((params == NULL) ||
@@ -108,6 +109,9 @@  pipeline_routing_init(struct pipeline_params *params,
 	TAILQ_INIT(&p->arp_entries);
 	p->n_arp_entries = 0;
 
+	APP_PARAM_GET_ID(params, "PIPELINE", pipeline_id);
+	app_pipeline_routing_set_macaddr(app, pipeline_id);
+
 	return p;
 }
 
@@ -853,6 +857,60 @@  app_pipeline_routing_delete_default_arp_entry(struct app_params *app,
 	return 0;
 }
 
+int
+app_pipeline_routing_set_macaddr(struct app_params *app,
+	uint32_t pipeline_id)
+{
+	struct pipeline_routing *p;
+
+	struct pipeline_routing_set_macaddr_msg_req *req;
+	struct pipeline_routing_set_macaddr_msg_rsp *rsp;
+	uint32_t port_id;
+
+	/* Check input arguments */
+	if (app == NULL)
+		return -1;
+
+	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
+	if (p == NULL)
+		return -EINVAL;
+
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -ENOMEM;
+
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_ROUTING_MSG_REQ_SET_MACADDR;
+
+	memset(req->macaddr, 0, sizeof(req->macaddr));
+	for (port_id = 0; port_id < p->n_ports_out; port_id++) {
+		struct app_link_params *link;
+
+		link = app_pipeline_track_pktq_out_to_link(app,
+			pipeline_id,
+			port_id);
+		if (link)
+			req->macaddr[port_id] = link->mac_addr;
+	}
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
+	if (rsp == NULL)
+		return -ETIMEDOUT;
+
+	/* Read response and write entry */
+	if (rsp->status) {
+		app_msg_free(app, rsp);
+		return rsp->status;
+	}
+
+	/* Free response */
+	app_msg_free(app, rsp);
+
+	return 0;
+}
+
 static int
 parse_labels(char *string, uint32_t *labels, uint32_t *n_labels)
 {
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing.h b/examples/ip_pipeline/pipeline/pipeline_routing.h
index fa41642..0197449 100644
--- a/examples/ip_pipeline/pipeline/pipeline_routing.h
+++ b/examples/ip_pipeline/pipeline/pipeline_routing.h
@@ -86,6 +86,13 @@  app_pipeline_routing_delete_default_arp_entry(struct app_params *app,
 	uint32_t pipeline_id);
 
 /*
+ * SETTINGS
+ */
+int
+app_pipeline_routing_set_macaddr(struct app_params *app,
+	uint32_t pipeline_id);
+
+/*
  * Pipeline type
  */
 extern struct pipeline_type pipeline_routing;
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing_be.c b/examples/ip_pipeline/pipeline/pipeline_routing_be.c
index bc5bf7a..d22a465 100644
--- a/examples/ip_pipeline/pipeline/pipeline_routing_be.c
+++ b/examples/ip_pipeline/pipeline/pipeline_routing_be.c
@@ -65,8 +65,6 @@ 
 	((((uint64_t) (pipe)) & 0xFFFFFFFF) << 32))
 
 
-#define MAC_SRC_DEFAULT 0x112233445566ULL
-
 #ifndef PIPELINE_ROUTING_LPM_TABLE_NUMBER_TABLE8s
 #define PIPELINE_ROUTING_LPM_TABLE_NUMBER_TABLE8s 256
 #endif
@@ -74,6 +72,7 @@ 
 struct pipeline_routing {
 	struct pipeline p;
 	struct pipeline_routing_params params;
+	uint64_t macaddr[PIPELINE_MAX_PORT_OUT];
 	pipeline_msg_req_handler custom_handlers[PIPELINE_ROUTING_MSG_REQS];
 } __rte_cache_aligned;
 
@@ -132,6 +131,10 @@  static void *
 pipeline_routing_msg_req_arp_del_default_handler(struct pipeline *p,
 	void *msg);
 
+static void *
+pipeline_routing_msg_req_set_macaddr_handler(struct pipeline *p,
+	void *msg);
+
 static pipeline_msg_req_handler custom_handlers[] = {
 	[PIPELINE_ROUTING_MSG_REQ_ROUTE_ADD] =
 		pipeline_routing_msg_req_route_add_handler,
@@ -149,6 +152,8 @@  static pipeline_msg_req_handler custom_handlers[] = {
 		pipeline_routing_msg_req_arp_add_default_handler,
 	[PIPELINE_ROUTING_MSG_REQ_ARP_DEL_DEFAULT] =
 		pipeline_routing_msg_req_arp_del_default_handler,
+	[PIPELINE_ROUTING_MSG_REQ_SET_MACADDR] =
+		pipeline_routing_msg_req_set_macaddr_handler,
 };
 
 /*
@@ -1534,7 +1539,7 @@  pipeline_routing_msg_req_route_add_handler(struct pipeline *p, void *msg)
 	/* Ether - ARP off */
 	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET) &&
 		(p_rt->params.n_arp_entries == 0)) {
-		uint64_t macaddr_src = MAC_SRC_DEFAULT;
+		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
 		uint64_t macaddr_dst;
 		uint64_t ethertype = ETHER_TYPE_IPv4;
 
@@ -1556,7 +1561,7 @@  pipeline_routing_msg_req_route_add_handler(struct pipeline *p, void *msg)
 	/* Ether - ARP on */
 	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET) &&
 		p_rt->params.n_arp_entries) {
-		uint64_t macaddr_src = MAC_SRC_DEFAULT;
+		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
 		uint64_t ethertype = ETHER_TYPE_IPv4;
 
 		entry_arp1.slab[0] = rte_bswap64((macaddr_src << 16) |
@@ -1571,7 +1576,7 @@  pipeline_routing_msg_req_route_add_handler(struct pipeline *p, void *msg)
 	/* Ether QinQ - ARP off */
 	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
 		(p_rt->params.n_arp_entries == 0)) {
-		uint64_t macaddr_src = MAC_SRC_DEFAULT;
+		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
 		uint64_t macaddr_dst;
 		uint64_t ethertype_ipv4 = ETHER_TYPE_IPv4;
 		uint64_t ethertype_vlan = 0x8100;
@@ -1603,7 +1608,7 @@  pipeline_routing_msg_req_route_add_handler(struct pipeline *p, void *msg)
 	/* Ether QinQ - ARP on */
 	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
 		p_rt->params.n_arp_entries) {
-		uint64_t macaddr_src = MAC_SRC_DEFAULT;
+		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
 		uint64_t ethertype_ipv4 = ETHER_TYPE_IPv4;
 		uint64_t ethertype_vlan = 0x8100;
 		uint64_t ethertype_qinq = 0x9100;
@@ -1628,7 +1633,7 @@  pipeline_routing_msg_req_route_add_handler(struct pipeline *p, void *msg)
 	/* Ether MPLS - ARP off */
 	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
 		(p_rt->params.n_arp_entries == 0)) {
-		uint64_t macaddr_src = MAC_SRC_DEFAULT;
+		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
 		uint64_t macaddr_dst;
 		uint64_t ethertype_mpls = 0x8847;
 
@@ -1714,7 +1719,7 @@  pipeline_routing_msg_req_route_add_handler(struct pipeline *p, void *msg)
 	/* Ether MPLS - ARP on */
 	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
 		p_rt->params.n_arp_entries) {
-		uint64_t macaddr_src = MAC_SRC_DEFAULT;
+		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
 		uint64_t ethertype_mpls = 0x8847;
 
 		uint64_t label0 = req->data.l2.mpls.labels[0];
@@ -1961,6 +1966,22 @@  pipeline_routing_msg_req_arp_del_default_handler(struct pipeline *p, void *msg)
 	return rsp;
 }
 
+void *
+pipeline_routing_msg_req_set_macaddr_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_routing *p_rt = (struct pipeline_routing *) p;
+	struct pipeline_routing_set_macaddr_msg_req *req = msg;
+	struct pipeline_routing_set_macaddr_msg_rsp *rsp = msg;
+	uint32_t port_id;
+
+	for (port_id = 0; port_id < p->n_ports_out; port_id++)
+		p_rt->macaddr[port_id] = req->macaddr[port_id];
+
+	rsp->status = 0;
+
+	return rsp;
+}
+
 struct pipeline_be_ops pipeline_routing_be_ops = {
 	.f_init = pipeline_routing_init,
 	.f_free = pipeline_routing_free,
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing_be.h b/examples/ip_pipeline/pipeline/pipeline_routing_be.h
index ec767b2..822995b 100644
--- a/examples/ip_pipeline/pipeline/pipeline_routing_be.h
+++ b/examples/ip_pipeline/pipeline/pipeline_routing_be.h
@@ -160,6 +160,7 @@  enum pipeline_routing_msg_req_type {
 	PIPELINE_ROUTING_MSG_REQ_ARP_DEL,
 	PIPELINE_ROUTING_MSG_REQ_ARP_ADD_DEFAULT,
 	PIPELINE_ROUTING_MSG_REQ_ARP_DEL_DEFAULT,
+	PIPELINE_ROUTING_MSG_REQ_SET_MACADDR,
 	PIPELINE_ROUTING_MSG_REQS
 };
 
@@ -291,6 +292,20 @@  struct pipeline_routing_arp_delete_default_msg_rsp {
 	int status;
 };
 
+/*
+ * MSG SET MACADDR
+ */
+struct pipeline_routing_set_macaddr_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_routing_msg_req_type subtype;
+
+	uint64_t macaddr[PIPELINE_MAX_PORT_OUT];
+};
+
+struct pipeline_routing_set_macaddr_msg_rsp {
+	int status;
+};
+
 extern struct pipeline_be_ops pipeline_routing_be_ops;
 
 #endif