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