[PATCH] vlan: support ingress/egress priority map flushing
When sending packets via a vlan device we can manipulate the priority bits in the vlan header (PCP) via a mapping based on tc class value. Similarly, when packets are received via a vlan device, the PCP value can be mapped onto a tc class value, which is available for iptables rules and tc queueing disciplines. One can use the vconfig utility to set both ingress and egress mapping entries (set_ingress_map/set_egress_map) or any other application to call the vlan ioctl handler. The resulting map can be printed via /proc/net/vlan/ , i.e. : # cat /proc/net/vlan/vlan11 vlan11 VID: 11 REORDER_HDR: 1 dev->priv_flags: 1 total frames received 52331849 total bytes received 17451834908 Broadcast/Multicast Rcvd 1525155 total frames transmitted 98569270 total bytes transmitted 144870211289 Device: eth_test INGRESS priority mappings: 0:0 1:1 2:2 3:3 4:0 5:0 6:0 7:0 EGRESS priority mappings: 0:7 The current API offers only GET and SET operations, and when actually using this functionality a flush is missing to reset all entries. This patch adds a FLUSH operation for both ingress and egress map which can then be used by vconfig or other applications. Signed-off-by: Thierry Du Tre --- include/uapi/linux/if_vlan.h | 2 ++ net/8021q/vlan.c | 16 net/8021q/vlan.h | 2 ++ net/8021q/vlan_dev.c | 23 +++ 4 files changed, 43 insertions(+) diff --git a/include/uapi/linux/if_vlan.h b/include/uapi/linux/if_vlan.h index 7e5e6b3..6bdff52 100644 --- a/include/uapi/linux/if_vlan.h +++ b/include/uapi/linux/if_vlan.h @@ -20,6 +20,8 @@ enum vlan_ioctl_cmds { ADD_VLAN_CMD, DEL_VLAN_CMD, + FLUSH_VLAN_INGRESS_PRIORITY_CMD, + FLUSH_VLAN_EGRESS_PRIORITY_CMD, SET_VLAN_INGRESS_PRIORITY_CMD, SET_VLAN_EGRESS_PRIORITY_CMD, GET_VLAN_INGRESS_PRIORITY_CMD, diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 467069b..8988419 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -539,6 +539,22 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg) } switch (args.cmd) { + case FLUSH_VLAN_INGRESS_PRIORITY_CMD: + err = -EPERM; + if (!capable(CAP_NET_ADMIN)) + break; + vlan_dev_flush_ingress_priority(dev); + err = 0; + break; + + case FLUSH_VLAN_EGRESS_PRIORITY_CMD: + err = -EPERM; + if (!capable(CAP_NET_ADMIN)) + break; + vlan_dev_flush_egress_priority(dev); + err = 0; + break; + case SET_VLAN_INGRESS_PRIORITY_CMD: err = -EPERM; if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index df8bd65..d8d90ca 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -97,6 +97,8 @@ static inline struct net_device *vlan_find_dev(struct net_device *real_dev, (i) % VLAN_N_VID))) /* found in vlan_dev.c */ +void vlan_dev_flush_ingress_priority(const struct net_device *dev); +void vlan_dev_flush_egress_priority(const struct net_device *dev); void vlan_dev_set_ingress_priority(const struct net_device *dev, u32 skb_prio, u16 vlan_prio); int vlan_dev_set_egress_priority(const struct net_device *dev, diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index e97ab82..8fd91c3 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -159,6 +159,29 @@ static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) return 0; } +void vlan_dev_flush_ingress_priority(const struct net_device *dev) +{ + struct vlan_dev_priv *vlan = vlan_dev_priv(dev); + + memset(vlan->ingress_priority_map, 0, sizeof(vlan->ingress_priority_map)); + vlan->nr_ingress_mappings = 0; +} + +void vlan_dev_flush_egress_priority(const struct net_device *dev) +{ + struct vlan_dev_priv *vlan = vlan_dev_priv(dev); + struct vlan_priority_tci_mapping *mp; + int i; + + for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) { + while ((mp = vlan->egress_priority_map[i]) != NULL) { + vlan->egress_priority_map[i] = mp->next; + kfree(mp); + } + } + vlan->nr_egress_mappings = 0; +} + void vlan_dev_set_ingress_priority(const struct net_device *dev, u32 skb_prio, u16 vlan_prio) { -- 2.7.4
[PATCH v2] VLAN, support ingress/egress priority map flushing
When sending packets via a vlan device we can manipulate the priority bits in the vlan header (PCP) via a mapping based on tc class value. Similarly, when packets are received via a vlan device, the PCP value can be mapped onto a tc class value, which is available for iptables rules and tc queueing disciplines. One can use the vconfig utility to set both ingress and egress mapping entries (set_ingress_map/set_egress_map) or any other application to call the vlan ioctl handler. The resulting map can be printed via /proc/net/vlan/ , i.e. : # cat /proc/net/vlan/vlan11 vlan11 VID: 11 REORDER_HDR: 1 dev->priv_flags: 1 total frames received 52331849 total bytes received 17451834908 Broadcast/Multicast Rcvd 1525155 total frames transmitted 98569270 total bytes transmitted 144870211289 Device: eth_test INGRESS priority mappings: 0:0 1:1 2:2 3:3 4:0 5:0 6:0 7:0 EGRESS priority mappings: 0:7 The current API offers only GET and SET operations, and when actually using this functionality a flush is missing to reset all entries. This patch adds a FLUSH operation for both ingress and egress map which can then be used by vconfig or other applications. Signed-off-by: Thierry Du Tre --- Changes in v2: - Move new vlan cmd values to end of enum list. include/uapi/linux/if_vlan.h | 4 +++- net/8021q/vlan.c | 16 net/8021q/vlan.h | 2 ++ net/8021q/vlan_dev.c | 23 +++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/if_vlan.h b/include/uapi/linux/if_vlan.h index 7e5e6b3..8daea77 100644 --- a/include/uapi/linux/if_vlan.h +++ b/include/uapi/linux/if_vlan.h @@ -27,7 +27,9 @@ enum vlan_ioctl_cmds { SET_VLAN_NAME_TYPE_CMD, SET_VLAN_FLAG_CMD, GET_VLAN_REALDEV_NAME_CMD, /* If this works, you know it's a VLAN device, btw */ - GET_VLAN_VID_CMD /* Get the VID of this VLAN (specified by name) */ + GET_VLAN_VID_CMD, /* Get the VID of this VLAN (specified by name) */ + FLUSH_VLAN_INGRESS_PRIORITY_CMD, + FLUSH_VLAN_EGRESS_PRIORITY_CMD }; enum vlan_flags { diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 467069b..8988419 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -539,6 +539,22 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg) } switch (args.cmd) { + case FLUSH_VLAN_INGRESS_PRIORITY_CMD: + err = -EPERM; + if (!capable(CAP_NET_ADMIN)) + break; + vlan_dev_flush_ingress_priority(dev); + err = 0; + break; + + case FLUSH_VLAN_EGRESS_PRIORITY_CMD: + err = -EPERM; + if (!capable(CAP_NET_ADMIN)) + break; + vlan_dev_flush_egress_priority(dev); + err = 0; + break; + case SET_VLAN_INGRESS_PRIORITY_CMD: err = -EPERM; if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index df8bd65..d8d90ca 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -97,6 +97,8 @@ static inline struct net_device *vlan_find_dev(struct net_device *real_dev, (i) % VLAN_N_VID))) /* found in vlan_dev.c */ +void vlan_dev_flush_ingress_priority(const struct net_device *dev); +void vlan_dev_flush_egress_priority(const struct net_device *dev); void vlan_dev_set_ingress_priority(const struct net_device *dev, u32 skb_prio, u16 vlan_prio); int vlan_dev_set_egress_priority(const struct net_device *dev, diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index e97ab82..8fd91c3 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -159,6 +159,29 @@ static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) return 0; } +void vlan_dev_flush_ingress_priority(const struct net_device *dev) +{ + struct vlan_dev_priv *vlan = vlan_dev_priv(dev); + + memset(vlan->ingress_priority_map, 0, sizeof(vlan->ingress_priority_map)); + vlan->nr_ingress_mappings = 0; +} + +void vlan_dev_flush_egress_priority(const struct net_device *dev) +{ + struct vlan_dev_priv *vlan = vlan_dev_priv(dev); + struct vlan_priority_tci_mapping *mp; + int i; + + for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) { + while ((mp = vlan->egress_priority_map[i]) != NULL) { + vlan->egress_priority_map[i] = mp->next; + kfree(mp); + } + } + vlan->nr_egress_mappings = 0; +} + void vlan_dev_set_ingress_priority(const struct net_device *dev, u32 skb_prio, u16 vlan_prio) { -- 2.7.4
Re: [PATCH v2] VLAN, support ingress/egress priority map flushing
On 13-03-17 16:28, Eric Dumazet wrote: On Mon, 2017-03-13 at 15:36 +0100, Thierry Du Tre wrote: +void vlan_dev_flush_egress_priority(const struct net_device *dev) +{ + struct vlan_dev_priv *vlan = vlan_dev_priv(dev); + struct vlan_priority_tci_mapping *mp; + int i; + + for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) { + while ((mp = vlan->egress_priority_map[i]) != NULL) { + vlan->egress_priority_map[i] = mp->next; + kfree(mp); + } + } + vlan->nr_egress_mappings = 0; +} Are you doing this on a live device ? Looks you'll need proper RCU support then. Otherwise, crashes will happen, say in egress_priority_map() smp_rmb() wont be enough if items can now be destroyed. Yes, good point about the smp concurrency. I wrongly assumed there was already some locking mechanism in place to protect these structures. Let me take a look at this and I'll come back with a new proposal. -- Thierry