xref: /openbmc/linux/net/mpls/internal.h (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
20189197fSEric W. Biederman #ifndef MPLS_INTERNAL_H
30189197fSEric W. Biederman #define MPLS_INTERNAL_H
49095e10eSJiri Benc #include <net/mpls.h>
50189197fSEric W. Biederman 
61511009cSDavid Ahern /* put a reasonable limit on the number of labels
71511009cSDavid Ahern  * we will accept from userspace
81511009cSDavid Ahern  */
91511009cSDavid Ahern #define MAX_NEW_LABELS 30
101511009cSDavid Ahern 
110189197fSEric W. Biederman struct mpls_entry_decoded {
120189197fSEric W. Biederman 	u32 label;
130189197fSEric W. Biederman 	u8 ttl;
140189197fSEric W. Biederman 	u8 tc;
150189197fSEric W. Biederman 	u8 bos;
160189197fSEric W. Biederman };
170189197fSEric W. Biederman 
1827d69105SRobert Shearman struct mpls_pcpu_stats {
1927d69105SRobert Shearman 	struct mpls_link_stats	stats;
2027d69105SRobert Shearman 	struct u64_stats_sync	syncp;
2127d69105SRobert Shearman };
2227d69105SRobert Shearman 
2303c57747SRobert Shearman struct mpls_dev {
2437bde799SRobert Shearman 	int				input_enabled;
2524045a03SDavid Ahern 	struct net_device		*dev;
2627d69105SRobert Shearman 	struct mpls_pcpu_stats __percpu	*stats;
2727d69105SRobert Shearman 
2837bde799SRobert Shearman 	struct ctl_table_header		*sysctl;
2925cc8f07SRobert Shearman 	struct rcu_head			rcu;
3003c57747SRobert Shearman };
3103c57747SRobert Shearman 
3227d69105SRobert Shearman #if BITS_PER_LONG == 32
3327d69105SRobert Shearman 
3427d69105SRobert Shearman #define MPLS_INC_STATS_LEN(mdev, len, pkts_field, bytes_field)		\
3527d69105SRobert Shearman 	do {								\
3627d69105SRobert Shearman 		__typeof__(*(mdev)->stats) *ptr =			\
3727d69105SRobert Shearman 			raw_cpu_ptr((mdev)->stats);			\
3827d69105SRobert Shearman 		local_bh_disable();					\
3927d69105SRobert Shearman 		u64_stats_update_begin(&ptr->syncp);			\
4027d69105SRobert Shearman 		ptr->stats.pkts_field++;				\
4127d69105SRobert Shearman 		ptr->stats.bytes_field += (len);			\
4227d69105SRobert Shearman 		u64_stats_update_end(&ptr->syncp);			\
4327d69105SRobert Shearman 		local_bh_enable();					\
4427d69105SRobert Shearman 	} while (0)
4527d69105SRobert Shearman 
4627d69105SRobert Shearman #define MPLS_INC_STATS(mdev, field)					\
4727d69105SRobert Shearman 	do {								\
4827d69105SRobert Shearman 		__typeof__(*(mdev)->stats) *ptr =			\
4927d69105SRobert Shearman 			raw_cpu_ptr((mdev)->stats);			\
5027d69105SRobert Shearman 		local_bh_disable();					\
5127d69105SRobert Shearman 		u64_stats_update_begin(&ptr->syncp);			\
5227d69105SRobert Shearman 		ptr->stats.field++;					\
5327d69105SRobert Shearman 		u64_stats_update_end(&ptr->syncp);			\
5427d69105SRobert Shearman 		local_bh_enable();					\
5527d69105SRobert Shearman 	} while (0)
5627d69105SRobert Shearman 
5727d69105SRobert Shearman #else
5827d69105SRobert Shearman 
5927d69105SRobert Shearman #define MPLS_INC_STATS_LEN(mdev, len, pkts_field, bytes_field)		\
6027d69105SRobert Shearman 	do {								\
6127d69105SRobert Shearman 		this_cpu_inc((mdev)->stats->stats.pkts_field);		\
6227d69105SRobert Shearman 		this_cpu_add((mdev)->stats->stats.bytes_field, (len));	\
6327d69105SRobert Shearman 	} while (0)
6427d69105SRobert Shearman 
6527d69105SRobert Shearman #define MPLS_INC_STATS(mdev, field)			\
6627d69105SRobert Shearman 	this_cpu_inc((mdev)->stats->stats.field)
6727d69105SRobert Shearman 
6827d69105SRobert Shearman #endif
6927d69105SRobert Shearman 
700189197fSEric W. Biederman struct sk_buff;
710189197fSEric W. Biederman 
72f8efb73cSRoopa Prabhu #define LABEL_NOT_SPECIFIED (1 << 20)
73f8efb73cSRoopa Prabhu 
74f8efb73cSRoopa Prabhu /* This maximum ha length copied from the definition of struct neighbour */
75cf4b24f0SRobert Shearman #define VIA_ALEN_ALIGN sizeof(unsigned long)
76cf4b24f0SRobert Shearman #define MAX_VIA_ALEN (ALIGN(MAX_ADDR_LEN, VIA_ALEN_ALIGN))
77f8efb73cSRoopa Prabhu 
78f8efb73cSRoopa Prabhu enum mpls_payload_type {
79f8efb73cSRoopa Prabhu 	MPT_UNSPEC, /* IPv4 or IPv6 */
80f8efb73cSRoopa Prabhu 	MPT_IPV4 = 4,
81f8efb73cSRoopa Prabhu 	MPT_IPV6 = 6,
82f8efb73cSRoopa Prabhu 
83f8efb73cSRoopa Prabhu 	/* Other types not implemented:
84f8efb73cSRoopa Prabhu 	 *  - Pseudo-wire with or without control word (RFC4385)
85f8efb73cSRoopa Prabhu 	 *  - GAL (RFC5586)
86f8efb73cSRoopa Prabhu 	 */
87f8efb73cSRoopa Prabhu };
88f8efb73cSRoopa Prabhu 
89f8efb73cSRoopa Prabhu struct mpls_nh { /* next hop label forwarding entry */
9018916818SBenjamin Poirier 	struct net_device	*nh_dev;
9139eb8cd1SDavid Ahern 
9239eb8cd1SDavid Ahern 	/* nh_flags is accessed under RCU in the packet path; it is
9339eb8cd1SDavid Ahern 	 * modified handling netdev events with rtnl lock held
9439eb8cd1SDavid Ahern 	 */
95c89359a4SRoopa Prabhu 	unsigned int		nh_flags;
96f8efb73cSRoopa Prabhu 	u8			nh_labels;
97f8efb73cSRoopa Prabhu 	u8			nh_via_alen;
98f8efb73cSRoopa Prabhu 	u8			nh_via_table;
9959b20966SDavid Ahern 	u8			nh_reserved1;
10059b20966SDavid Ahern 
101680a9316SGustavo A. R. Silva 	u32			nh_label[];
102f8efb73cSRoopa Prabhu };
103f8efb73cSRoopa Prabhu 
10459b20966SDavid Ahern /* offset of via from beginning of mpls_nh */
10559b20966SDavid Ahern #define MPLS_NH_VIA_OFF(num_labels) \
10659b20966SDavid Ahern 		ALIGN(sizeof(struct mpls_nh) + (num_labels) * sizeof(u32), \
10759b20966SDavid Ahern 		      VIA_ALEN_ALIGN)
10859b20966SDavid Ahern 
10959b20966SDavid Ahern /* all nexthops within a route have the same size based on the
11059b20966SDavid Ahern  * max number of labels and max via length across all nexthops
11159b20966SDavid Ahern  */
11259b20966SDavid Ahern #define MPLS_NH_SIZE(num_labels, max_via_alen)		\
11359b20966SDavid Ahern 		(MPLS_NH_VIA_OFF((num_labels)) +	\
11459b20966SDavid Ahern 		ALIGN((max_via_alen), VIA_ALEN_ALIGN))
11559b20966SDavid Ahern 
1165b441ac8SRobert Shearman enum mpls_ttl_propagation {
1175b441ac8SRobert Shearman 	MPLS_TTL_PROP_DEFAULT,
1185b441ac8SRobert Shearman 	MPLS_TTL_PROP_ENABLED,
1195b441ac8SRobert Shearman 	MPLS_TTL_PROP_DISABLED,
1205b441ac8SRobert Shearman };
1215b441ac8SRobert Shearman 
122cf4b24f0SRobert Shearman /* The route, nexthops and vias are stored together in the same memory
123cf4b24f0SRobert Shearman  * block:
124cf4b24f0SRobert Shearman  *
125cf4b24f0SRobert Shearman  * +----------------------+
126cf4b24f0SRobert Shearman  * | mpls_route           |
127cf4b24f0SRobert Shearman  * +----------------------+
128cf4b24f0SRobert Shearman  * | mpls_nh 0            |
129cf4b24f0SRobert Shearman  * +----------------------+
13059b20966SDavid Ahern  * | alignment padding    |   4 bytes for odd number of labels
131cf4b24f0SRobert Shearman  * +----------------------+
132cf4b24f0SRobert Shearman  * | via[rt_max_alen] 0   |
133cf4b24f0SRobert Shearman  * +----------------------+
13459b20966SDavid Ahern  * | alignment padding    |   via's aligned on sizeof(unsigned long)
13559b20966SDavid Ahern  * +----------------------+
136cf4b24f0SRobert Shearman  * | ...                  |
137cf4b24f0SRobert Shearman  * +----------------------+
13859b20966SDavid Ahern  * | mpls_nh n-1          |
13959b20966SDavid Ahern  * +----------------------+
140cf4b24f0SRobert Shearman  * | via[rt_max_alen] n-1 |
141cf4b24f0SRobert Shearman  * +----------------------+
142cf4b24f0SRobert Shearman  */
143f8efb73cSRoopa Prabhu struct mpls_route { /* next hop label forwarding entry */
144f8efb73cSRoopa Prabhu 	struct rcu_head		rt_rcu;
145f8efb73cSRoopa Prabhu 	u8			rt_protocol;
146f8efb73cSRoopa Prabhu 	u8			rt_payload_type;
147cf4b24f0SRobert Shearman 	u8			rt_max_alen;
1485b441ac8SRobert Shearman 	u8			rt_ttl_propagate;
14977ef013aSDavid Ahern 	u8			rt_nhn;
15039eb8cd1SDavid Ahern 	/* rt_nhn_alive is accessed under RCU in the packet path; it
15139eb8cd1SDavid Ahern 	 * is modified handling netdev events with rtnl lock held
15239eb8cd1SDavid Ahern 	 */
15377ef013aSDavid Ahern 	u8			rt_nhn_alive;
15459b20966SDavid Ahern 	u8			rt_nh_size;
15559b20966SDavid Ahern 	u8			rt_via_offset;
15659b20966SDavid Ahern 	u8			rt_reserved1;
157680a9316SGustavo A. R. Silva 	struct mpls_nh		rt_nh[];
158f8efb73cSRoopa Prabhu };
159f8efb73cSRoopa Prabhu 
160f8efb73cSRoopa Prabhu #define for_nexthops(rt) {						\
161*f05b0b97SBenjamin Poirier 	int nhsel; const struct mpls_nh *nh;				\
16269d9c0d0SBenjamin Poirier 	for (nhsel = 0, nh = (rt)->rt_nh;				\
163f8efb73cSRoopa Prabhu 	     nhsel < (rt)->rt_nhn;					\
16469d9c0d0SBenjamin Poirier 	     nh = (void *)nh + (rt)->rt_nh_size, nhsel++)
165f8efb73cSRoopa Prabhu 
166f8efb73cSRoopa Prabhu #define change_nexthops(rt) {						\
16769d9c0d0SBenjamin Poirier 	int nhsel; struct mpls_nh *nh;					\
16869d9c0d0SBenjamin Poirier 	for (nhsel = 0, nh = (rt)->rt_nh;				\
169f8efb73cSRoopa Prabhu 	     nhsel < (rt)->rt_nhn;					\
17069d9c0d0SBenjamin Poirier 	     nh = (void *)nh + (rt)->rt_nh_size, nhsel++)
171f8efb73cSRoopa Prabhu 
172f8efb73cSRoopa Prabhu #define endfor_nexthops(rt) }
173f8efb73cSRoopa Prabhu 
mpls_entry_decode(struct mpls_shim_hdr * hdr)1740189197fSEric W. Biederman static inline struct mpls_entry_decoded mpls_entry_decode(struct mpls_shim_hdr *hdr)
1750189197fSEric W. Biederman {
1760189197fSEric W. Biederman 	struct mpls_entry_decoded result;
1770189197fSEric W. Biederman 	unsigned entry = be32_to_cpu(hdr->label_stack_entry);
1780189197fSEric W. Biederman 
1790189197fSEric W. Biederman 	result.label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT;
1800189197fSEric W. Biederman 	result.ttl = (entry & MPLS_LS_TTL_MASK) >> MPLS_LS_TTL_SHIFT;
1810189197fSEric W. Biederman 	result.tc =  (entry & MPLS_LS_TC_MASK) >> MPLS_LS_TC_SHIFT;
1820189197fSEric W. Biederman 	result.bos = (entry & MPLS_LS_S_MASK) >> MPLS_LS_S_SHIFT;
1830189197fSEric W. Biederman 
1840189197fSEric W. Biederman 	return result;
1850189197fSEric W. Biederman }
1860189197fSEric W. Biederman 
mpls_dev_get(const struct net_device * dev)18727d69105SRobert Shearman static inline struct mpls_dev *mpls_dev_get(const struct net_device *dev)
18827d69105SRobert Shearman {
18927d69105SRobert Shearman 	return rcu_dereference_rtnl(dev->mpls_ptr);
19027d69105SRobert Shearman }
19127d69105SRobert Shearman 
192face0188SRoopa Prabhu int nla_put_labels(struct sk_buff *skb, int attrtype,  u8 labels,
193face0188SRoopa Prabhu 		   const u32 label[]);
194a4ac8c98SDavid Ahern int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels,
195a1f10abeSDavid Ahern 		   u32 label[], struct netlink_ext_ack *extack);
196face0188SRoopa Prabhu bool mpls_output_possible(const struct net_device *dev);
197face0188SRoopa Prabhu unsigned int mpls_dev_mtu(const struct net_device *dev);
198face0188SRoopa Prabhu bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu);
19927d69105SRobert Shearman void mpls_stats_inc_outucastpkts(struct net_device *dev,
20027d69105SRobert Shearman 				 const struct sk_buff *skb);
201966bae33SEric W. Biederman 
2020189197fSEric W. Biederman #endif /* MPLS_INTERNAL_H */
203